/* Gardens Studio — the scroll.
   A single, natively-scrolling page. It opens on the living flower title held at
   the centre of the first viewport; scroll a little and the wind carries the
   title off to the right, revealing the studio's long editorial document, which
   you keep scrolling straight into as one continuous page. Scroll back to the
   top and the title re-plants and blooms again. Same warm paper ground, same
   Fraunces + Space Mono voice as the rest of the site — a new scroll model. */

/* Photos travel in from off-screen (mobile entrances) — clip horizontal
   overflow at the root so they never create sideways page scroll.
   overflow-x: clip (not hidden) on purpose: clip does NOT create a scroll
   container, so position: sticky (left columns, cyc stage) keeps working. */
html, body { overflow-x: clip; }

/* WHITE GROUND VARIANT — the page is the same white the Blender render sits on
   (#ffffff), so the warm-tan neutral ramp is re-cut as clean greys. Each grey
   was chosen to hold the SAME contrast ratio against the new ground that its
   tan held against #f1ebe0, so the hierarchy of the document is unchanged and
   only the temperature moves; --muted is the one exception (see below). The
   poppy accent is untouched — it is the only colour on the page that is not
   the flowers. */
:root {
  /* ANIMAL CROSSING GROUND — the island's sunny grass, lightened to page
     weight. The neutral ramp is re-cut green-biased to sit on it. */
  --paper:   #dcedb2;      /* light AC grass */
  --paper-2: #cfe2a2;
  --ink:     #202614;      /* deep leaf-green ink */
  --muted:   #5c6a42;      /* 4.6:1 on the grass ground */
  --faint:   #94a374;
  --hair:    #c2d494;
  --hair-2:  #cfe0a4;
  --poppy:   #cf4325;      /* unchanged — the audited accent */

  --serif: "Fraunces", Georgia, "Times New Roman", serif;
  --mono:  "Space Mono", ui-monospace, Menlo, monospace;
  --gutter: clamp(18px, 4vw, 52px);
  --ease:  cubic-bezier(.22, .61, .36, 1);
  --stick: clamp(172px, 22vh, 216px);      /* sticky-left offset — clears the STICKY header band */
  /* SPACING SCALE (2026-09-14) — every vertical gap between text blocks and
     photos derives from these three, so the page has one rhythm:
       --gap-head     heading -> its body (copy, list, grid, form)
       --gap-photo    text <-> photo, photo <-> photo
       --gap-section  between sections / before a new heading            */
  --gap-head:    clamp(18px, 2.2vw, 30px);
  --gap-photo:   clamp(56px, 6vw, 100px);
  --gap-section: clamp(64px, 11vh, 132px);
  /* MENU ACCENT (settled 2026-09-14: soft sage, chosen over five greens and
     the original poppy): the header menu's hover / active colour — the inset
     top bar and the light wash behind the cell. */
  --accent:      #7d9a72;
  --accent-wash: color-mix(in srgb, var(--accent) 9%, transparent);
}

* { box-sizing: border-box; }
html { scroll-behavior: auto; }            /* JS drives smooth scrolls itself */
html, body {
  margin: 0; padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--mono);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
body { min-height: 100vh; }                /* THIS version scrolls the document natively */
a { color: inherit; }
::selection { background: var(--poppy); color: #fff; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0; clip: rect(0 0 0 0); overflow: hidden;
}
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 90;
  background: var(--ink); color: var(--paper); padding: 10px 16px;
  font: 400 12px/1 var(--mono);
}
.skip:focus { left: 12px; top: 12px; }

/* ================================================================== */
/* THE HEADER BAND — static, at the very top of the studio document.    */
/* It is NOT a fixed overlay: it scrolls away with the page. Three       */
/* 1px-ink boxes in a row — wordmark / contact / numbered nav grid —     */
/* with adjacent borders collapsed into single hairlines. Faded in       */
/* FIRST on reveal (the body follows a beat later); nothing overlays the  */
/* content, so section sticky-tops are the only clearance that matters.   */
/* ================================================================== */
/* The header FOLLOWS the scroll: a sticky paper band pinned to the top of the
   viewport; the studio document slides beneath it. */
.info-header {
  position: sticky; top: 0; z-index: 25;
  background: var(--paper);
  display: flex; align-items: stretch;
  padding: clamp(14px, 2.5vh, 26px) clamp(18px, 5vw, 84px) clamp(12px, 2vh, 18px);
  opacity: 0; pointer-events: none;
  transition: opacity .45s var(--ease);
}
body.revealed .info-header { opacity: 1; pointer-events: auto; }

.hbox {
  display: flex; border: 1px solid var(--ink);
  min-height: clamp(96px, 12vh, 122px);
}
.hbox + .hbox { margin-left: -1px; }         /* collapse adjacent borders to one line */

/* 1 — Wordmark box: "Gardens Studio", centred; the whole word carries you home. */
.hbox-mark { flex: 1 1 0; align-items: center; justify-content: center; gap: 14px; }
.hmark-word {
  font-family: var(--serif); font-weight: 400; font-size: clamp(16px, 1.7vw, 23px);
  letter-spacing: 0.005em; color: var(--ink); text-decoration: none;
  transition: color .3s var(--ease);
}
.hmark-word:hover, .hmark-word:focus-visible { color: var(--poppy); outline: none; }
.hmenu { display: none; }                    /* mobile-only Menu toggle */

/* 2 — Contact box: three label→value rows (Space Mono small caps). */
.hbox-contact { flex: 1.5 1 0; flex-direction: column; justify-content: center; min-width: 0; }
.hrow {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: clamp(6px, 1vh, 10px) clamp(14px, 1.6vw, 22px);
}
.hrow + .hrow { border-top: 1px solid var(--hair); }
.hlabel {
  flex: 0 0 auto; font: 400 9.5px/1.4 var(--mono); letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--muted);
}
.hval {
  font: 400 10.5px/1.45 var(--mono); letter-spacing: 0.01em; color: var(--ink);
  text-align: right; text-decoration: none; min-width: 0;
}
a.hval { border-bottom: 1px solid transparent; padding-bottom: 1px;
  transition: color .25s var(--ease), border-color .25s var(--ease); }
a.hval:hover, a.hval:focus-visible { color: var(--poppy); border-bottom-color: var(--poppy); outline: none; }

/* 3 — Nav grid box (~half the width): The Space spans the top row, the other
   three sections share the row below, with 1px internal dividers. Active cell
   wears a poppy top border + ink text. */
.hbox-nav {
  flex: 2.5 1 0; display: grid; grid-template-columns: 1fr 1fr 1fr; grid-auto-rows: 1fr;
}
.hnav-cell {
  display: flex; align-items: center; gap: 10px;
  padding: 7px clamp(12px, 1.5vw, 22px); text-decoration: none;
  font: 400 10.5px/1.2 var(--mono); letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted); position: relative;
  transition: color .2s var(--ease), background .2s var(--ease), box-shadow .2s var(--ease);
}
.hnav-cell .n { font-size: 9.5px; letter-spacing: 0.04em; color: var(--faint);
  transition: color .2s var(--ease); }
.hnav-full { grid-column: 1 / -1; }
.hnav-cell:not(.hnav-full) { border-top: 1px solid var(--hair); }         /* rule under 01, and between rows */
.hnav-cell:nth-child(3), .hnav-cell:nth-child(4) { border-left: 1px solid var(--hair); }  /* column dividers */
.hnav-cell:hover, .hnav-cell:focus-visible {
  color: var(--ink); background: var(--accent-wash);
  box-shadow: inset 0 3px 0 var(--accent); outline: none;
}
.hnav-cell:hover .n, .hnav-cell:focus-visible .n { color: var(--poppy); }
.hnav-cell.active { color: var(--ink); box-shadow: inset 0 3px 0 var(--accent); }
.hnav-cell.active .n { color: var(--accent); }

/* ------------------------------------------------------------------ */
/* The living flower title — fixed & centred over the hero              */
/* ------------------------------------------------------------------ */
.title-wrap {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  z-index: 30; pointer-events: none;
  transition: opacity .45s var(--ease);
}
/* After the blow-away (or the reduced-motion fade) the title is put away; kept
   in layout (not display:none) so the WebGL canvas keeps a valid size. */
.title-wrap.gone   { opacity: 0; visibility: hidden; pointer-events: none; }
.title-wrap.fading { opacity: 0; }              /* reduced-motion quick fade-out */

#banner {
  position: relative;
  /* The height budget caps the WIDTH (not the height): with aspect-ratio in
     force the banner keeps its designed 1.22 frame at any window size. A
     bare max-height used to flatten the box on large/short windows while
     the camera kept framing a fixed world WIDTH — slicing the top and
     bottom flower rows off. max-height stays only as belt-and-braces. */
  width: min(1150px, 88vw, calc(82vh * 1.22)); aspect-ratio: 1.22 / 1; max-height: 82vh;
  pointer-events: auto; cursor: crosshair;
  filter: drop-shadow(0 10px 24px rgba(58, 57, 54, 0.12));   /* neutral grey; fitted with the blob opacity so the shadowed area matches the render's luminance curve */
}
#scene, #shadows { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }
#shadows {
  pointer-events: none;
  /* The shadow blobs are drawn on a canvas exactly the banner's size; a shadow
     that runs past the canvas edge hard-clips into a straight seam. Fade the
     canvas out over its last few px on ALL FOUR sides so they dissolve instead.
     The sides matter since the wide framing put the letters ~5% from the edge:
     the G's shadow (offset left by GRADE.shadow.dx) was cut into a vertical
     line. The two gradients are intersected, so a corner fades on both axes. */
  -webkit-mask-image:
    linear-gradient(to bottom, transparent 0, #000 34px, #000 calc(100% - 34px), transparent 100%),
    linear-gradient(to right,  transparent 0, #000 26px, #000 calc(100% - 26px), transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to bottom, transparent 0, #000 34px, #000 calc(100% - 34px), transparent 100%),
    linear-gradient(to right,  transparent 0, #000 26px, #000 calc(100% - 26px), transparent 100%);
  mask-composite: intersect;
}

/* During the blow-away the canvas expands to fill the whole window (the camera
   is reframed in JS so the title stays the exact same size/place), so the
   flowers can fly clear to the window's right edge instead of being clipped. */
.title-wrap.blowing { left: 0; top: 0; transform: none; width: 100vw; height: 100vh; }
.title-wrap.blowing #banner { width: 100%; height: 100%; aspect-ratio: auto; max-height: none; }

/* Scroll cue — a quiet nudge on the hero. It HOLDS through the whole scrub and
   the blow, then fades out once the flowers are away (enterDoc adds .gone). */
.scroll-cue {
  position: fixed; left: 50%; bottom: clamp(20px, 4vw, 34px);
  transform: translateX(-50%); z-index: 35;
  display: flex; align-items: center; gap: 10px;
  font: 400 10.5px/1 var(--mono); letter-spacing: 0.26em; text-transform: uppercase;
  color: var(--muted); pointer-events: none;
  transition: opacity .9s var(--ease);
}
.scroll-cue.gone { opacity: 0; }
.scroll-cue-key {
  display: inline-grid; place-items: center; width: 20px; height: 20px;
  border: 1px solid var(--faint); border-radius: 5px; font-size: 11px; letter-spacing: 0;
  animation: nudge 2.6s var(--ease) infinite;
}
@keyframes nudge { 0%,100%{transform:translateY(0)} 45%{transform:translateY(-4px)} 72%{transform:translateY(2px)} }

/* ------------------------------------------------------------------ */
/* The hero — a zero-height anchor; the held title is fixed & centred   */
/* over it, and the studio document sits at the very top of the page    */
/* (hidden) so it can fade in IN PLACE once the title blows away —       */
/* it never scrolls up from below the fold.                             */
/* ------------------------------------------------------------------ */
.hero {
  position: relative;
  min-height: 0;
  background: transparent;
}

/* The wind gust overlay — flowing streamlines drawn while the title blows off. */
.wind {
  position: fixed; inset: 0; z-index: 40; pointer-events: none;
  opacity: 0; transition: opacity .35s var(--ease);
}
.wind.on { opacity: 1; }
.wind-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }

/* ================================================================== */
/* THE STUDIO DOCUMENT — a satspace.ltd-style flowing scroll            */
/* ================================================================== */
/* The studio sits at the very top of the document, hidden under the flower
   title. When the title blows away it fades in RIGHT WHERE IT IS (opacity only —
   no transform). Reveal is STAGGERED: the header lights first, then the body a
   beat later (transition-delay applies to the fade-IN only, so a regrow fades
   both out together). Nothing slides up from the bottom. */
.info-doc { position: relative; background: var(--paper); }

.info-body {
  max-width: 1680px; margin: 0 auto;
  padding: clamp(46px, 8vh, 96px) clamp(18px, 5vw, 84px) clamp(80px, 12vh, 150px);
  opacity: 0; pointer-events: none;
  transition: opacity .6s var(--ease);
}
body.revealed .info-body { opacity: 1; pointer-events: auto; transition-delay: 0.4s; }
@media (prefers-reduced-motion: reduce) {
  .info-header { transition: opacity .25s linear; }
  .info-body { transition: opacity .25s linear; }
  body.revealed .info-body { transition-delay: 0.16s; }
}

/* ---- A section: a flex row of a sticky LEFT text column + a RIGHT column of
   full-size images that flow past the pinned text. The differential between the
   pinned left and the flowing right IS the staggered movement — pure sticky, no
   JS parallax. Section height comes from the right column's image stack. ---- */
.main {
  display: flex; align-items: stretch;              /* left stretches so its inner can pin */
  gap: clamp(30px, 5vw, 90px);
}
.main + .main { margin-top: var(--gap-section); }

.main-left { flex: 1 1 50%; min-width: 0; }
.main-left-inner { position: sticky; top: var(--stick); }

.sec-head { display: flex; align-items: baseline; gap: 16px; margin: 0 0 var(--gap-head); }
.sec-idx { flex: 0 0 auto; font: 400 11px/1 var(--mono); letter-spacing: 0.2em; color: var(--poppy); }
.sec-title {
  font-family: var(--serif); font-weight: 300;
  font-size: clamp(28px, 3.6vw, 46px); line-height: 1.04; letter-spacing: -0.02em;
  margin: 0; text-wrap: balance;
}
.sec-head-sub { margin-top: clamp(30px, 4vw, 54px); }

.sec-copy { max-width: 46ch; }
.sec-copy p { font: 400 15px/1.85 var(--mono); color: var(--ink); margin: 0 0 1.15em; }
.sec-copy p:last-child { margin-bottom: 0; }

/* RIGHT column — a plain flex column of FULL-SIZE, uncropped images at their
   natural aspect ratio. No object-fit, no fixed-height frames, no cross-fade. */
.main-right { flex: 1 1 50%; min-width: 0; display: flex; flex-direction: column; gap: var(--gap-photo); }
.main-right img {
  display: block; width: 100%; max-width: 100%; height: auto;
  background: var(--paper-2);
  box-shadow: 0 22px 50px -34px rgba(38, 37, 34, 0.44);
}

/* Floor plan rides the right column — drawn on paper, legend beneath. */
.main-right-plan { gap: clamp(16px, 2vw, 24px); }

.mob-photos { display: none; }

/* The merged left column pins as ONE satspace-style stack (Space copy,
   Amenities, floor plan) — everything compacted so the whole column fits a
   typical viewport and then simply holds still while the photos flow. */
.plan-block { margin-top: 0; max-width: 500px; }
.plan-block .floorplan { margin-bottom: 0; }
@media (min-width: 721px) {
  /* SATSPACE SIDE-TEXT MODEL (2026-09-14, desktop only — the phone layout is
     untouched). Transcribed from satspace.ltd's shipped Webflow CSS, all of
     it, not just the sticky rule:
       .sticky-container  { position: sticky; top: 200px }  — ONE block per
         section: heading + description + "FEATURES:" label + plain line
         list, pinned while the right-column images flow, DETACHING when the
         section ends (no card train, no hand-over).
       .heading           { margin-bottom: 68px }
       .studio-description{ margin-bottom: 43px; narrow column }
       .features          { small bold label; margin-bottom: 20px }
       features list      = plain lines: no bullets, no rules, no columns
       .image-container   { flex column; gap: 30px }
       sections           { display: flex; margin-top: 40px }
       equipment          = sticky heading on the left, lists on the right.
     The base `.main-left-inner { position: sticky; top: var(--stick) }` is
     the sticky-container; the old card-train overrides are gone. */
  /* MOTION ONLY (owner's brief, 2026-09-14): what is adopted from satspace
     is how the text chunks MOVE — each section's text pins as one block,
     the next section's block rises toward it (sections sit close, 40px, so
     they nearly meet), then the pinned block DETACHES as its section ends
     and the next one pins — plus their title -> body spacing. Layout,
     fonts, list styling and image spacing stay the site's own. */
  #info-space .lseg .lblock { position: static; }
  .main + .main { margin-top: 40px; }                 /* chunks come close before the hand-off */
  .sec-head { margin: 0 0 68px; }                     /* title -> body text */
  #info-space .sec-copy { max-width: 46ch; }
  #info-space .sec-copy p { line-height: 1.65; }
  /* The Amenities heading and list keep the site's OWN typography and list
     styling (the owner's rule: never change the font). Only satspace's
     block anatomy and spacing are adopted. */
  #info-amenities .sec-head-sub { margin: 0 0 var(--gap-head); }
  #info-amenities .sec-list {
    display: grid; grid-template-columns: 1fr 1fr;
    column-gap: clamp(18px, 2vw, 30px); max-width: 46ch;
  }
  #info-amenities .sec-list li { padding-top: 6px; padding-bottom: 6px; }
}

/* A quiet flag on content that is not final: placeholder copy / drawings. */
.ph-note {
  margin: 14px 0 0; font: 400 10px/1.6 var(--mono);
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--faint);
}
.plan-figure .ph-note { margin-top: 10px; }

/* ---- Mobile-only content blocks (see scroll.js mobileCycHero/mobilePiano).
   Hidden on desktop; the spacing rule keeps the section rhythm intact even
   though the (hidden) piano div sits between two .main sections. ---- */
.mobile-hero-cyc, .mobile-piano { display: none; }
.plan-figure { margin: 0; }
.plan-figure .floorplan { width: 100%; height: auto; max-width: 100%; margin: 0 0 clamp(16px, 2vw, 22px); }

/* Equipment — a two-column grid of category lists in the right column. */
.kit-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(24px, 3vw, 40px) clamp(26px, 3vw, 46px);
}

/* ---- Features — a clean mono list in the sticky left column ---- */
.sec-list { list-style: none; margin: clamp(4px, 1vw, 10px) 0 0; padding: 0; max-width: 46ch; }
.sec-list li {
  display: flex; align-items: baseline; gap: 14px;
  padding: 13px 2px; border-bottom: 1px solid var(--hair-2);
  font: 400 14px/1.55 var(--mono); color: var(--ink);
}
.sec-list li:first-child { border-top: 1px solid var(--hair-2); }
.sec-list li::before {
  content: ""; flex: 0 0 auto; width: 6px; height: 6px; margin-top: 6px;
  background: var(--poppy); border-radius: 50%;
}

/* ---- Equipment categories (right column, two-up grid) ---- */
.kit-cat h3 {
  margin: 0 0 14px; padding-bottom: 12px; border-bottom: 1px solid var(--ink);
  font: 700 11px/1 var(--mono); letter-spacing: 0.22em; text-transform: uppercase; color: var(--ink);
}
.kit-cat ul { list-style: none; margin: 0; padding: 0; }
.kit-cat li {
  padding: 9px 0; border-bottom: 1px solid var(--hair-2);
  font: 400 12.5px/1.5 var(--mono); color: var(--muted);
}
.kit-cat li:last-child { border-bottom: 0; }

/* Final desktop presentation; the mobile layout keeps its existing styling. */
@media (min-width: 721px) {
  body[data-desktop-wind="original"] #windLinePanel { display: none; }
  .sec-list li::before { content: none; }
  #info-features .sec-title, #info-equipment .sec-title,
  .sec-list li, .kit-cat h3, .kit-cat li { color: #000; }
}

/* ---- Floor plan drawing (shared by the right panel + the mobile inline) ---- */
.floorplan { display: block; width: 100%; height: auto; max-width: 100%; margin: 0 auto;
  color: var(--ink); }
.floorplan .fp-wall { stroke: currentColor; stroke-width: 2; fill: none; }
.floorplan .fp-open { stroke: var(--faint); stroke-width: 1.25; stroke-dasharray: 6 6; fill: none; }
.floorplan .fp-accent { stroke: var(--poppy); stroke-width: 2.4; fill: none; }
.floorplan .fp-win { stroke: currentColor; stroke-width: 1.25; fill: none; }
.floorplan .fp-dim { stroke: var(--muted); stroke-width: 1; fill: none; }
.floorplan .fp-tick { stroke: var(--muted); stroke-width: 1; }
.floorplan .fp-label { fill: var(--ink); font-family: var(--mono); font-size: 16px;
  font-weight: 400; letter-spacing: 0.14em; }
.floorplan .fp-sub { fill: var(--muted); font-family: var(--mono); font-size: 11px;
  font-weight: 400; letter-spacing: 0.1em; }
.floorplan .fp-meas { fill: var(--muted); font-family: var(--mono); font-size: 13px;
  font-weight: 400; letter-spacing: 0.08em; }
.fp-legend { display: flex; flex-wrap: wrap; gap: 12px 22px; margin: 0;
  font: 400 10.5px/1 var(--mono); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--muted); }
.fp-legend span { display: inline-flex; align-items: center; gap: 9px; }
.fp-legend .sw { width: 18px; height: 0; border-top-width: 2px; border-top-style: solid; }
.fp-legend .sw.ink { border-top-color: var(--ink); }
.fp-legend .sw.dash { border-top-style: dashed; border-top-color: var(--faint); }
.fp-legend .sw.pop { border-top-color: var(--poppy); }

/* ---- Contact — a full-width close below the sectioned area ---- */
.info-contact { margin-top: var(--gap-section); }

/* Write to the studio — the 05 section IS this form. High contrast, extremely
   legible: bold ink labels, full 1px-ink boxed fields on warm white (not faint
   underlines on paper), large input type, poppy focus. */
.contact-form-wrap { margin-top: clamp(28px, 4vw, 48px); max-width: 760px; }
.field { position: relative; margin-top: 28px; }
.field label { display: block; font: 700 12px/1 var(--mono); letter-spacing: 0.24em;
  text-transform: uppercase; color: var(--ink); margin-bottom: 10px; }
.field input, .field textarea {
  width: 100%; background: #ffffff;            /* the 1px ink box IS the field on a white ground */
  border: 1px solid var(--ink);
  color: var(--ink); font: 400 17px/1.5 var(--mono); padding: 15px 16px;
  border-radius: 0; transition: border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.field textarea { resize: vertical; min-height: 140px; }
.field input:focus, .field textarea:focus {
  outline: none; border-color: var(--poppy);
  box-shadow: inset 0 0 0 1px var(--poppy);
}
.field input::placeholder, .field textarea::placeholder { color: var(--muted); }
.send {
  margin-top: 34px; display: inline-flex; align-items: center; gap: 12px;
  background: var(--ink); color: #ffffff; border: 1px solid var(--ink);
  font: 700 13px/1 var(--mono); letter-spacing: 0.22em; text-transform: uppercase;
  padding: 18px 30px; cursor: pointer;
  transition: background .3s var(--ease), color .3s var(--ease);
}
.send:hover { background: var(--paper); color: var(--ink); }
.send .arr { transition: transform .3s var(--ease); }
.send:hover .arr { transform: translateX(4px); }
.done-note {
  margin: 34px 0 0; font-family: var(--serif); font-weight: 300;
  font-size: clamp(24px, 4vw, 40px); line-height: 1.06; letter-spacing: -0.015em;
}
.done-sub { font: 400 13px/1.7 var(--mono); color: var(--muted); margin: 16px 0 0; max-width: 52ch; }
.done-sub em { font-style: normal; color: var(--ink); }
.info-note { margin: clamp(32px, 5vw, 58px) 0 0; max-width: 60ch;
  font: 400 11.5px/1.7 var(--mono); color: var(--faint); }

/* A quiet close: a back-to-top affordance at the very foot of the document. */
.info-foot {
  margin-top: clamp(56px, 9vw, 104px); padding-top: clamp(26px, 4vw, 40px);
  border-top: 1px solid var(--hair-2);
  display: flex; align-items: baseline; justify-content: space-between; gap: 20px;
  flex-wrap: wrap;
}
.info-foot .foot-mark { font: 400 11px/1 var(--mono); letter-spacing: 0.3em;
  text-transform: uppercase; color: var(--muted); }
.to-top { font: 400 11px/1 var(--mono); letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink); text-decoration: none; display: inline-flex; align-items: center; gap: 10px;
  border-bottom: 1px solid var(--accent); padding-bottom: 4px; cursor: pointer; }
.to-top .arr { transition: transform .3s var(--ease); }
.to-top:hover .arr { transform: translateY(-4px); }

/* ---- Responsive ---- */
@media (max-width: 1040px) {
  .main { gap: clamp(24px, 4vw, 56px); }
  .kit-grid { gap: clamp(20px, 3vw, 30px) clamp(22px, 3vw, 34px); }
}
@media (max-width: 720px) {
  #banner { width: min(97vw, calc(74vh * 1.22)); max-height: 74vh; }  /* canonical WIDE: near edge-to-edge on phones (width also bows to the height budget — see the desktop rule) */

  /* Header collapses (satspace convention): the wordmark box goes full-width with
     a Menu toggle; the contact rows are hidden; the nav grid drops open below
     when Menu is tapped. */
  /* The phone header OVERLAYS the page instead of occupying flow space, so
     the cyc opener below can own the viewport from y=0. A translucent paper
     scrim + blur keeps the wordmark and Menu legible over the photograph. */
  .info-header {
    position: fixed; top: 0; left: 0; right: 0;
    flex-direction: column; padding: clamp(16px, 6vw, 26px) clamp(16px, 5vw, 26px) clamp(10px, 3vw, 16px);
    background: color-mix(in srgb, var(--paper) 74%, transparent);
    -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  }
  /* In the column header, size each box to its own content (the row-mode
     flex bases of 0 would otherwise collapse the box heights). */
  .hbox { min-height: 0; flex: 0 0 auto; }
  .hbox + .hbox { margin-left: 0; margin-top: -1px; }
  .hbox-mark { justify-content: space-between; padding: 15px clamp(14px, 4vw, 20px); }
  .hmark-word { font-size: clamp(16px, 5vw, 20px); }
  .hmenu {
    display: inline-flex; align-items: center; gap: 8px; background: none; border: 0;
    cursor: pointer; color: var(--ink); padding: 6px 2px;
    font: 400 11px/1 var(--mono); letter-spacing: 0.2em; text-transform: uppercase;
  }
  .hbox-contact { display: none; }
  .hbox-nav { display: none; }
  /* In the column header the nav box has no definite height, so the base
     grid-auto-rows:1fr would collapse — size rows to their content instead. */
  .info-header.nav-open .hbox-nav { display: grid; grid-auto-rows: auto; grid-template-columns: 1fr; }
  .hnav-cell { padding: 15px clamp(14px, 4vw, 20px); border-left: 0 !important; }

  /* Sections stack to one column: the left text, then its full-size images (still
     uncropped, natural aspect). No pinning — a simple stacked read. */
  .main { flex-direction: column; gap: clamp(20px, 6vw, 30px); }
  /* Phone spacing is deliberately NOT on the desktop token scale — the
     owner's normalization brief was desktop-only (2026-09-14); these are the
     phone's original values. */
  .info-contact { margin-top: clamp(72px, 11vh, 140px); }
  .main + .main { margin-top: clamp(48px, 13vw, 78px); }
  .main-left, .main-right { flex: 1 1 auto; width: 100%; }
  .main-left-inner { position: static; }
  .sec-copy, .sec-list { max-width: none; }
  .kit-grid { grid-template-columns: 1fr; }
  .plan-figure .floorplan { max-width: 560px; }

  /* The phone read opens on the cyc wall, bled to all four corners of the
     viewport: full width via the negative side pull out of .info-body's
     padding, full height via 100svh, covered (cropped) — never letterboxed. */
  /* The cyc opener (2026-09-11): a 2-viewport scroll RUNWAY holding a sticky
     full-viewport stage. The wall opens WHOLE — natural horizontal framing,
     letterboxed on the page ground — and scroll scales it up (wireCycHero)
     until the screen's edges reach the wall's edges, where the sticky runs
     out and the photo scrolls away at full bleed. */
  .mobile-hero-cyc {
    display: block; position: relative;
    width: 100vw; height: 145vh; height: 145dvh;  /* short runway: quick grow (2026-09-11) */
    /* Negative bottom margin (2026-09-11): "The Space" rises into the screen
       WHILE the zoom is still finishing, instead of waiting out the runway —
       the stopped image is a roughly square band mid-screen, so the heading
       climbs into the clear ground beneath it. 20dvh leaves the title sitting
       ~a photo-gap (≈50-65px) below the image at the stop, matching the
       site's photo/text rhythm (clamp(36px, 10vw, 56px)). */
    margin: calc(0px - clamp(46px, 8vh, 96px)) 0 calc(clamp(48px, 13vw, 78px) - 20dvh)
            calc(50% - 50vw);
  }
  .mobile-hero-cyc .cyc-stage {
    position: sticky; top: 0;
    width: 100%; height: 100vh; height: 100dvh;
    overflow: hidden;
    display: flex; align-items: center; justify-content: center;
  }
  .mobile-hero-cyc img {
    width: 100%; height: auto; display: block;
    will-change: transform;
  }
  /* On phones the desktop right-column stack hides entirely — the photos
     interleave the left column's text blocks instead (.mob-photos). */
  .sec-list li::before { content: none; }         /* no poppy dots on the phone list (2026-09-14) */
  /* One list convention on the phone (2026-09-14): the Equipment items take
     the Amenities items' size, colour, row height and hairlines — they were
     smaller, greyer and tighter. Category labels (h3) stay as they are. */
  .kit-cat li {
    padding: 10px 2px; font: 400 14px/1.55 var(--mono); color: var(--ink);   /* items within a group sit a little closer */
    border-bottom: 1px solid var(--hair-2);
  }
  .kit-cat li:last-child { border-bottom: 1px solid var(--hair-2); }
  /* Equipment rhythm on the phone (2026-09-14): a clearer break between one
     group and the next, and more air between the heading and the first group. */
  #info-equipment .kit-grid { gap: 44px; }
  #info-equipment .sec-head { margin-bottom: 34px; }
  #info-space .main-right, #info-amenities .main-right { display: none; }
  /* Amenities is its own section now (desktop motion); on the phone it must
     sit exactly where it did inside the old merged section — the photo
     cluster's bottom margin + the sub-heading's top margin, nothing more. */
  #info-amenities { margin-top: 0; }
  .mob-photos {
    display: flex; flex-direction: column; gap: clamp(24px, 7vw, 38px);
    margin: clamp(36px, 10vw, 56px) 0;
  }
  .mob-photos img { width: 100%; height: auto; display: block; }
  /* The piano sits immediately above the Equipment heading (its desktop
     home inside the kit column hides here so it never shows twice). */
  .equip-photo { display: none; }
  /* The piano photo FOLLOWS the Equipment list (2026-09-11, was above the
     heading) at the site's standard photo/text gap. */
  .mobile-piano { display: block; margin-top: clamp(36px, 10vw, 56px); }
  .mobile-piano img { width: 100%; height: auto; display: block; }

}

@media (prefers-reduced-motion: reduce) {
  .scroll-cue-key { animation: none; }
  .title-wrap { transition: opacity .2s linear; }
}

/* ------------------------------------------------------------------ */
/* GROUND THEMES — the picker swaps these token sets. Each ground has   */
/* its own neutral ramp (same contrast ratios against its own paper as  */
/* the shipped tan had against #f1ebe0), so the document reads the same  */
/* on all of them. The poppy accent and the flower colours never move.   */
/* ------------------------------------------------------------------ */
:root[data-ground="white"] {
  --paper:   #ffffff;  --paper-2: #e0e0e0;
  --ink:     #1d1d1d;  --muted:   #767676;  --faint: #a8a8a8;
  --hair:    #d2d2d2;  --hair-2:  #e1e1e1;
}
:root[data-ground="green"] {
  --paper:   #eaefe4;  --paper-2: #e0e2dc;
  --ink:     #1c1f1a;  --muted:   #6a6d65;  --faint: #a9afa3;
  --hair:    #d3d7cf;  --hair-2:  #e1e4dd;
}
.ground-dot-white { --swatch: #ffffff; }
.ground-dot-green { --swatch: #eaefe4; }


/* ------------------------------------------------------------------ */
/* GROUND THEMES — the picker swaps these token sets. Each ground has   */
/* its own neutral ramp (same contrast ratios against its own paper as  */
/* the shipped tan had against #f1ebe0), so the document reads the same  */
/* on all of them. The poppy accent and the flower colours never move.   */
/* ------------------------------------------------------------------ */
:root[data-ground="white"] {
  --paper:   #ffffff;  --paper-2: #e0e0e0;
  --ink:     #1d1d1d;  --muted:   #767676;  --faint: #a8a8a8;
  --hair:    #d2d2d2;  --hair-2:  #e1e1e1;
}
:root[data-ground="green"] {
  --paper:   #eaefe4;  --paper-2: #e0e2dc;
  --ink:     #1c1f1a;  --muted:   #6a6d65;  --faint: #a9afa3;
  --hair:    #d3d7cf;  --hair-2:  #e1e4dd;
}
:root[data-ground="sage"] {
  --paper:   #97a38a;  --paper-2: #8b9382;
  --ink:     #1a1d18;  --muted:   #343831;  --faint: #697062;
  --hair:    #889080;  --hair-2:  #92988a;
  --poppy:   #922f1a;
}
.ground-dot-white { --swatch: #ffffff; }
.ground-dot-green { --swatch: #eaefe4; }
.ground-dot-sage { --swatch: #97a38a; }


/* ------------------------------------------------------------------ */
/* GROUND THEMES — the picker swaps these token sets. Each ground has   */
/* its own neutral ramp (same contrast ratios against its own paper as  */
/* the shipped tan had against #f1ebe0), so the document reads the same  */
/* on all of them. The poppy accent and the flower colours never move.   */
/* ------------------------------------------------------------------ */
:root[data-ground="white"] {
  --paper:   #ffffff;  --paper-2: #e0e0e0;
  --ink:     #1d1d1d;  --muted:   #767676;  --faint: #a8a8a8;
  --hair:    #d2d2d2;  --hair-2:  #e1e1e1;
}
:root[data-ground="green"] {
  --paper:   #eaefe4;  --paper-2: #e0e2dc;
  --ink:     #1c1f1a;  --muted:   #6a6d65;  --faint: #a9afa3;
  --hair:    #d3d7cf;  --hair-2:  #e1e4dd;
}
:root[data-ground="sage"] {
  --paper:   #97a38a;  --paper-2: #8b9382;
  --ink:     #1a1d18;  --muted:   #343831;  --faint: #697062;
  --hair:    #889080;  --hair-2:  #92988a;
  --poppy:   #922f1a;
}
.ground-dot-white { --swatch: #ffffff; }
.ground-dot-green { --swatch: #eaefe4; }
.ground-dot-sage { --swatch: #97a38a; }


/* ------------------------------------------------------------------ */
/* GROUND THEMES — the picker swaps these token sets. Each ground has   */
/* its own neutral ramp (same contrast ratios against its own paper as  */
/* the shipped tan had against #f1ebe0), so the document reads the same  */
/* on all of them. The poppy accent and the flower colours never move.   */
/* ------------------------------------------------------------------ */
:root[data-ground="white"] {
  --paper:   #ffffff;  --paper-2: #e0e0e0;
  --ink:     #1d1d1d;  --muted:   #767676;  --faint: #a8a8a8;
  --hair:    #d2d2d2;  --hair-2:  #e1e1e1;
}
:root[data-ground="green"] {
  --paper:   #eaefe4;  --paper-2: #e0e2dc;
  --ink:     #1c1f1a;  --muted:   #6a6d65;  --faint: #a9afa3;
  --hair:    #d3d7cf;  --hair-2:  #e1e4dd;
}
:root[data-ground="paper"] {
  --paper:   #f1ebe0;  --paper-2: #e7dfd0;
  --ink:     #211c16;  --muted:   #8a8073;  --faint: #b4aa98;
  --hair:    #ddd3c2;  --hair-2:  #e8e0d1;
}
.ground-dot-white { --swatch: #ffffff; }
.ground-dot-green { --swatch: #eaefe4; }
.ground-dot-paper { --swatch: #f1ebe0; }


/* ------------------------------------------------------------------ */
/* GROUND THEMES — the picker swaps these token sets. Each ground has   */
/* its own neutral ramp (same contrast ratios against its own paper as  */
/* the shipped tan had against #f1ebe0), so the document reads the same  */
/* on all of them. The poppy accent and the flower colours never move.   */
/* ------------------------------------------------------------------ */
:root[data-ground="white"] {
  --paper:   #ffffff;  --paper-2: #e0e0e0;
  --ink:     #1d1d1d;  --muted:   #767676;  --faint: #a8a8a8;
  --hair:    #d2d2d2;  --hair-2:  #e1e1e1;
}
:root[data-ground="green"] {
  --paper:   #eaefe4;  --paper-2: #e0e2dc;
  --ink:     #1c1f1a;  --muted:   #6a6d65;  --faint: #a9afa3;
  --hair:    #d3d7cf;  --hair-2:  #e1e4dd;
}
:root[data-ground="paper"] {
  --paper:   #f1ebe0;  --paper-2: #e7dfd0;
  --ink:     #211c16;  --muted:   #8a8073;  --faint: #b4aa98;
  --hair:    #ddd3c2;  --hair-2:  #e8e0d1;
}
.ground-dot-white { --swatch: #ffffff; }
.ground-dot-green { --swatch: #eaefe4; }
.ground-dot-paper { --swatch: #f1ebe0; }


/* ------------------------------------------------------------------ */
/* GROUND THEMES — the picker swaps these token sets. Each ground has   */
/* its own neutral ramp (same contrast ratios against its own paper as  */
/* the shipped tan had against #f1ebe0), so the document reads the same  */
/* on all of them. The poppy accent and the flower colours never move.   */
/* ------------------------------------------------------------------ */
:root[data-ground="white"] {
  --paper:   #ffffff;  --paper-2: #e0e0e0;
  --ink:     #1d1d1d;  --muted:   #767676;  --faint: #a8a8a8;
  --hair:    #d2d2d2;  --hair-2:  #e1e1e1;
}
:root[data-ground="green"] {
  --paper:   #eaefe4;  --paper-2: #e0e2dc;
  --ink:     #1c1f1a;  --muted:   #6a6d65;  --faint: #a9afa3;
  --hair:    #d3d7cf;  --hair-2:  #e1e4dd;
}
:root[data-ground="paper"] {
  --paper:   #f1ebe0;  --paper-2: #e7dfd0;
  --ink:     #211c16;  --muted:   #8a8073;  --faint: #b4aa98;
  --hair:    #ddd3c2;  --hair-2:  #e8e0d1;
}
.ground-dot-white { --swatch: #ffffff; }
.ground-dot-green { --swatch: #eaefe4; }
.ground-dot-paper { --swatch: #f1ebe0; }


/* ------------------------------------------------------------------ */
/* GROUND THEMES — the picker swaps these token sets. Each ground has   */
/* its own neutral ramp (same contrast ratios against its own paper as  */
/* the shipped tan had against #f1ebe0), so the document reads the same  */
/* on all of them. The poppy accent and the flower colours never move.   */
/* ------------------------------------------------------------------ */
:root[data-ground="white"] {
  --paper:   #ffffff;  --paper-2: #e0e0e0;
  --ink:     #1d1d1d;  --muted:   #767676;  --faint: #a8a8a8;
  --hair:    #d2d2d2;  --hair-2:  #e1e1e1;
}
:root[data-ground="green"] {
  --paper:   #eaefe4;  --paper-2: #e0e2dc;
  --ink:     #1c1f1a;  --muted:   #6a6d65;  --faint: #a9afa3;
  --hair:    #d3d7cf;  --hair-2:  #e1e4dd;
}
:root[data-ground="paper"] {
  --paper:   #f1ebe0;  --paper-2: #e7dfd0;
  --ink:     #211c16;  --muted:   #8a8073;  --faint: #b4aa98;
  --hair:    #ddd3c2;  --hair-2:  #e8e0d1;
}
.ground-dot-white { --swatch: #ffffff; }
.ground-dot-green { --swatch: #eaefe4; }
.ground-dot-paper { --swatch: #f1ebe0; }

/* ================================================================== */
/* GROUND PICKER — the ground swatches, in the strip ABOVE the studio    */
/* header's boxes, so they clear the wordmark / contact / nav grid at   */
/* every width and sit far from the title canvas's brush area.         */
/* ================================================================== */
.ground-pick {
  position: fixed; top: 7px; right: clamp(12px, 2vw, 26px); z-index: 60;
  display: flex; gap: 7px; align-items: center;
  padding: 0; margin: 0; line-height: 0;
}
.ground-dot {
  width: 11px; height: 11px; padding: 0; border-radius: 50%;
  border: 1px solid var(--faint); background: var(--swatch, #fff);
  cursor: pointer; -webkit-appearance: none; appearance: none;
  transition: transform .18s var(--ease), border-color .18s var(--ease),
              box-shadow .18s var(--ease);
}
.ground-dot:hover { transform: scale(1.25); border-color: var(--muted); }
.ground-dot:focus-visible {
  outline: none; border-color: var(--poppy);
  box-shadow: 0 0 0 2px var(--paper), 0 0 0 3px var(--poppy);
}
/* current selection: a poppy ring, the same accent the nav uses */
.ground-dot[aria-checked="true"] {
  border-color: var(--poppy);
  box-shadow: 0 0 0 1px var(--poppy);
}
@media (prefers-reduced-motion: reduce) {
  .ground-dot { transition: none; }
  .ground-dot:hover { transform: none; }
}

/* ANIMAL CROSSING GRASS GROUND — this variant's own default. */
:root[data-ground="acgrass"] {
  --paper:   #dcedb2;  --paper-2: #cfe2a2;
  --ink:     #202614;  --muted:   #5c6a42;  --faint: #94a374;
  --hair:    #c2d494;  --hair-2:  #cfe0a4;
}
.ground-dot-acgrass { --swatch: #dcedb2; }


/* INK GROUND — the reference logo sits on black, and the high-key palette is
   built to carry it. Chrome inverts to read on the dark field. */
:root[data-ground="ink"] {
  --paper:   #14140f;  --paper-2: #1e1e18;
  --ink:     #f4f2e8;  --muted:   #a8a596;  --faint: #6e6c62;
  --hair:    #35342c;  --hair-2:  #26251f;
}
.ground-dot-ink { --swatch: #14140f; }

/* ================================================================== */
/* LOOK PICKER — the palette list, top-left, mirroring the ground      */
/* swatches on the right. Same quiet vocabulary as the rest of the      */
/* chrome: Space Mono caps, a poppy rule on the active row.             */
/* ================================================================== */
.look-pick {
  position: fixed; top: 7px; left: clamp(12px, 2vw, 26px); z-index: 60;
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
}
.look-title {
  font: 400 9px/1.4 var(--mono); letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 3px;
}
.look-item {
  appearance: none; border: 0; background: none; cursor: pointer;
  padding: 2px 6px 2px 8px; margin: 0;
  font: 400 10px/1.5 var(--mono); letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted); box-shadow: inset 2px 0 0 transparent;
  transition: color .2s var(--ease), box-shadow .2s var(--ease), background .2s var(--ease);
}
.look-item:hover { color: var(--ink); background: rgba(207, 67, 37, 0.045); }
.look-item:focus-visible { outline: 2px solid var(--poppy); outline-offset: 1px; }
.look-item[aria-checked="true"] { color: var(--ink); box-shadow: inset 2px 0 0 var(--poppy); }

/* Render exact keeps its own two grounds here as well */
:root[data-variant="exp2exact"][data-ground="paper"] {
  --paper:   #fbfbda;  --paper-2: #f2f0c1;
  --ink:     #292817;  --muted:   #7d7946;  --faint: #b8b683;
  --hair:    #e7e4a8;  --hair-2:  #f3f1c2;
}
:root[data-variant="exp2exact"][data-ground="green"] {
  --paper:   #e9f6da;  --paper-2: #e3e6df;
  --ink:     #1f221b;  --muted:   #6b7065;  --faint: #acb3a3;
  --hair:    #d7dbd2;  --hair-2:  #e5e9e0;
}
@media (max-width: 720px) {
  .look-pick { gap: 0; }
  .look-title { display: none; }
  .look-item { font-size: 9px; padding: 1px 5px 1px 7px; }
}

/* Both pickers belong to the HERO only: they are a way to try the title on,
   not site chrome. Once the wind carries the title off and the studio document
   stages in (body.revealed), they fade out and stop taking pointer events;
   scrolling back to the top brings them with the title. */
.look-pick, .ground-pick {
  transition: opacity .35s var(--ease), visibility .35s var(--ease);
}
body.revealed .look-pick,
body.revealed .ground-pick {
  opacity: 0; visibility: hidden; pointer-events: none;
}

/* The swatch strip gains a heading, mirroring the palette list on the left:
   the label sits above, the dots keep their own row. */
.ground-pick {
  flex-direction: column; align-items: flex-end; gap: 0; line-height: normal;
}
.ground-title {
  font: 400 9px/1.4 var(--mono); letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 6px;
}
.ground-row { display: flex; gap: 7px; align-items: center; line-height: 0; }
@media (max-width: 720px) {
  .look-title { display: block; }     /* both headings stay legible on mobile */
}

/* ------------------------------------------------------------------ */
/* Phone-only CONTACT CARD (scroll.js contactSection) — a 1px-ink boxed  */
/* block below the form: "Contact" head row, address + email row,       */
/* Instagram row. Hidden on desktop, where the header band carries the   */
/* same details.                                                          */
/* ------------------------------------------------------------------ */
.contact-card { display: none; }
@media (max-width: 720px) {
  .contact-card {
    display: block; margin-top: clamp(36px, 10vw, 56px);
    border: 1px solid var(--ink);
  }
  .cc-row {
    display: flex; flex-direction: column; gap: 6px;
    padding: 14px 16px; color: var(--ink);
  }
  .cc-row + .cc-row { border-top: 1px solid var(--ink); }
  .cc-label { font: 700 15px/1.4 var(--mono); }
  .cc-value { font: 400 15px/1.5 var(--mono); color: inherit; text-decoration: none; }
}

/* The wind-study selector panel (#windLinePanel) is a research control, not
   site UI — hidden on EVERY viewport (2026-09-14; it was still showing on
   phones). The ?wind= query flag keeps working for anyone who needs it. */
#windLinePanel { display: none !important; }
