/* ==========================================================================
   KF Crafts — concept site
   One deliberate dark theme. Ink is the ground (85%+ of every surface);
   champagne appears only as a line, a number or a frame — never a fill.
   Order: tokens · base · primitives · views · masthead · film · home blocks ·
          menu pages · contact · FAQ · footer · lightbox · motion.
   ========================================================================== */

:root {
  color-scheme: dark;

  /* Brand (BRANDBOOK) */
  --ink: #0a0a0a;
  --ink-2: #121110;
  --ink-3: #1a1917;
  --gold: #c5a253;
  --champagne: #d8c79c;
  --gold-hi: #e3ce92;
  --gold-lo: #8e7231;
  --paper: #f4f1ea;
  --muted: #8a8a86;
  --error: #e59c84;

  /* Accents (owner, 25.09: "black and gold, plus what fits") — used sparingly: a hover, a hairline, a
     small highlight, the moonlit mood. Never a background, never a block of colour. */
  --cedar: #b27a4f;       /* warm cedar: numbers, a warm hover */
  --ivory: #f2ebdc;       /* ivory: headings on photographs, a pressed state */
  --moon: #b9c7d8;        /* moonlight silver-blue: the night's hairlines and small labels */
  --moon-dim: rgba(185, 199, 216, 0.34);
  --water: #5fc4bd;       /* water teal: the one live dot (current item, focus pulse) */

  /* Text on ink — body never below 0.78 paper */
  --text-strong: rgba(244, 241, 234, 0.96);
  --text: rgba(244, 241, 234, 0.82);
  --text-dim: rgba(244, 241, 234, 0.78);

  /* Hairlines */
  --line: rgba(216, 199, 156, 0.26);
  --line-strong: rgba(216, 199, 156, 0.55);
  --rule: rgba(244, 241, 234, 0.1);

  /* Type */
  --sans: "Jost", "Futura PT", Futura, "Avenir Next", "Century Gothic", system-ui, -apple-system, "Segoe UI", sans-serif;
  --seal: "Cinzel", "Trajan Pro", Georgia, "Times New Roman", serif;
  --fs-display: clamp(2.375rem, 1.45rem + 4.1vw, 5.5rem);
  --fs-h2: clamp(2.125rem, 1.4rem + 2.8vw, 4.25rem);
  --fs-h3: clamp(1.625rem, 1.3rem + 1.3vw, 2.5rem);
  --fs-lead: clamp(1.125rem, 1.03rem + 0.4vw, 1.375rem);

  /* Layout */
  --gutter: clamp(1rem, 4vw, 4rem);
  --maxw: 88rem;
  --col-gap: clamp(1rem, 1.8vw, 1.75rem);
  --section-pad: clamp(3.5rem, 6vw, 6rem);
  --header-h: 64px;
  --masthead-h: 100px;   /* main.js: the header's visible bottom edge (banner + header, header alone once scrolled) */
  --masthead-full: 100px; /* main.js: banner + header at rest */
  --banner-h: 0px;

  /* Motion */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
}

@media (min-width: 1000px) {
  :root { --header-h: 76px; }
}

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

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

html {
  background: var(--ink);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: calc(var(--header-h) + 1rem);
}

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
/* Desktop wheel: js/smooth.js glides the page itself, so its per-frame scrollTo must land at once. The
   site's own link scrolls ask for "smooth" explicitly and keep it. */
html.has-smooth-wheel { scroll-behavior: auto; }

html.is-locked { overflow: hidden; }

body {
  margin: 0;
  min-width: 320px;
  background: var(--ink);
  color: var(--text);
  font-family: var(--sans);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-kerning: normal;
  overflow-wrap: break-word;
  overflow-x: clip; /* safety net only; nothing should overflow by design */
}

h1, h2, h3, h4, p, ul, ol, dl, dd, figure, blockquote { margin: 0; }
ul[role="list"], ol[role="list"] { list-style: none; padding: 0; }

h1, h2, h3, h4 {
  color: var(--text-strong);
  font-weight: 300;
  text-wrap: balance;
}

p { text-wrap: pretty; }

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

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

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

:focus-visible {
  outline: 2px solid var(--gold-hi);
  outline-offset: 3px;
}

/* Sections and chapters receive programmatic focus after in-page navigation. */
[tabindex="-1"]:focus { outline: none; }

::selection { background: rgba(216, 199, 156, 0.32); color: var(--paper); }

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

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

.skip-link {
  position: fixed;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 100;
  padding: 0.75rem 1rem;
  background: var(--paper);
  color: var(--ink);
  font-weight: 500;
  transform: translateY(-200%);
}
.skip-link:focus { transform: none; }

.selectable { -webkit-user-select: text; user-select: text; }

/* ---------- Primitives ---------- */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: max(var(--gutter), env(safe-area-inset-left)) max(var(--gutter), env(safe-area-inset-right));
}

.section { position: relative; padding-block: var(--section-pad); }

/* Seal-style eyebrow: Cinzel, tiny, letter-spaced, led by a single champagne line. */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  color: var(--champagne);
  font-family: var(--seal);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}
.eyebrow::before {
  content: "";
  flex: none;
  width: 1.75rem;
  height: 1px;
  background: currentColor;
}

.h2 {
  font-size: var(--fs-h2);
  font-weight: 200;
  line-height: 1.06;
  letter-spacing: -0.02em;
}

.h3 {
  font-size: var(--fs-h3);
  font-weight: 200;
  line-height: 1.12;
  letter-spacing: -0.015em;
}

.lead {
  color: var(--text);
  font-size: var(--fs-lead);
  font-weight: 300;
  line-height: 1.6;
}

.kicker {
  color: var(--text-strong);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

.caption {
  margin-top: 0.75rem;
  color: var(--muted);
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
}

/* Section head: the champagne hairline is the structure every section hangs from. */
.head {
  display: grid;
  gap: 1.25rem var(--col-gap);
  margin-bottom: clamp(3rem, 6vw, 6rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.head__intro { max-width: 34rem; color: var(--text); }
.head__intro.lead { max-width: 36rem; }

@media (min-width: 1024px) {
  .head { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: end; }
  .head__eyebrow { grid-column: 1 / -1; }
  .head__title { grid-column: 1 / 8; }
  .head__intro { grid-column: 9 / 13; padding-bottom: 0.4rem; }
}

/* Primary button: champagne outline; champagne wipes in on hover. */
.btn {
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0.8rem 1.6rem;
  overflow: hidden;
  border: 1px solid var(--champagne);
  color: var(--champagne);
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0.2em;
  text-align: center;
  text-transform: uppercase;
  transition: color 0.45s var(--ease-out), transform 0.6s var(--ease-out);
}
/* Magnetic (main.js, fine pointers): the button leans a few pixels toward the pointer; quicker while it follows. */
.btn.is-magnetic { transition: color 0.45s var(--ease-out), transform 0.18s ease-out; }
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--champagne);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 0.6s var(--ease-out);
}
.btn:focus-visible { color: var(--ink); }
.btn:focus-visible::before { transform: scaleX(1); transform-origin: left center; }
@media (hover: hover) {
  .btn:hover { color: var(--ink); }
  .btn:hover::before { transform: scaleX(1); transform-origin: left center; }
}
.btn:active::before { background: var(--gold-hi); }

.btn--sm {
  min-height: 44px;
  padding: 0.65rem 1.15rem;
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
}

/* Secondary: a text link whose underline draws itself on hover. */
.link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--text-strong);
  font-size: 0.9375rem;
  font-weight: 400;
  letter-spacing: 0.02em;
}
.link__text {
  position: relative;
  padding-bottom: 4px;
}
/* Resting underline (quiet paper) and the champagne line that draws over it. */
.link__text::before,
.link__text::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
}
.link__text::before { background: rgba(244, 241, 234, 0.35); }
.link__text::after {
  background: var(--champagne);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 0.55s var(--ease-out);
}
.link:focus-visible .link__text::after { transform: scaleX(1); transform-origin: left center; }
@media (hover: hover) {
  .link:hover .link__text::after { transform: scaleX(1); transform-origin: left center; }
}

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 2rem;
}

/* Prices: the number is the one champagne element; qualifiers stay quiet. */
.price {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.4em;
  color: var(--champagne);
  font-size: 1.125rem;
  font-weight: 300;
  line-height: 1.3;
  font-variant-numeric: lining-nums tabular-nums;
  white-space: nowrap;
}
.price__from,
.price__vat {
  color: var(--text-dim);
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.price--xl {
  font-size: clamp(2.5rem, 1.9rem + 2.6vw, 4rem);
  font-weight: 200;
  letter-spacing: -0.02em;
  line-height: 1.05;
}
.price--xl .price__from,
.price--xl .price__vat { letter-spacing: 0.18em; }

/* Image labels — legally required, so sized to stay readable on a phone. */
.tag {
  position: absolute;
  left: 0.625rem;
  bottom: 0.625rem;
  z-index: 1;
  max-width: calc(100% - 1.25rem);
  padding: 0.375rem 0.625rem 0.4rem;
  border-left: 1px solid var(--champagne);
  background: rgba(10, 10, 10, 0.74);
  color: rgba(244, 241, 234, 0.92);
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 400;
  line-height: 1.35;
  letter-spacing: 0.02em;
  text-align: left;
  pointer-events: none;
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .tag {
    background: rgba(10, 10, 10, 0.6);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
  }
}
.tag--built { letter-spacing: 0.12em; text-transform: uppercase; font-size: 0.75rem; }

/* ---------- Views ----------
   One screen at a time: html[data-screen] (set in <head> from the address, then by main.js on every
   hashchange) shows the matching [data-screen] and nothing else; the FAQ and the footer are outside the
   screens, so every page has them. Without JS every screen shows, in turn. A menu page starts under the
   fixed masthead with a way back; home starts under it on purpose (the film). */

.js [data-screen] { display: none; }
.js[data-screen="home"] [data-screen="home"],
.js[data-screen="work"] [data-screen="work"],
.js[data-screen="annexe"] [data-screen="annexe"],
.js[data-screen="build"] [data-screen="build"],
.js[data-screen="about"] [data-screen="about"],
.js[data-screen="studio"] [data-screen="studio"] { display: block; }

.view { padding-top: calc(var(--masthead-full) + 0.75rem); }
.view__back {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  min-height: 44px;
  margin-bottom: 1rem;
  color: var(--text-dim);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  transition: color 0.3s;
}
.view__back span { font-size: 1.2em; letter-spacing: 0; }
@media (hover: hover) {
  .view__back:hover { color: var(--champagne); }
}
html:not(.js) .view__back { display: none; }

/* ---------- Masthead: concept banner + header ---------- */

.masthead {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  color: var(--paper);
  transition: top 0.5s var(--ease-out);
}
/* Once scrolled, the banner slides up out of view with the header following it: the masthead never
   changes size (no reflow of the page under it), and --masthead-h changes once, not every frame.
   (top, not transform: a transform would trap the fixed phone menu inside the masthead.) */
.masthead.is-scrolled { top: calc(-1 * var(--banner-h)); }
/* Solid layer lives on a pseudo-element: backdrop-filter on .masthead itself would
   trap the fixed mobile menu inside the header box. */
/* Once solid, solid: ink with a champagne hairline — never a translucent grey over a daylight picture
   or the 3D scenes. */
.masthead::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--ink);
  border-bottom: 1px solid rgba(216, 199, 156, 0.3);
  opacity: 0;
  transition: opacity 0.45s var(--ease-out);
}
.masthead.is-solid::before { opacity: 1; }
/* Without JS nothing can make the header solid, so it stays at the top of the film and scrolls away. */
html:not(.js) .masthead { position: absolute; }

.banner {
  position: relative;
  background: rgba(10, 10, 10, 0.88);
  border-bottom: 1px solid var(--rule);
  transition: opacity 0.35s ease, visibility 0s linear 0s;
}
.banner[hidden] { display: none; }
.banner__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding-inline: max(var(--gutter), env(safe-area-inset-left)) calc(max(var(--gutter), env(safe-area-inset-right)) - 12px);
}
.banner__text {
  padding-block: 0.45rem;
  color: rgba(244, 241, 234, 0.84);
  font-size: 0.75rem;
  line-height: 1.45;
  letter-spacing: 0.06em;
}
.banner__close {
  display: grid;
  place-items: center;
  flex: none;
  position: relative;
  width: 44px;
  height: 36px;
  color: rgba(244, 241, 234, 0.8);
  transition: color 0.3s;
}
.banner__close::after { content: ""; position: absolute; inset: -4px 0; } /* a 44px target in a 36px strip */
.banner__close:hover { color: var(--champagne); }
.masthead.is-scrolled .banner {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0s linear 0.5s;
}

.header {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  height: var(--header-h);
  padding-inline: max(var(--gutter), env(safe-area-inset-left)) max(var(--gutter), env(safe-area-inset-right));
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 44px;
  min-width: 44px; /* the scrolled seal is 42px: keep a 44px target */
}
/* The compact seal (ring, the lit annexe, KF CRAFTS). 48px on phones, 58px on desktop; it settles a size
   smaller once the page scrolls (the masthead's .is-scrolled). main.js brings it in on first load. */
.brand__seal {
  flex: none;
  width: 48px;
  height: 48px;
  overflow: visible;
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.45));
  transition: width 0.5s var(--ease-out), height 0.5s var(--ease-out);
}
@media (min-width: 1000px) {
  .brand__seal { width: 60px; height: 60px; }
}
.masthead.is-scrolled .brand__seal { width: 42px; height: 42px; }
@media (min-width: 1000px) {
  .masthead.is-scrolled .brand__seal { width: 50px; height: 50px; }
}
.brand__seal .kf-glass { filter: drop-shadow(0 0 6px rgba(243, 227, 176, 0.35)); }
@media (hover: hover) {
  .brand:hover .brand__seal .kf-glass { filter: drop-shadow(0 0 9px rgba(243, 227, 176, 0.7)); }
}
@keyframes kf-show { to { visibility: visible; } }
.brand__word {
  color: var(--paper);
  font-size: 0.875rem;
  font-weight: 300;
  line-height: 1;
  letter-spacing: 0.34em;
  white-space: nowrap;
}

/* Navigation: the header carries the logo, "Design in 3D", Contact and the Menu button; everything
   else lives in the full-screen cinematic menu (css/menu.css, the <dialog> after the header). */

@media (max-width: 359.98px) {
  .brand__word { letter-spacing: 0.24em; }
}

/* ===== THE HOME FILM HAS TWO MODES (13.10.2026, evening) =====
   Desktop and laptop (min-width 1024px and a fine pointer) keep the ORIGINAL scroll film: a pinned stage, the camera
   walking through the garden frame by frame as the page scrolls (js/film.js), the words and the progress line along
   the way. Phones and tablets (below 1024px, or a coarse pointer) get the plain self-starting film with captions on
   its own clock (js/film-live.js, no scroll effect). <head> decides once, at parse time: html.kf-live = the second.
   Every rule of the two blocks below carries a zero-specificity guard, :where(html:not(.kf-live)) for the scroll film
   and :where(html.kf-live) for the plain film, so each block applies only to its own markup and the specificity of
   every selector (against layers.css, intro.css …) is exactly what it was. The scroll film's block is the 06.10
   production file byte for byte, guards aside.
   Both film sections are in index.html; a script after each removes the one this screen does not use. Without JS the
   scroll film shows and the plain film's section is hidden here. */
html:not(.js) .film[data-film-live] { display: none; }

/* ---------- THE SCROLL FILM (desktop · html:not(.kf-live)) ---------- */
/* ---------- 2 · The film (Round 4: ONE continuous film) ----------
   The stage is pinned (sticky) for the whole section; the chapters scroll over it (the first is pulled
   up over the stage with a negative margin) and each chapter's copy is sticky at the foot of the screen.
   film.js plays one frame sequence through the whole section and switches chapters as a chapter's top
   crosses the middle of the stage.

   Without the film (no JS, or it failed): chapters are plain one-screen blocks, the stage keeps the
   first frame as its CSS background (the LCP), and every chapter's copy stays visible, scrolling over it.

   While the film runs (film.js sets .film--running and [data-chapter]; CSS keys on the class only, so the
   chapter number changing never re-styles the whole film): consecutive chapters overlap by half a screen, so a
   chapter's copy is already pinned at the foot when its top reaches mid-stage. Each chapter is worth
   --frames × --film-frame of scroll, in proportion to its footage, so the camera keeps one steady pace
   from the garden to the golf room: 477 units — 5.7 screens of pinned scroll at 1440 × 900 (6.7 with the
   stage leaving), 4.8 (5.8) on phones. Within a chapter the words show only while the camera is at the
   place (.is-shown, from data-show) and step aside while it travels (owner, 26.09: "one film, everything
   alive … it must never feel slow; the camera always moves"). */

:where(html:not(.kf-live)) .film {
  --sv: 1vh; /* one "small viewport" unit, where supported */
  --film-chapter: calc(100 * var(--sv));
  --film-frame: calc(1.2 * var(--sv));  /* scroll per master frame of footage */
  --film-overlap: calc(50 * var(--sv)); /* must stay half the stage: film.js switches at mid-stage */
  --film-copy-bottom: calc(4.25rem + env(safe-area-inset-bottom));
  position: relative;
  background: var(--ink);
}
@supports (height: 1svh) {
  :where(html:not(.kf-live)) .film { --sv: 1svh; }
}
@media (max-width: 899.98px) {
  :where(html:not(.kf-live)) .film { --film-frame: calc(1 * var(--sv)); }
}

:where(html:not(.kf-live)) .film__stage {
  position: sticky;
  top: 0;
  z-index: 0;
  /* dvh: the image always reaches the bottom edge, with Safari's toolbar in or out. */
  height: 100vh;
  height: 100svh;
  height: 100dvh;
  overflow: hidden;
  background-color: var(--ink);
  /* The film's first frame (the LCP, preloaded in <head>): the canvas fades in over the same picture. */
  background-image: url("assets/seq/journey/0001.webp");
  background-position: 50% 50%;
  background-size: cover;
  background-repeat: no-repeat;
}
@media (max-aspect-ratio: 9/10) {
  :where(html:not(.kf-live)) .film__stage { background-image: url("assets/seq/journey/v/0001.webp"); background-position: 50% 50%; }
}

:where(html:not(.kf-live)) .film__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Legibility scrims (functional, not decorative): header at the top, copy at the foot. */
:where(html:not(.kf-live)) .film__stage::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(10, 10, 10, 0.62) 0%, rgba(10, 10, 10, 0.2) 14%, rgba(10, 10, 10, 0) 26%),
    linear-gradient(to top, rgba(10, 10, 10, 0.9) 0%, rgba(10, 10, 10, 0.55) 32%, rgba(10, 10, 10, 0) 64%);
}
@media (min-width: 900px) {
  :where(html:not(.kf-live)) .film__stage::after {
    background:
      linear-gradient(to bottom, rgba(10, 10, 10, 0.55) 0%, rgba(10, 10, 10, 0) 22%),
      linear-gradient(to top, rgba(10, 10, 10, 0.78) 0%, rgba(10, 10, 10, 0) 48%),
      linear-gradient(to left, rgba(10, 10, 10, 0.34) 0%, rgba(10, 10, 10, 0) 16%),
      linear-gradient(to right, rgba(10, 10, 10, 0.55) 0%, rgba(10, 10, 10, 0) 58%);
  }
}
/* The resolve: as the last place gives way to the invitation, the night closes in around the words
   (opacity only, on its own layer — never a filter on the moving picture). */
:where(html:not(.kf-live)) .film__stage::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(120% 90% at 50% 70%, rgba(10, 10, 10, 0.45) 0%, rgba(10, 10, 10, 0.86) 70%, var(--ink) 100%);
  opacity: 0;
  transition: opacity 1.6s var(--ease-out);
}
:where(html:not(.kf-live)) .film.film--end .film__stage::before { opacity: 1; }

/* The honest minimum on AI imagery (UK CAP / DMCC), done the way property developers do it: a tiny,
   low-contrast CGI in the corner of the stage, always on screen with the film; the footer explains it. */
:where(html:not(.kf-live)) .film__label {
  position: absolute;
  right: max(var(--gutter), env(safe-area-inset-right));
  bottom: calc(1rem + env(safe-area-inset-bottom));
  z-index: 3;
  margin: 0;
  color: rgba(244, 241, 234, 0.56);
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.24em;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.7);
  pointer-events: none;
}

/* Small caps used by the progress line's names and the skip link. */
:where(html:not(.kf-live)) .film__now,
:where(html:not(.kf-live)) .film__skip,
:where(html:not(.kf-live)) .film__tick-name {
  color: rgba(244, 241, 234, 0.84);
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.6);
}

/* The progress line — one hairline that fills as the film plays (film.js sets the fill's transform), with a
   mark where each place's words appear (--at, from main.js). It follows the film, so without JS it isn't
   shown. Phone: across the top under the header, the place's number and name beneath. */
html:where(:not(.kf-live)):not(.js) .film__rail { display: none; }
/* Only the marks take taps: the rail's box never covers "Skip film" beside it. */
:where(html:not(.kf-live)) .film__rail { pointer-events: none; }
:where(html:not(.kf-live)) .film__tick { pointer-events: auto; }

:where(html:not(.kf-live)) .film__rail {
  position: absolute;
  top: calc(var(--masthead-h) + 0.25rem);
  left: max(var(--gutter), env(safe-area-inset-left));
  right: max(var(--gutter), env(safe-area-inset-right));
  z-index: 3;
  display: flex;
  flex-direction: column-reverse;
  gap: 0.1rem;
  transition: top 0.5s var(--ease-out), opacity 0.8s var(--ease-out);
}
:where(html:not(.kf-live)) .film.film--end .film__rail { opacity: 0; }
:where(html:not(.kf-live)) .film__now { display: flex; align-items: baseline; gap: 0.75rem; }
:where(html:not(.kf-live)) .film__now-num { color: var(--champagne); font-variant-numeric: tabular-nums; }
:where(html:not(.kf-live)) .film__track { position: relative; height: 36px; }
:where(html:not(.kf-live)) .film__line {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 1px;
  background: rgba(244, 241, 234, 0.26);
}
:where(html:not(.kf-live)) .film__fill {
  position: absolute;
  inset: 0;
  background: var(--champagne);
  transform: scaleX(0); /* film.js writes scaleX(t) / scaleY(t) straight onto the fill, every frame */
  transform-origin: left center;
  will-change: transform;
}
:where(html:not(.kf-live)) .film__ticks { position: absolute; inset: 0; }
:where(html:not(.kf-live)) .film__ticks li { position: absolute; top: 0; bottom: 0; left: calc(var(--at, 0) * 100%); }
/* Each mark: a 44 × 44 target centred on a small notch in the line. */
:where(html:not(.kf-live)) .film__tick {
  position: absolute;
  top: 50%;
  left: -22px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-top: -22px;
}
:where(html:not(.kf-live)) .film__tick::before {
  content: "";
  width: 1px;
  height: 9px;
  background: rgba(244, 241, 234, 0.6);
  transition: background-color 0.5s var(--ease-out), transform 0.5s var(--ease-out);
}
:where(html:not(.kf-live)) .film__tick[aria-current="step"]::before { background: var(--champagne); transform: scaleY(1.6); }
:where(html:not(.kf-live)) .film__ticks li:first-child .film__tick { left: -12px; }
/* Names: read by screen readers on phones, shown beside the line on desktop. */
:where(html:not(.kf-live)) .film__tick-name {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Skip — phone: right-aligned on the place-name line (a 44px target centred on it). */
:where(html:not(.kf-live)) .film__skip {
  position: absolute;
  z-index: 3;
  top: calc(var(--masthead-h) + 0.25rem + 36px + 0.1rem + 7px - 22px);
  right: max(var(--gutter), env(safe-area-inset-right));
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  min-height: 44px;
  padding-left: 0.75rem;
  transition: color 0.3s, top 0.5s var(--ease-out), opacity 0.8s var(--ease-out);
}
:where(html:not(.kf-live)) .film.film--end .film__skip { opacity: 0; pointer-events: none; }
/* Phone (Round 4 fix): the first screen is the picture and the slogan. The place line and "Skip film" join the
   progress hairline once the visitor starts to scroll (main.js sets #film.kf-moved). */
@media (max-width: 899.98px) {
  html:where(:not(.kf-live)).js .film:not(.kf-moved) .film__now,
  html:where(:not(.kf-live)).js .film:not(.kf-moved) .film__skip { opacity: 0; visibility: hidden; }
  :where(html:not(.kf-live)) .film__now { transition: opacity 0.8s var(--ease-out), visibility 0s; }
}
:where(html:not(.kf-live)) .film__skip span { font-size: 1.2em; letter-spacing: 0; }
@media (hover: hover) {
  :where(html:not(.kf-live)) .film__skip:hover { color: var(--champagne); }
}

/* Desktop: the line stands on the right edge, the places' names beside it; skip sits bottom-left,
   level with the CGI label. */
@media (min-width: 900px) {
  :where(html:not(.kf-live)) .film { --film-copy-bottom: clamp(5.5rem, 12vh, 8.5rem); }

  :where(html:not(.kf-live)) .film__label { bottom: 1.75rem; }

  :where(html:not(.kf-live)) .film__rail {
    top: 50%;
    left: auto;
    right: max(var(--gutter), env(safe-area-inset-right));
    transform: translateY(-50%);
  }
  :where(html:not(.kf-live)) .film__now { display: none; }
  :where(html:not(.kf-live)) .film__track { width: 11rem; height: min(46svh, 26rem); }
  :where(html:not(.kf-live)) .film__line { left: auto; right: 0; top: 0; bottom: 0; width: 1px; height: auto; }
  :where(html:not(.kf-live)) .film__fill { transform: scaleY(0); transform-origin: center top; }
  :where(html:not(.kf-live)) .film__ticks li { left: 0; right: 0; top: calc(var(--at, 0) * 100%); bottom: auto; height: 0; }
  :where(html:not(.kf-live)) .film__tick {
    left: auto;
    right: -22px;
    width: auto;
    min-width: 44px;
    height: 44px;
    margin-top: -22px;
    justify-content: flex-end;
    gap: 0.875rem;
    padding-right: 22px;
  }
  :where(html:not(.kf-live)) .film__ticks li:first-child .film__tick { left: auto; }
  :where(html:not(.kf-live)) .film__tick::before { width: 9px; height: 1px; margin-right: -4px; }
  :where(html:not(.kf-live)) .film__tick[aria-current="step"]::before { transform: scaleX(2.2); transform-origin: right center; }
  :where(html:not(.kf-live)) .film__tick-name {
    order: -1;
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
    color: rgba(244, 241, 234, 0.5);
    transition: color 0.5s var(--ease-out), opacity 0.5s var(--ease-out), transform 0.6s var(--ease-out);
  }
  :where(html:not(.kf-live)) .film__tick[aria-current="step"] .film__tick-name { color: var(--champagne); transform: translateX(-0.35rem); }
  @media (hover: hover) {
    :where(html:not(.kf-live)) .film__tick:hover .film__tick-name { color: var(--paper); }
  }

  :where(html:not(.kf-live)) .film__skip {
    top: auto;
    right: auto;
    bottom: calc(1.75rem - 14px);
    left: max(var(--gutter), env(safe-area-inset-left));
    padding-left: 0;
    font-size: 0.6875rem;
  }
}

/* Chapters: plain one-screen blocks until the film runs. */
:where(html:not(.kf-live)) .film__chapter {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  min-height: var(--film-chapter);
  /* Bottom padding = the copy's sticky offset, so when the stage leaves, the copy leaves with it at
     the same height instead of sliding down onto the CGI label. */
  padding: 0 max(var(--gutter), env(safe-area-inset-right)) var(--film-copy-bottom) max(var(--gutter), env(safe-area-inset-left));
  pointer-events: none;
}
/* Negative-margin overlay: the first chapter starts at the top of the pinned stage. */
:where(html:not(.kf-live)) .film__stage + .film__chapter { margin-top: calc(-1 * var(--film-chapter)); }
@media (max-width: 899.98px) {
  :where(html:not(.kf-live)) .film__chapter + .film__chapter { min-height: calc(var(--film-chapter) * 0.9); }
}

/* Film running: each chapter's own stretch of scroll is its footage (--frames, inline) at one pace; the
   chapters overlap by half a screen, and the first gets the extra half screen the overlap takes. */
:where(html:not(.kf-live)) .film.film--running .film__chapter { min-height: calc(var(--frames, 40) * var(--film-frame) + var(--film-overlap)); }
:where(html:not(.kf-live)) .film.film--running .film__chapter--hero { min-height: calc(var(--frames, 60) * var(--film-frame) + var(--film-overlap) + 50 * var(--sv)); }
:where(html:not(.kf-live)) .film.film--running .film__chapter + .film__chapter { margin-top: calc(-1 * var(--film-overlap)); }

/* No scroll-snap anywhere (owner 26.09: "the scroll effect — make it smoother"). The phone's own momentum
   scroll is left alone; film.js eases the picture after it with a critically damped spring and blends
   neighbouring frames, so a flick that stops between two places simply rests there, softly. */

:where(html:not(.kf-live)) .film__copy {
  position: sticky;
  bottom: var(--film-copy-bottom);
  width: 100%;
  max-width: 40rem;
  padding-bottom: 0.25rem;
  pointer-events: auto;
  text-shadow: 0 1px 28px rgba(0, 0, 0, 0.45);
}
:where(html:not(.kf-live)) .film__chapter--hero .film__copy { max-width: 50rem; }

:where(html:not(.kf-live)) .film__eyebrow { margin-bottom: 1.25rem; }

:where(html:not(.kf-live)) .film__title {
  color: var(--text-strong);
  font-size: clamp(2rem, 1.35rem + 2.9vw, 4rem);
  font-weight: 200;
  line-height: 1.06;
  letter-spacing: -0.02em;
}
:where(html:not(.kf-live)) .film__title--hero {
  font-size: var(--fs-display);
  font-size: min(var(--fs-display), 10.5svh);
  line-height: 1.02;
  letter-spacing: -0.025em;
}
/* The slogan lockup (ROUND3 §1, §11): the H1, then "Crafted for life." small, in champagne, hung from a
   hairline — a signature under the line, not a second headline. */
:where(html:not(.kf-live)) .hero__line { display: block; }
:where(html:not(.kf-live)) .hero__sig {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  margin-top: 0.9rem;
  color: var(--champagne);
  font-size: clamp(1.0625rem, 0.92rem + 0.75vw, 1.75rem);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: 0.04em;
}
:where(html:not(.kf-live)) .hero__sig::before {
  content: "";
  flex: none;
  width: clamp(1.75rem, 3vw, 3rem);
  height: 1px;
  background: currentColor;
  opacity: 0.8;
}
:where(html:not(.kf-live)) .film__copy--hero .film__meta { margin-top: 1.5rem; }

:where(html:not(.kf-live)) .film__sub {
  max-width: 34rem;
  margin-top: 1.25rem;
  color: rgba(244, 241, 234, 0.86);
  font-size: var(--fs-lead);
  font-weight: 300;
  line-height: 1.55;
}
:where(html:not(.kf-live)) .film__meta { margin-top: 1.25rem; font-size: 1.25rem; }
/* A price and a quiet link on one line (the annexe). */
:where(html:not(.kf-live)) .film__meta:has(.film__more) { display: flex; flex-wrap: wrap; align-items: center; gap: 0 1.75rem; }
:where(html:not(.kf-live)) .film__more { font-size: 1rem; }
/* Honesty line (pool / pond): small, in the moonlight tone, never hidden. */
:where(html:not(.kf-live)) .film__note {
  max-width: 30rem;
  margin-top: 0.75rem;
  color: var(--moon);
  font-size: 0.75rem;
  line-height: 1.45;
  letter-spacing: 0.02em;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7), 0 1px 18px rgba(0, 0, 0, 0.6);
}
:where(html:not(.kf-live)) .film__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 2rem;
  margin-top: 1.75rem;
}

/* The end card: centred, the invitation the whole film has been walking toward. */
:where(html:not(.kf-live)) .film__chapter--end { justify-content: center; }
:where(html:not(.kf-live)) .film__copy--end { max-width: 42rem; text-align: center; }
:where(html:not(.kf-live)) .film__copy--end .eyebrow { justify-content: center; }
:where(html:not(.kf-live)) .film__copy--end .eyebrow::after {
  content: "";
  flex: none;
  width: 1.75rem;
  height: 1px;
  background: currentColor;
}
:where(html:not(.kf-live)) .film__copy--end .film__title { font-size: clamp(2.25rem, 1.4rem + 3.4vw, 4.75rem); }
:where(html:not(.kf-live)) .film__copy--end .film__sub { margin-inline: auto; }
:where(html:not(.kf-live)) .film__copy--end .film__actions { justify-content: center; }

/* Phones: the small words sit on lit glass and roofs — a tight shadow under the soft one keeps the
   eyebrow and the lines readable without darkening the picture. */
@media (max-width: 899.98px) {
  :where(html:not(.kf-live)) .film__copy .eyebrow,
  :where(html:not(.kf-live)) .film__sub,
  :where(html:not(.kf-live)) .film__meta { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.65), 0 1px 24px rgba(0, 0, 0, 0.6); }
}
@media (max-width: 599.98px) {
  :where(html:not(.kf-live)) .film__eyebrow { margin-bottom: 0.875rem; }
  :where(html:not(.kf-live)) .film__sub { margin-top: 0.875rem; }
  :where(html:not(.kf-live)) .film__meta { margin-top: 0.875rem; font-size: 1.125rem; }
}
@media (max-width: 899.98px) and (max-height: 700px) {
  :where(html:not(.kf-live)) .film__chapter--hero .film__eyebrow { display: none; }
}
@media (max-width: 899.98px) and (max-height: 760px) {
  :where(html:not(.kf-live)) .film__eyebrow { margin-bottom: 0.875rem; }
  :where(html:not(.kf-live)) .film__title--hero { font-size: min(2.25rem, 10.5vw); }
  :where(html:not(.kf-live)) .film__sub { margin-top: 0.875rem; font-size: 1.0625rem; }
  :where(html:not(.kf-live)) .film__meta { margin-top: 0.875rem; }
  :where(html:not(.kf-live)) .film__actions { margin-top: 1.125rem; }
}
@media (max-width: 899.98px) and (max-height: 620px) {
  :where(html:not(.kf-live)) .film { --film-copy-bottom: calc(3.5rem + env(safe-area-inset-bottom)); }
  :where(html:not(.kf-live)) .film__chapter--hero .film__eyebrow { display: none; }
  :where(html:not(.kf-live)) .film__title { font-size: 1.75rem; }
  :where(html:not(.kf-live)) .film__title--hero { font-size: 2rem; }
  :where(html:not(.kf-live)) .film__sub { font-size: 1rem; line-height: 1.5; }
}
/* Landscape phones: the eyebrow gives way so the headline and the buttons still fit. */
@media (max-height: 480px) {
  :where(html:not(.kf-live)) .film__chapter--hero .film__eyebrow { display: none; }
  :where(html:not(.kf-live)) .film__title, :where(html:not(.kf-live)) .film__title--hero { font-size: 1.625rem; }
  :where(html:not(.kf-live)) .film__sub { margin-top: 0.5rem; font-size: 0.9375rem; }
  :where(html:not(.kf-live)) .film__meta { margin-top: 0.5rem; }
  :where(html:not(.kf-live)) .film__actions { margin-top: 0.625rem; }
}

/* ---------- Round 5 §B: on a phone the landing is an endless film ----------
   html.kf-reel (set in <head>: portrait screens under 900px, and touch screens under 540px tall) never loads the
   scroll film. One screen: the stage holds the reel's poster (the LCP, preloaded) and, once it plays, the looping
   reel (main.js startReel) fading in over it, with the hero's words and buttons on it. The scroll film's other
   places, its rail and "Skip film" step aside: the rooms right below carry every room and its price. Heights in
   svh, so the screen never resizes under the visitor as Safari's toolbar comes and goes. */
:where(html:not(.kf-live)) .film__reel { display: none; }
html:where(:not(.kf-live)).kf-reel .film { min-height: 100vh; min-height: 100svh; }
html:where(:not(.kf-live)).kf-reel .film__stage {
  position: absolute;
  inset: 0;
  height: auto;
  background-image: url("assets/video/reel-v-poster.webp");
  background-position: 50% 50%;
}
html:where(:not(.kf-live)).kf-reel .film__canvas,
html:where(:not(.kf-live)).kf-reel .film__rail,
html:where(:not(.kf-live)).kf-reel .film__skip,
html:where(:not(.kf-live)).kf-reel .film__chapter--beat { display: none; }
html:where(:not(.kf-live)).kf-reel .film__reel {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  opacity: 0;
  transition: opacity 1.2s var(--ease-out);
  pointer-events: none;
}
html:where(:not(.kf-live)).kf-reel .film__stage.is-reel-on .film__reel { opacity: 1; }
/* The reel passes through bright rooms: a deeper veil under the words than the night film needed. */
html:where(:not(.kf-live)).kf-reel .film__stage::after {
  background:
    linear-gradient(to bottom, rgba(10, 10, 10, 0.7) 0%, rgba(10, 10, 10, 0.4) 13%, rgba(10, 10, 10, 0.1) 24%, rgba(10, 10, 10, 0) 32%), /* the header's words stay legible when the moon passes behind them */
    linear-gradient(to top, rgba(10, 10, 10, 0.92) 0%, rgba(10, 10, 10, 0.72) 30%, rgba(10, 10, 10, 0.3) 52%, rgba(10, 10, 10, 0) 68%);
}
html:where(:not(.kf-live)).kf-reel .film__stage + .film__chapter { margin-top: 0; }
html:where(:not(.kf-live)).kf-reel .film__chapter--hero { min-height: 100vh; min-height: 100svh; }
/* A little more air under the words: nothing else competes for this screen now. */
html:where(:not(.kf-live)).kf-reel .film { --film-copy-bottom: calc(3rem + env(safe-area-inset-bottom)); }
html:where(:not(.kf-live)).kf-reel .film__label { bottom: calc(1.1rem + env(safe-area-inset-bottom)); }

/* JS-enhanced: while film.js runs (.film--running), only the words of the place the camera is at show
   (.is-shown). The others rest hidden — waiting below if still to come, drifting up once the camera has
   moved on — and ease in, line by line, when the camera arrives. Without JS, or if the film fails to
   start, every chapter's copy stays visible. */
:where(html:not(.kf-live)) .film__copy > * {
  transition: opacity 1.25s var(--ease-out), transform 1.5s var(--ease-out), filter 1.25s var(--ease-out);
}
:where(html:not(.kf-live)) .film__copy > :nth-child(2) { transition-delay: 0.08s; }
:where(html:not(.kf-live)) .film__copy > :nth-child(3) { transition-delay: 0.16s; }
:where(html:not(.kf-live)) .film__copy > :nth-child(4) { transition-delay: 0.24s; }
:where(html:not(.kf-live)) .film__copy > :nth-child(5) { transition-delay: 0.32s; }
:where(html:not(.kf-live)) .film.film--running .film__chapter:not(.is-shown) .film__copy { pointer-events: none; }
:where(html:not(.kf-live)) .film.film--running .film__chapter:not(.is-shown) .film__copy > * {
  opacity: 0;
  filter: blur(6px);
  transform: translate(0, 1.5rem); /* 2D at rest: a 3D transform would make every waiting line its own GPU layer */
  transition-duration: 0.7s;
  transition-delay: 0s;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
:where(html:not(.kf-live)) .film.film--running .film__chapter.is-past .film__copy > *,
:where(html:not(.kf-live)) .film.film--running .film__chapter.is-after .film__copy > * { transform: translate(0, -1.25rem); }
/* Soft parallax: the words drift up a little as the camera passes — film.js sets the active chapter's
   .film__copy transform directly (translate3d(0, (0.5 − progress) × 2.25rem, 0); none under reduced motion).
   Speed pass 26.09: it used to be a custom property here, which re-styled the whole film every frame. */
/* A keyboard user tabbing into a resting chapter's links still sees them. Only keyboard focus (:focus-visible):
   Back home from a menu page focuses the hero's heading for screen readers, and that must not bring the hero's
   words back over a later place in the film (integrator walk 27.09). */
:where(html:not(.kf-live)) .film.film--running .film__chapter:not(.is-shown) .film__copy:has(:focus-visible) > * { opacity: 1; transform: none; filter: none; }

/* ---------- THE PLAIN FILM (phones & tablets · html.kf-live) ---------- */
/* ---------- 2 · The film (13.10.2026: a plain, self-starting film; the words follow ITS clock, never the scroll) ----------
   The stage holds the looping <video autoplay muted playsinline> (its source is set at parse time by the script right after it
   in index.html; js/film-live.js is the safety net) over its first frame, which is the LCP and is also the stage's own
   background. The video is never hidden waiting for an event: with no frame yet, the picture under it shows; once there is
   one, it is the film.
   The words: the hero's lines, then five scenes (.film__place), each with a window in seconds of the film (data-cap);
   film-live.js reads video.currentTime and sets data-state wait | on | out, and the CSS below fades and slides them.
   Nothing is pinned: the page scrolls normally. The stage is as tall as the first screen and goes with the film.
   Heights in svh, so the screen never resizes under the visitor as Safari's toolbar comes and goes.
   Without JS, or under reduced motion, there is one screen: the first frame and the hero's words. */

:where(html.kf-live) .film {
  --film-copy-bottom: calc(3rem + env(safe-area-inset-bottom));
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  background: var(--ink);
}
@media (min-width: 900px) {
  :where(html.kf-live) .film { --film-copy-bottom: calc(4.25rem + env(safe-area-inset-bottom)); }
}

:where(html.kf-live) .film__stage {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background-color: var(--ink);
  /* The film's first frame (the LCP, preloaded in <head>): the video plays over the same picture. */
  background-image: url("assets/video/film-poster.webp");
  background-position: 50% 50%;
  background-size: cover;
  background-repeat: no-repeat;
}
@media (max-aspect-ratio: 9/10) {
  :where(html.kf-live) .film__stage { background-image: url("assets/video/film-poster-v.webp"); }
}
:where(html.kf-live) .film__reel {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  pointer-events: none;
}

/* Legibility scrims (functional, not decorative): header at the top, words at the foot. The film passes through
   bright rooms, so the foot is deeper than the night alone needed. */
:where(html.kf-live) .film__stage::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(10, 10, 10, 0.7) 0%, rgba(10, 10, 10, 0.4) 13%, rgba(10, 10, 10, 0.1) 24%, rgba(10, 10, 10, 0) 32%),
    linear-gradient(to top, rgba(10, 10, 10, 0.92) 0%, rgba(10, 10, 10, 0.72) 30%, rgba(10, 10, 10, 0.3) 52%, rgba(10, 10, 10, 0) 68%);
}
@media (min-width: 900px) and (min-aspect-ratio: 9/10) {
  :where(html.kf-live) .film__stage::after {
    background:
      linear-gradient(to bottom, rgba(10, 10, 10, 0.58) 0%, rgba(10, 10, 10, 0) 22%),
      linear-gradient(to top, rgba(10, 10, 10, 0.84) 0%, rgba(10, 10, 10, 0.5) 24%, rgba(10, 10, 10, 0) 52%),
      linear-gradient(to right, rgba(10, 10, 10, 0.5) 0%, rgba(10, 10, 10, 0) 58%);
  }
}

/* The honest minimum on AI imagery (UK CAP / DMCC), done the way property developers do it: a tiny,
   low-contrast CGI in the corner of the stage, always on screen with the film; the footer explains it. */
:where(html.kf-live) .film__label {
  position: absolute;
  right: max(var(--gutter), env(safe-area-inset-right));
  bottom: calc(1.1rem + env(safe-area-inset-bottom));
  z-index: 3;
  margin: 0;
  color: rgba(244, 241, 234, 0.56);
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.24em;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.7);
  pointer-events: none;
}
@media (min-width: 900px) {
  :where(html.kf-live) .film__label { bottom: 1.75rem; }
}

/* Pause: a film that moves on its own for more than five seconds can be stopped (WCAG 2.2.2). */
:where(html.kf-live) .film__toggle {
  position: absolute;
  z-index: 3;
  right: calc(max(var(--gutter), env(safe-area-inset-right)) + 2.25rem);
  bottom: calc(0.2rem + env(safe-area-inset-bottom));
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: rgba(244, 241, 234, 0.62);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
@media (min-width: 900px) {
  :where(html.kf-live) .film__toggle { bottom: 1.1rem; }
}
:where(html.kf-live) .film__toggle[hidden] { display: none; }
:where(html.kf-live) .film__toggle::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 0.5rem;
  height: 0.7rem;
  translate: -50% -50%;
  border-left: 2px solid currentColor;
  border-right: 2px solid currentColor;
}
:where(html.kf-live) .film__toggle[aria-pressed="true"]::before {
  width: 0;
  height: 0;
  translate: -35% -50%;
  border: 0 solid transparent;
  border-width: 0.36rem 0 0.36rem 0.62rem;
  border-left-color: currentColor;
}
:where(html.kf-live) .film__toggle:focus-visible { outline: 1px solid var(--champagne); outline-offset: -4px; color: var(--paper); }
@media (hover: hover) {
  :where(html.kf-live) .film__toggle:hover { color: var(--paper); }
}

/* The film's own clock: one champagne hairline along the foot of the stage. */
:where(html.kf-live) .film__progress {
  position: absolute;
  z-index: 3;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: rgba(244, 241, 234, 0.1);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.9s var(--ease-out);
}
:where(html.kf-live) .film__stage.is-reel-on .film__progress { opacity: 1; }
:where(html.kf-live) .film__fill {
  display: block;
  height: 100%;
  background: var(--champagne);
  opacity: 0.75;
  transform: scaleX(0);
  transform-origin: 0 50%;
}
html:where(.kf-live):not(.js) .film__progress,
html:where(.kf-live):not(.js) .film__toggle { display: none; }
@media (prefers-reduced-motion: reduce) {
  :where(html.kf-live) .film__progress,
  :where(html.kf-live) .film__toggle { display: none; }
}

/* The hero, as one screen: the words at the foot, left. */
:where(html.kf-live) .film__chapter {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  min-height: 100vh;
  min-height: 100svh;
  padding: 0 max(var(--gutter), env(safe-area-inset-right)) var(--film-copy-bottom) max(var(--gutter), env(safe-area-inset-left));
  pointer-events: none;
}
:where(html.kf-live) .film__copy {
  position: relative;
  width: 100%;
  max-width: 50rem;
  padding-bottom: 0.25rem;
  pointer-events: auto;
  text-shadow: 0 1px 28px rgba(0, 0, 0, 0.45);
}

/* The hero's lines and the places' words share one cell, so nothing moves when one gives way to the other. */
:where(html.kf-live) .film__stack { display: grid; }
:where(html.kf-live) .film__stack > * { grid-area: 1 / 1; align-self: end; min-width: 0; }
:where(html.kf-live) .film__tour { display: grid; }
:where(html.kf-live) .film__tour > .film__place { grid-area: 1 / 1; align-self: end; }
/* The scenes wait invisible; film-live.js sets data-state="on" on the one whose window the film is in (its clock, not the
   scroll), "out" once it is past. Under reduced motion they are never shown: the hero's lines stay. */
:where(html.kf-live) .film__place {
  opacity: 0;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  :where(html.kf-live) .film__place { display: none; }
}

:where(html.kf-live) .film__eyebrow { margin-bottom: 1.25rem; }

:where(html.kf-live) .film__title {
  color: var(--text-strong);
  font-size: clamp(2rem, 1.35rem + 2.9vw, 4rem);
  font-weight: 200;
  line-height: 1.06;
  letter-spacing: -0.02em;
}
:where(html.kf-live) .film__title--hero {
  font-size: var(--fs-display);
  font-size: min(var(--fs-display), 10.5svh);
  line-height: 1.02;
  letter-spacing: -0.025em;
}
:where(html.kf-live) .film__place-title {
  margin: 0;
  color: var(--text-strong);
  font-size: clamp(1.625rem, 1.1rem + 2.2vw, 3rem);
  font-weight: 200;
  line-height: 1.08;
  letter-spacing: -0.02em;
}
/* The slogan lockup (ROUND3 §1, §11): the H1, then "Crafted for life." small, in champagne, hung from a
   hairline — a signature under the line, not a second headline. */
:where(html.kf-live) .hero__line { display: block; }
:where(html.kf-live) .hero__sig {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  margin-top: 0.9rem;
  color: var(--champagne);
  font-size: clamp(1.0625rem, 0.92rem + 0.75vw, 1.75rem);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: 0.04em;
}
:where(html.kf-live) .hero__sig::before {
  content: "";
  flex: none;
  width: clamp(1.75rem, 3vw, 3rem);
  height: 1px;
  background: currentColor;
  opacity: 0.8;
}
:where(html.kf-live) .film__copy--hero .film__meta { margin-top: 1.5rem; }

:where(html.kf-live) .film__sub {
  max-width: 34rem;
  margin-top: 1.25rem;
  color: rgba(244, 241, 234, 0.86);
  font-size: var(--fs-lead);
  font-weight: 300;
  line-height: 1.55;
}
:where(html.kf-live) .film__meta { margin-top: 1.25rem; font-size: 1.25rem; }
/* Honesty line (pool / pond): small, in the moonlight tone, never hidden. */
:where(html.kf-live) .film__note {
  max-width: 30rem;
  margin-top: 0.75rem;
  color: var(--moon);
  font-size: 0.75rem;
  line-height: 1.45;
  letter-spacing: 0.02em;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7), 0 1px 18px rgba(0, 0, 0, 0.6);
}
:where(html.kf-live) .film__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 2rem;
  margin-top: 1.75rem;
}

/* Phones: the small words sit on lit glass and roofs — a tight shadow under the soft one keeps the
   eyebrow and the lines readable without darkening the picture. */
@media (max-width: 899.98px) {
  :where(html.kf-live) .film__copy .eyebrow,
  :where(html.kf-live) .film__sub,
  :where(html.kf-live) .film__meta { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.65), 0 1px 24px rgba(0, 0, 0, 0.6); }
}
@media (max-width: 599.98px) {
  :where(html.kf-live) .film__eyebrow { margin-bottom: 0.875rem; }
  :where(html.kf-live) .film__sub { margin-top: 0.875rem; }
  :where(html.kf-live) .film__meta { margin-top: 0.875rem; font-size: 1.125rem; }
  /* Larger words for the thumb: the chapters read at the size of the hero's own line. */
  :where(html.kf-live) .film__place-title { font-size: clamp(2rem, 8.6vw, 2.5rem); line-height: 1.08; }
}
@media (max-width: 899.98px) and (max-height: 700px) {
  :where(html.kf-live) .film__chapter--hero .film__intro .film__eyebrow { display: none; }
  :where(html.kf-live) .film__place .film__sub { display: none; }
}
@media (max-width: 899.98px) and (max-height: 760px) {
  :where(html.kf-live) .film__eyebrow { margin-bottom: 0.875rem; }
  :where(html.kf-live) .film__title--hero { font-size: min(2.25rem, 10.5vw); }
  :where(html.kf-live) .film__sub { margin-top: 0.875rem; font-size: 1.0625rem; }
  :where(html.kf-live) .film__meta { margin-top: 0.875rem; }
  :where(html.kf-live) .film__actions { margin-top: 1.125rem; }
}
@media (max-width: 899.98px) and (max-height: 620px) {
  :where(html.kf-live) .film { --film-copy-bottom: calc(3.5rem + env(safe-area-inset-bottom)); }
  :where(html.kf-live) .film__title { font-size: 1.75rem; }
  :where(html.kf-live) .film__title--hero { font-size: 2rem; }
  :where(html.kf-live) .film__place-title { font-size: 1.5rem; }
  :where(html.kf-live) .film__sub { font-size: 1rem; line-height: 1.5; }
}
/* Landscape phones: the eyebrow gives way so the headline and the buttons still fit. */
@media (max-height: 480px) {
  :where(html.kf-live) .film__chapter--hero .film__intro .film__eyebrow { display: none; }
  :where(html.kf-live) .film__title, :where(html.kf-live) .film__title--hero { font-size: 1.625rem; }
  :where(html.kf-live) .film__place-title { font-size: 1.375rem; }
  :where(html.kf-live) .film__sub { margin-top: 0.5rem; font-size: 0.9375rem; }
  :where(html.kf-live) .film__meta { margin-top: 0.5rem; }
  :where(html.kf-live) .film__actions { margin-top: 0.625rem; }
}

/* ---------- The words follow the film (13.10.2026, third pass) ----------
   Each scene rises into place as the film reaches it and lifts away as it leaves; the hero's lines do the same at the
   start of every loop. Opacity and transform only. The buttons and the note under them never move. A darker foot comes
   in while a scene is on, so the words stay readable on the film's bright rooms (the base scrims above are tuned for the
   hero alone). Under reduced motion, and without JS, none of this applies: one screen, the hero's words. */
:where(html.kf-live) .film__shade {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  background:
    linear-gradient(to top, rgba(10, 10, 10, 0.5) 0%, rgba(10, 10, 10, 0.3) 40%, rgba(10, 10, 10, 0.07) 76%, rgba(10, 10, 10, 0.05) 100%);
  transition: opacity 0.9s var(--ease-out);
}
:where(html.kf-live) .film[data-now="scene"] .film__shade { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  html:where(.kf-live).js .film__place,
  html:where(.kf-live).js .film.is-timed .film__intro {
    transition: opacity 0.8s var(--ease-out), transform 1.1s var(--ease-out);
  }
  html:where(.kf-live).js .film__place {
    transform: translate3d(0, 18px, 0);
    will-change: opacity, transform;
  }
  html:where(.kf-live).js .film__place[data-state="on"] { opacity: 1; transform: none; }
  html:where(.kf-live).js .film__place[data-state="out"] { transform: translate3d(0, -14px, 0); }
  html:where(.kf-live).js .film.is-timed .film__intro { will-change: opacity, transform; }
  html:where(.kf-live).js .film.is-timed .film__intro:not([data-state="on"]) { opacity: 0; transform: translate3d(0, -14px, 0); }
  html:where(.kf-live).js .film__fill { will-change: transform; }
}
@media (prefers-reduced-motion: reduce) {
  :where(html.kf-live) .film__shade { display: none; }
}

/* ---------- Home: after the film ----------
   Four compact blocks in the first version's language (hairline heads, champagne prices), then the FAQ
   and the footer: rooms & prices, the 3D designer, real photographs, contact. */

.home-block { padding-block: clamp(3rem, 5.5vw, 5.5rem); }
.home-block + .home-block { padding-top: 0; }
/* A tighter section head: the hairline, the eyebrow, the title and one line beside it. */
.head--tight { margin-bottom: clamp(1.5rem, 3vw, 2.75rem); }

/* Phones: a strip that runs to the screen's edges and snaps card by card. (Shared by the rooms and
   the real photographs; desktop turns each into one row.) */
.rooms,
.strip {
  display: grid;
  grid-auto-flow: column;
  gap: 0.75rem;
  margin-inline: calc(-1 * max(var(--gutter), env(safe-area-inset-left))) calc(-1 * max(var(--gutter), env(safe-area-inset-right)));
  scroll-padding-inline: max(var(--gutter), env(safe-area-inset-left));
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  position: relative; /* contains anything absolutely placed inside, so it can't widen the page */
}
/* The list reset (ul[role="list"]) outranks a bare class: the strips' own gutter is set here, so the
   first card starts on the page's margin rather than at the glass edge. */
.rooms[role="list"],
.strip[role="list"] { padding-inline: max(var(--gutter), env(safe-area-inset-left)) max(var(--gutter), env(safe-area-inset-right)); }
.rooms::-webkit-scrollbar,
.strip::-webkit-scrollbar { display: none; }
.rooms { grid-auto-columns: min(72vw, 17rem); }
.strip { grid-auto-columns: min(62vw, 15rem); }

/* 1 · Rooms & prices: small picture, name, price on the hairline, one line. */
.room { min-width: 0; scroll-snap-align: start; }
.room__link { display: flex; flex-direction: column; height: 100%; }
.room__link:focus-visible { outline-offset: 4px; }
.room__media {
  position: relative;
  display: block;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--ink-2);
}
.room__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.6s var(--ease-out);
}
.room__media .tag { font-size: 0.6875rem; }
.room--spa .room__media img { object-position: 42% 62%; }
.room--sauna .room__media img { object-position: 50% 45%; }
.room--gym .room__media img { object-position: 55% 55%; }
.room--golf .room__media img { object-position: 64% 50%; }
.room--annexe .room__media img { object-position: 54% 56%; }
.room__name {
  margin-top: 1rem;
  color: var(--text-strong);
  font-size: 1.1875rem;
  font-weight: 300;
  line-height: 1.25;
  letter-spacing: -0.005em;
}
.room .price {
  margin-top: 0.375rem;
  padding-bottom: 0.625rem;
  border-bottom: 1px solid var(--rule);
  font-size: 1.0625rem;
}
.room .price__from,
.room .price__vat { font-size: 0.75rem; }
.room__line { margin-top: 0.625rem; color: var(--text-dim); font-size: 0.9375rem; line-height: 1.45; }
@media (hover: hover) {
  .room__link:hover .room__media img { transform: scale(1.04); }
  .room__link:hover .room__name { color: var(--champagne); }
}

@media (min-width: 1024px) {
  .rooms[role="list"] {
    grid-auto-flow: row;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: var(--col-gap);
    margin-inline: 0;
    padding-inline: 0;
    overflow: visible;
  }
  .room__name { font-size: 1.125rem; }
}

/* 2 · Design yours in 3D: the configurator (css/configurator.css) fills the mount. */

/* 3 · Built by KF Crafts: one row of six, each leaning toward a mouse pointer as if held up to the
   light (main.js sets --tilt-x / --tilt-y). */
.strip__item { min-width: 0; scroll-snap-align: start; perspective: 900px; }
.strip__open {
  display: block;
  width: 100%;
  text-align: left;
  cursor: zoom-in;
  transform: rotateX(calc(var(--tilt-y, 0) * -5deg)) rotateY(calc(var(--tilt-x, 0) * 6deg));
  transition: transform 0.9s var(--ease-out);
}
.strip__open:focus-visible { outline-offset: 4px; }
.strip__frame {
  position: relative;
  display: block;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--ink-2);
}
.strip__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: translate(calc(var(--tilt-x, 0) * -6px), calc(var(--tilt-y, 0) * -6px)) scale(1.06);
  transition: transform 0.9s var(--ease-out);
}
/* The light it catches: a soft sheen that follows the pointer. */
.strip__frame::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(60% 50% at calc(50% + var(--tilt-x, 0) * 40%) calc(50% + var(--tilt-y, 0) * 40%), rgba(255, 226, 170, 0.14), transparent 70%);
  opacity: 0;
  transition: opacity 0.6s var(--ease-out);
  pointer-events: none;
}
.strip__frame .tag { font-size: 0.6875rem; letter-spacing: 0.1em; }
.strip__cap {
  display: block;
  margin-top: 0.625rem;
  color: var(--text-dim);
  font-size: 0.8125rem;
  line-height: 1.4;
  letter-spacing: 0.02em;
}
@media (hover: hover) and (pointer: fine) {
  .strip__open:hover { transition-duration: 0.25s; }
  .strip__open:hover .strip__frame img { transition-duration: 0.25s; }
  .strip__open:hover .strip__frame::after { opacity: 1; }
}
.built__all { margin-top: 1rem; }

@media (min-width: 1024px) {
  .strip[role="list"] {
    grid-auto-flow: row;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: var(--col-gap);
    margin-inline: 0;
    padding-inline: 0;
    overflow: visible;
  }
  .strip__item:nth-child(even) { margin-top: clamp(1.25rem, 2.5vw, 2.5rem); }
}

.footer__label {
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.contact__alt { display: flex; flex-wrap: wrap; column-gap: 1.5rem; font-size: 0.8125rem; line-height: 1.6; }
.contact__alt a { display: inline-flex; align-items: center; min-height: 44px; color: var(--text-dim); text-decoration: underline; text-decoration-color: var(--rule); text-underline-offset: 3px; }
/* Links inside running text: a taller tap target on touch screens. Vertical padding on an inline box
   grows what a finger can hit without moving a single line. */
@media (pointer: coarse) {
  .footer__base a,
  :where(p, dd, li) > a:not([class]) { padding-block: 11px; }
}

/* ---------- View · the annexe ---------- */

/* A little of the film's warm door-light at the top of the view. Behind the content (isolated
   stacking), never over it. */
.annexe { isolation: isolate; }
.annexe::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  z-index: -1;
  height: min(90vh, 48rem);
  background: radial-gradient(70% 45% at 50% 0, rgba(227, 206, 146, 0.12), transparent 70%);
  pointer-events: none;
}

.annexe__views {
  display: grid;
  gap: 1.5rem var(--col-gap);
  margin-bottom: clamp(3rem, 6vw, 5rem);
}
.annexe__frame { position: relative; aspect-ratio: 1280 / 714; overflow: hidden; background: var(--ink-2); }
.annexe__frame img { width: 100%; height: 100%; object-fit: cover; }
.annexe__view .caption { margin-top: 0.625rem; }
@media (min-width: 768px) {
  .annexe__views { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.annexe__layout {
  display: grid;
  gap: clamp(3.5rem, 7vw, 6rem) var(--col-gap);
}
@media (min-width: 1024px) {
  .annexe__layout { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: start; }
  .annexe__plan { grid-column: 1 / 7; position: sticky; top: calc(var(--header-h) + 3rem); }
  .annexe__detail { grid-column: 8 / 13; }
}

.annexe__plan {
  --plan-bg: var(--ink-2);
  padding: clamp(1rem, 3vw, 2.5rem);
  background: var(--plan-bg);
  border: 1px solid var(--rule);
}
.annexe__plan-cap {
  display: grid;
  justify-items: start;
  gap: 0.25rem;
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
  color: var(--text-dim);
  font-size: 0.875rem;
}

/* The plan draws itself in from the left when it arrives (main.js adds .draw, then .is-drawn). */
.draw .plan { clip-path: inset(0 100% 0 0); }
.draw.is-drawn .plan { clip-path: inset(0 0 0 0); transition: clip-path 1.6s var(--ease-in-out) 0.2s; }

.plan { width: 100%; height: auto; overflow: visible; }
.plan__wall {
  fill: rgba(216, 199, 156, 0.14);
  stroke: var(--champagne);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.plan__cut { fill: var(--plan-bg); }
.plan__glass {
  fill: none;
  stroke: var(--gold-hi);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.plan__furn {
  fill: none;
  stroke: rgba(244, 241, 234, 0.4);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.plan__swing {
  fill: none;
  stroke: rgba(244, 241, 234, 0.3);
  stroke-width: 1;
  stroke-dasharray: 3 3;
  vector-effect: non-scaling-stroke;
}
.plan__dim {
  fill: none;
  stroke: rgba(216, 199, 156, 0.6);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
/* SVG text scales with the drawing, so sizes are set per breakpoint in user units. */
.plan__label {
  fill: rgba(244, 241, 234, 0.8);
  font-family: var(--sans);
  font-size: 17px;
  font-weight: 500;
  letter-spacing: 0.1em;
}
.plan__dimtext {
  fill: var(--champagne);
  font-family: var(--sans);
  font-size: 18px;
  font-weight: 400;
  letter-spacing: 0.04em;
}
@media (min-width: 640px) {
  .plan__label { font-size: 12px; letter-spacing: 0.16em; }
  .plan__dimtext { font-size: 13px; }
}

.annexe__detail .kicker { margin-bottom: 1.25rem; }
.annexe__detail .kicker ~ .kicker { margin-top: 3.5rem; }

.uses { display: grid; }
.use {
  display: grid;
  gap: 0.375rem;
  padding-block: 1.25rem;
  border-top: 1px solid var(--rule);
}
.use:last-child { border-bottom: 1px solid var(--rule); }
.use__title {
  color: var(--text-strong);
  font-size: 1.1875rem;
  font-weight: 300;
  line-height: 1.35;
}

.inside {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem var(--col-gap);
}
.inside__item {
  padding-top: 0.875rem;
  border-top: 1px solid var(--line);
}
.inside dt {
  color: var(--text-strong);
  font-size: 1.0625rem;
  font-weight: 400;
}
.inside dd {
  margin-top: 0.25rem;
  color: var(--text-dim);
  font-size: 0.875rem;
  line-height: 1.5;
}

.fact {
  margin-top: 3.5rem;
  padding: 0.25rem 0 0.25rem 1.5rem;
  border-left: 1px solid var(--champagne);
}
.fact__title {
  margin-bottom: 0.5rem;
  color: var(--champagne);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.fact p:not(.fact__title) { color: var(--text); font-size: 1.0625rem; font-weight: 300; line-height: 1.6; }

.annexe__price { margin-top: 3.5rem; padding-top: 2rem; border-top: 1px solid var(--line); }
.annexe__price-note { margin-top: 0.75rem; color: var(--text-dim); font-size: 0.9375rem; }
.annexe__incl { margin-top: 0.75rem; max-width: 34rem; color: var(--text-dim); font-size: 0.875rem; }
.annexe__incl a {
  color: var(--text-strong);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
  transition: text-decoration-color 0.3s;
}
@media (hover: hover) {
  .annexe__incl a:hover { text-decoration-color: var(--champagne); }
}
.annexe__price .actions { margin-top: 2rem; }

/* ---------- View · how it's built: layers, then process, then promises ----------
   The exploded view (#layers) is styled entirely by css/layers.css (its plain list is also the
   no-JS / no-WebGL state). */

/* Promises */

.promises { background: var(--ink); }
.promises__layout { display: grid; gap: 3rem var(--col-gap); }
.promises__head {
  display: grid;
  gap: 1.25rem;
  align-content: start;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.promises__intro { max-width: 24rem; color: var(--text); }

.promises__list { display: grid; column-gap: clamp(1.5rem, 3vw, 3rem); }
.promise {
  display: grid;
  align-content: start;
  gap: 0.5rem;
  padding: 1.5rem 0 2.25rem;
  border-top: 1px solid var(--rule);
}
.promise p { color: var(--text-dim); }
.promise__title {
  color: var(--text-strong);
  font-size: 1.1875rem;
  font-weight: 400;
  line-height: 1.35;
  letter-spacing: 0;
}
.promise--lead { border-top-color: var(--line-strong); padding-bottom: 2.75rem; }
.promise--lead .promise__title {
  font-size: clamp(1.75rem, 1.35rem + 1.6vw, 2.625rem);
  font-weight: 200;
  line-height: 1.12;
  letter-spacing: -0.015em;
}
.promise--lead p { max-width: 34rem; color: var(--text); font-size: var(--fs-lead); font-weight: 300; }
.promise__cta { justify-self: start; margin-top: 0.75rem; }

@media (min-width: 640px) {
  .promises__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .promise--lead { grid-column: 1 / -1; }
}
@media (min-width: 1024px) {
  .promises__layout { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: start; }
  .promises__head { grid-column: 1 / 5; position: sticky; top: calc(var(--header-h) + 3rem); }
  .promises__list { grid-column: 6 / 13; }
  .promise--lead { padding-top: 1.5rem; border-top: 1px solid var(--line-strong); }
}

/* How it works */

.process__top {
  display: grid;
  gap: 3rem var(--col-gap);
  margin-bottom: clamp(4rem, 8vw, 7rem);
}
.process__head {
  display: grid;
  gap: 1.25rem;
  align-content: start;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.process__head .lead { max-width: 32rem; }
.process__photo { max-width: 26rem; }
.process__frame { position: relative; aspect-ratio: 4 / 5; overflow: hidden; background: var(--ink-2); }
.process__frame img { width: 100%; height: 100%; object-fit: cover; }
@media (min-width: 1024px) {
  .process__top { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: end; }
  .process__head { grid-column: 1 / 7; align-self: start; }
  .process__photo { grid-column: 9 / 13; max-width: none; }
}

.steps { display: grid; }
.step {
  position: relative;
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr);
  column-gap: 1rem;
  padding-bottom: 2.5rem;
}
/* Mobile: a vertical hairline threads the numbers together. */
.step::before {
  content: "";
  position: absolute;
  left: 0.9rem;
  top: 3.4rem;
  bottom: 0.75rem;
  width: 1px;
  background: var(--line);
}
.step:last-child { padding-bottom: 0; }
.step:last-child::before { display: none; }
.step__num {
  grid-row: 1 / span 3;
  color: var(--champagne);
  font-size: 2.5rem;
  font-weight: 200;
  line-height: 1;
  font-variant-numeric: lining-nums;
}
.step__title {
  grid-column: 2;
  color: var(--text-strong);
  font-size: 1.3125rem;
  font-weight: 300;
  line-height: 1.3;
}
.step__when {
  grid-column: 2;
  margin-top: 0.375rem;
  color: var(--champagne);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.step__text { grid-column: 2; margin-top: 0.75rem; color: var(--text-dim); font-size: 0.9375rem; }

@media (min-width: 1024px) {
  .steps {
    position: relative;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    column-gap: var(--col-gap);
  }
  /* The path-lights line: one champagne hairline joining the five steps, drawn left to right on arrival. */
  .steps::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 1px;
    background: var(--line-strong);
    transform-origin: left center;
  }
  .draw.steps::after { transform: scaleX(0); }
  .draw.steps.is-drawn::after { transform: none; transition: transform 1.2s var(--ease-in-out); }
  .step { display: block; padding: 2.25rem 0 0; }
  /* Desktop: each step hangs from the line on a short champagne tick. */
  .step::before {
    left: 0;
    top: -7px;
    bottom: auto;
    width: 1px;
    height: 13px;
    background: var(--champagne);
  }
  .step:last-child::before { display: block; }
  .step__num { display: block; font-size: clamp(3.75rem, 1.5rem + 3.4vw, 6.5rem); margin-bottom: 1.25rem; }
  .step__text { max-width: 17rem; }
}

/* ---------- View · our projects ----------
   Rows of equal height, each photograph in its own shape and in reading order: an item grows in
   proportion to its aspect ratio (--ar, on the item), so every row fills the width; the last row's
   filler keeps it from stretching. Filters (main.js) hide what isn't asked for. */

/* Phones: one row that scrolls sideways, edge to edge; from 640px it wraps. */
.filters {
  display: flex;
  gap: 0.5rem;
  margin: -0.5rem calc(-1 * max(var(--gutter), env(safe-area-inset-right))) clamp(1.5rem, 3vw, 2.25rem) calc(-1 * max(var(--gutter), env(safe-area-inset-left)));
  padding-inline: max(var(--gutter), env(safe-area-inset-left)) max(var(--gutter), env(safe-area-inset-right));
  overflow-x: auto;
  scrollbar-width: none;
}
.filters::-webkit-scrollbar { display: none; }
@media (min-width: 640px) {
  .filters { flex-wrap: wrap; margin-inline: 0; padding-inline: 0; overflow: visible; }
}
.filters[hidden] { display: none; }
.filter {
  flex: none;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 1rem;
  border: 1px solid var(--rule);
  color: var(--text-dim);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transition: color 0.3s, border-color 0.3s, background-color 0.3s;
}
.filter[aria-pressed="true"] { border-color: var(--line-strong); color: var(--champagne); background: rgba(216, 199, 156, 0.06); }
@media (hover: hover) {
  .filter:hover { color: var(--text-strong); border-color: var(--line); }
}

.gallery {
  --row: clamp(8.5rem, 26vw, 10.5rem);
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem var(--col-gap);
}
.gallery::after { content: ""; flex: 999 1 0; }
.gallery__item {
  flex: var(--ar) 1 calc(var(--ar) * var(--row));
  min-width: 0;
}
.gallery__item[hidden] { display: none; }
.shot__open {
  position: relative;
  display: block;
  width: 100%;
  text-align: left;
  cursor: zoom-in;
}
.shot__open:focus-visible { outline-offset: 4px; }
.gallery__frame { display: block; aspect-ratio: var(--ar); overflow: hidden; background: var(--ink-2); }
.gallery__frame img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.4s var(--ease-out); }
@media (hover: hover) {
  .shot__open:hover .gallery__frame img { transform: scale(1.035); }
}
.gallery__item .caption { margin-top: 0.5rem; }
@media (min-width: 1024px) {
  .gallery { --row: clamp(15rem, 21vw, 21rem); row-gap: 2rem; }
}

/* Honest social proof, said quietly: a hairline, a line of small type, one link. */
.refs {
  margin-top: clamp(2rem, 4vw, 3rem);
  color: var(--text-dim);
  font-size: 0.875rem;
  letter-spacing: 0.02em;
}
.refs::before {
  content: "";
  display: inline-block;
  width: 1.25rem;
  height: 1px;
  margin-right: 0.625rem;
  vertical-align: middle;
  background: var(--champagne);
}
.refs__ask {
  display: inline-block;
  padding-block: 0.75rem; /* a 44px target inside a line of small type */
  color: var(--champagne);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
}

/* ---------- View · design yours ---------- */

.design__mount { position: relative; min-height: 34rem; }
/* Holding state until configurator.js fills the container. */
.design__mount:empty {
  display: grid;
  place-items: center;
  padding: 2rem;
  border: 1px solid var(--rule);
  background: var(--ink-2);
}
.design__mount:empty::before {
  content: "Loading the 3D designer";
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.design__mount.is-failed:empty::before {
  content: "The 3D designer could not load here. Every price on the home page includes VAT — or send us a photo of your garden.";
  max-width: 28rem;
  color: var(--text-dim);
  font-size: 0.9375rem;
  font-weight: 300;
  letter-spacing: 0;
  text-align: center;
  text-transform: none;
}
html:not(.js) .design__mount { display: none; }
.design__noscript {
  margin-top: 1.5rem;
  padding-left: 1.25rem;
  border-left: 1px solid var(--champagne);
  color: var(--text);
}


/* ---------- Home · 4 · contact: see it in your garden ----------
   Phone: the head, Hristiyan's number and WhatsApp, then the form. Desktop: all of that down the left,
   the form on the right. */

.enquire__layout { display: grid; gap: 2rem var(--col-gap); }
.enquire__intro { display: grid; gap: 1.5rem; align-content: start; }
.enquire__head {
  display: grid;
  gap: 1rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.enquire__lead { max-width: 28rem; color: var(--text); }
@media (min-width: 1024px) {
  .enquire__layout { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: start; }
  .enquire__intro { grid-column: 1 / 6; }
  .enquire__panel { grid-column: 7 / 13; }
}

.design-card {
  margin-top: 1rem;
  padding: 1.25rem 1.25rem 1.25rem 1.5rem;
  border: 1px solid var(--line);
  border-left-color: var(--champagne);
  background: var(--ink-2);
}
.design-card[hidden] { display: none; }
.design-card.is-fresh { animation: card-in 0.9s var(--ease-out); }
.design-card__title {
  color: var(--champagne);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.design-card__head { margin-top: 0.5rem; color: var(--text-strong); font-size: 1rem; }
.design-card__more summary {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--text-dim);
  font-size: 0.875rem;
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
  cursor: pointer;
  list-style: none;
}
.design-card__more summary::-webkit-details-marker { display: none; }
.design-card__more[open] summary { display: none; }
.design-card__lines { display: grid; gap: 0.25rem; margin-top: 0.5rem; color: var(--text); font-size: 0.9375rem; }
.design-card__lines .is-price { color: var(--text-strong); }
.design-card__lines .is-note { color: var(--muted); font-size: 0.8125rem; }
.design-card__note { margin-top: 0.875rem; color: var(--muted); font-size: 0.8125rem; }

@keyframes card-in {
  from { opacity: 0; transform: translate3d(0, 0.75rem, 0); }
  to { opacity: 1; transform: none; }
}

.contact { display: grid; gap: 0.125rem; }
.contact__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin: 0.5rem 0 0.75rem; }
.contact__label {
  margin-bottom: 0.5rem;
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.contact__value {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--text-strong);
  font-size: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
  font-weight: 200;
  letter-spacing: 0.01em;
  font-variant-numeric: lining-nums;
}

.enquire__panel {
  padding: clamp(1.25rem, 3vw, 2.25rem);
  background: var(--ink-2);
  border: 1px solid var(--rule);
}

.form__grid { display: grid; gap: 1.25rem var(--col-gap); }
@media (min-width: 640px) {
  .form__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .field--full, .photo { grid-column: 1 / -1; }
}
@media (min-width: 1100px) {
  .form__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.field { display: grid; gap: 0.5rem; min-width: 0; margin: 0; padding: 0; border: 0; }
.field__label {
  color: rgba(244, 241, 234, 0.86);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.field__opt {
  margin-left: 0.5rem;
  color: var(--muted);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: none;
}
.field__error { color: var(--error); font-size: 0.8125rem; line-height: 1.45; }
.field__error[hidden] { display: none; }

.input {
  width: 100%;
  min-height: 48px;
  padding: 0.75rem 0;
  border: 0;
  border-bottom: 1px solid rgba(244, 241, 234, 0.3);
  border-radius: 0;
  background: transparent;
  color: var(--paper);
  font-family: var(--sans);
  font-size: 1.0625rem; /* ≥ 16px: iOS Safari won't zoom on focus */
  font-weight: 300;
  line-height: 1.4;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color 0.3s, box-shadow 0.3s;
}
.input::placeholder { color: rgba(244, 241, 234, 0.4); }
@media (hover: hover) {
  .input:hover { border-bottom-color: rgba(244, 241, 234, 0.5); }
}
.input:focus { outline: none; }
.input:focus-visible,
.input:focus {
  border-bottom-color: var(--champagne);
  box-shadow: 0 1px 0 0 var(--champagne);
}
.input[aria-invalid="true"] { border-bottom-color: var(--error); box-shadow: 0 1px 0 0 var(--error); }
.input--area { min-height: 5.5rem; padding-top: 0.875rem; resize: vertical; line-height: 1.6; }
.input:-webkit-autofill {
  -webkit-text-fill-color: var(--paper);
  box-shadow: 0 0 0 1000px var(--ink-2) inset;
  caret-color: var(--paper);
}

/* Photo: native input kept focusable but visually replaced by the drop zone. */
.photo__input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  overflow: hidden;
}
.drop {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 1rem;
  padding: 1.125rem;
  border: 1px solid var(--line);
  cursor: pointer;
  transition: border-color 0.3s, background-color 0.3s;
}
.photo__input:focus-visible + .drop { outline: 2px solid var(--gold-hi); outline-offset: 3px; }
.drop:hover, .drop.is-over { border-color: var(--champagne); background: rgba(216, 199, 156, 0.04); }
.drop__icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--line-strong);
  color: var(--champagne);
}
.drop__text { display: grid; gap: 0.125rem; }
.drop__title { color: var(--text-strong); font-weight: 400; }
.drop__hint { color: var(--muted); font-size: 0.8125rem; line-height: 1.45; }
.drop[hidden] { display: none; }

.preview {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) auto;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem;
  border: 1px solid var(--line);
}
.preview[hidden] { display: none; }
.preview__thumb { width: 72px; height: 72px; object-fit: cover; background: var(--ink); }
.preview__meta { min-width: 0; }
.preview__name { overflow: hidden; color: var(--text-strong); font-size: 0.9375rem; text-overflow: ellipsis; white-space: nowrap; }
.preview__size { color: var(--muted); font-size: 0.8125rem; }
.preview__remove {
  min-height: 44px;
  padding-inline: 0.75rem;
  color: var(--text);
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-decoration: underline;
  text-decoration-color: rgba(244, 241, 234, 0.35);
  text-underline-offset: 4px;
}
.preview__remove:hover { color: var(--champagne); }

.consent { color: var(--text-dim); font-size: 0.8125rem; line-height: 1.55; }

.form__submit {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
  margin-top: 1.75rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
}
.form__note { color: var(--muted); font-size: 0.8125rem; }
.form[hidden] { display: none; }

.done { display: grid; gap: 1.25rem; justify-items: start; }
.done[hidden] { display: none; }
.done:not([hidden]) { animation: card-in 0.8s var(--ease-out); }
.done__mark { width: 28px; height: auto; aspect-ratio: 124 / 128; color: var(--champagne); }
.done__title {
  font-size: clamp(1.75rem, 1.35rem + 1.6vw, 2.5rem);
  font-weight: 200;
  line-height: 1.12;
  letter-spacing: -0.015em;
}
.done__text { max-width: 34rem; color: var(--text); }
.done__book { display: grid; gap: 1rem; width: 100%; margin-top: 0.5rem; }
.done__ask { color: var(--text-strong); font-size: 1.0625rem; font-weight: 300; }
.done__recap {
  display: grid;
  width: 100%;
  border-top: 1px solid var(--rule);
}
.done__recap > div {
  display: grid;
  gap: 0.125rem 1.5rem;
  padding-block: 0.875rem;
  border-bottom: 1px solid var(--rule);
}
@media (min-width: 640px) {
  .done__recap > div { grid-template-columns: 9rem minmax(0, 1fr); }
}
.done__recap dt {
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 2;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.done__recap dd { color: var(--text-strong); white-space: pre-line; }


/* ---------- FAQ (every page) ----------
   Above the footer on home and on every menu page: four labelled groups, every answer closed until asked
   for, two columns from 900px. Collapsed, it is a short block. */

.faq { padding-block: clamp(1.5rem, 3vw, 3rem) clamp(3rem, 5.5vw, 5.5rem); }
.faq__head {
  display: grid;
  gap: 0.875rem var(--col-gap);
  margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.faq__title {
  font-size: var(--fs-h3);
  font-weight: 200;
  line-height: 1.12;
  letter-spacing: -0.015em;
}
@media (min-width: 1024px) {
  .faq__head { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: end; }
  .faq__head .eyebrow { grid-column: 1 / -1; }
  .faq__title { grid-column: 1 / 8; }
}
/* Each topic is one closed row (label, "3 questions", +); open, it shows its three questions. */
.faq__groups { display: grid; }
@media (min-width: 900px) {
  .faq__groups { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(2rem, 5vw, 5rem); align-items: start; }
  .faq__group:nth-last-child(2) { border-bottom: 1px solid var(--line); }
}
.faq__group { min-width: 0; border-top: 1px solid var(--line); }
.faq__group:last-child { border-bottom: 1px solid var(--line); }
.faq__label {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 60px;
  padding-block: 1rem;
  color: var(--champagne);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  list-style: none;
  cursor: pointer;
}
.faq__label::-webkit-details-marker { display: none; }
.faq__label > span:first-child { flex: 1; }
.faq__count { color: var(--text-dim); font-size: 0.8125rem; font-weight: 400; letter-spacing: 0.02em; text-transform: none; }
.faq__group[open] > .faq__label .qa__icon::after { transform: rotate(0deg); }
@media (hover: hover) {
  .faq__label:hover .faq__count { color: var(--text); }
}
.faq__group > .qa:last-child { border-bottom: 0; }
.faq__group[open] { padding-bottom: 0.5rem; }

.qa { border-top: 1px solid var(--rule); }
.qa:last-child { border-bottom: 1px solid var(--rule); }
.qa summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 44px;
  padding-block: 1rem;
  color: var(--text-strong);
  font-size: clamp(1.0625rem, 1rem + 0.25vw, 1.1875rem);
  font-weight: 300;
  line-height: 1.35;
  list-style: none;
  cursor: pointer;
  transition: color 0.3s;
}
.qa summary::-webkit-details-marker { display: none; }
@media (hover: hover) {
  .qa summary:hover { color: var(--champagne); }
}
.qa__icon { position: relative; flex: none; width: 14px; height: 14px; }
.qa__icon::before,
.qa__icon::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 1px;
  background: var(--champagne);
  transition: transform 0.45s var(--ease-out);
}
.qa__icon::after { transform: rotate(90deg); }
.qa[open] .qa__icon::after { transform: rotate(0deg); }
.qa__a { display: grid; gap: 0.75rem; max-width: 40rem; padding-bottom: 1.25rem; color: var(--text); }
.qa__a a { color: var(--text-strong); text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; }
.qa__stages { display: grid; gap: 0.25rem; }
.qa__stages li { display: grid; grid-template-columns: 3.25rem minmax(0, 1fr); }
.qa__stages span { color: var(--champagne); font-variant-numeric: tabular-nums; }
.qa[open] .qa__a { animation: card-in 0.6s var(--ease-out); }


/* ---------- Footer (every view): compact ---------- */

.footer {
  padding-block: clamp(2rem, 4vw, 3.5rem) calc(1.5rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
}
.footer__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem var(--col-gap);
}
.footer__brand { grid-column: 1 / -1; display: flex; align-items: center; gap: 1.25rem; }
.footer__seal { flex: none; width: 112px; height: 112px; }
@media (min-width: 1024px) {
  .footer__brand { flex-direction: column; align-items: flex-start; }
  .footer__seal { width: 168px; height: 168px; }
}
.footer__words { display: grid; gap: 0.5rem; }
.footer__sign { color: var(--champagne); font-size: 1.0625rem; font-weight: 300; line-height: 1.35; letter-spacing: 0.01em; }
.footer__tagline { max-width: 18rem; color: var(--text-dim); font-size: 0.875rem; line-height: 1.5; }
/* A living line: London's time and tonight's moon (main.js, computed on the device — no network). */
.footer__now { color: var(--moon); font-size: 0.75rem; letter-spacing: 0.06em; }
.footer__now[hidden] { display: none; }
.footer__nav ul { display: grid; gap: 0; }
.footer__link,
.footer__tel {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--text);
  font-size: 0.9375rem;
  transition: color 0.3s;
}
@media (hover: hover) {
  .footer__link:hover { color: var(--champagne); }
}
.footer__contact { display: grid; align-content: start; justify-items: start; gap: 0; color: var(--text-strong); }
.footer__label { margin-bottom: 0.125rem; }
.footer__label--2 { margin-top: 1rem; }
.footer__tel--main { color: var(--text-strong); font-size: 1.375rem; font-weight: 200; }
.footer__base a { text-decoration: underline; text-decoration-color: var(--rule); text-underline-offset: 3px; }
.footer__base {
  display: grid;
  gap: 0.375rem;
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  color: var(--muted);
  font-size: 0.8125rem;
  line-height: 1.5;
}

@media (min-width: 1024px) {
  .footer__grid { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: start; }
  .footer__brand { grid-column: 1 / 5; }
  .footer__nav { grid-column: 6 / 10; }
  .footer__nav ul { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--col-gap); }
  .footer__contact { grid-column: 10 / 13; }
}

/* ---------- Phone call-to-action bar ----------
   Under 1000px, off the film: call, WhatsApp, or start with a photo. Ink, never gold. main.js hides it
   over the configurator (its own price dock), the pinned build (its caption card) and the form. */

.cta-bar { display: none; }
@media (max-width: 999.98px) {
  /* Phones: the menu carries the sections, so the footer keeps to who we are and how to reach us
     (without JS the menu can't open, and this list is where "Menu" leads). */
  .js .footer__nav { display: none; }
  .footer__contact { grid-column: 1 / -1; }
  .footer__base { font-size: 0.75rem; }

  .cta-bar {
    position: fixed;
    inset: auto 0 0;
    z-index: 40;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 10px max(var(--gutter), env(safe-area-inset-right)) calc(10px + env(safe-area-inset-bottom)) max(var(--gutter), env(safe-area-inset-left));
    background: rgba(10, 10, 10, 0.94);
    border-top: 1px solid var(--line);
    visibility: hidden;
    transform: translate3d(0, 100%, 0);
    transition: transform 0.45s var(--ease-out), visibility 0s linear 0.45s;
  }
  .cta-bar[hidden] { display: none; }
  .cta-bar.is-on { visibility: visible; transform: none; transition-delay: 0s; }
  .cta-bar__call {
    display: inline-flex;
    flex: none;
    align-items: center;
    min-width: 44px;
    min-height: 44px;
    color: var(--text-strong);
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
  }
  .cta-bar__go { flex: 0 1 auto; padding-inline: 0.9rem; line-height: 1.3; text-align: center; }
  .footer { padding-bottom: calc(5.5rem + env(safe-area-inset-bottom)); }
}

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

.lightbox {
  position: fixed;
  inset: 0;
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: env(safe-area-inset-top) max(var(--gutter), env(safe-area-inset-right)) env(safe-area-inset-bottom) max(var(--gutter), env(safe-area-inset-left));
  border: 0;
  background: rgba(8, 8, 8, 0.97);
  color: var(--paper);
  overscroll-behavior: contain;
}
.lightbox[open] {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  animation: fade-in 0.35s var(--ease-out);
}
.lightbox::backdrop { background: rgba(0, 0, 0, 0.8); }

.lightbox__bar,
.lightbox__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 64px;
}
.lightbox__count {
  color: var(--text-dim);
  font-size: 0.75rem;
  letter-spacing: 0.18em;
  font-variant-numeric: tabular-nums;
}
.lightbox__stage {
  position: relative;
  min-height: 0;
  touch-action: pan-y pinch-zoom;
}
/* Absolutely placed so max-height has a definite box to resolve against: as a grid item of an
   auto-sized row, a tall (portrait) photograph ignored max-height: 100% and ran off the screen,
   under the caption and the arrows. */
.lightbox__img {
  position: absolute;
  inset: 0;
  margin: auto;
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: 100%;
  object-fit: contain;
  transition: opacity 0.35s var(--ease-out);
}
.lightbox__img.is-loading { opacity: 0; }
.lightbox__caption { min-width: 0; color: var(--text); font-size: 0.875rem; }
.lightbox__tag {
  margin-right: 0.625rem;
  padding-left: 0.625rem;
  border-left: 1px solid var(--champagne);
  color: var(--champagne);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.lightbox__nav { display: flex; gap: 0.5rem; flex: none; }

.icon-btn {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border: 1px solid var(--rule);
  color: var(--paper);
  transition: border-color 0.3s, color 0.3s;
}
@media (hover: hover) {
  .icon-btn:hover { border-color: var(--champagne); color: var(--champagne); }
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* ---------- Reveal on scroll ----------
   main.js adds .reveal only to elements that start below the fold, and only when motion
   is allowed — so nothing is ever parked invisible without JS. */

/* One motion for every reveal: a short rise on the page's ease-out, opacity a touch quicker than the
   move so words are legible before they settle. Transform and opacity only — nothing reflows. */
.reveal {
  --reveal-dur: 1.1s;
  opacity: 0;
  transform: translate(0, 1.25rem);
  transition: opacity calc(var(--reveal-dur) * 0.8) var(--ease-out), transform var(--reveal-dur) var(--ease-out);
  transition-delay: var(--reveal-delay, 0s);
}
.reveal.is-revealed { opacity: 1; transform: none; }
.reveal[data-reveal="1"] { --reveal-delay: 0.07s; }
.reveal[data-reveal="2"] { --reveal-delay: 0.14s; }
.reveal[data-reveal="3"] { --reveal-delay: 0.21s; }
.reveal[data-reveal="4"] { --reveal-delay: 0.28s; }

/* ---------- Switching views ----------
   main.js: the View Transitions API where there is one (the masthead and the phone bar hold still,
   the page crossfades and the new view rises a little); elsewhere the new view gets .view-in. */

.masthead { view-transition-name: masthead; }
.cta-bar { view-transition-name: cta-bar; }
::view-transition-group(masthead),
::view-transition-group(cta-bar) { animation: none; }
::view-transition-old(root) { animation: fade-out 0.24s var(--ease-in-out) both; }
::view-transition-new(root) { animation: view-rise 0.5s var(--ease-out) both; }
.view-in { animation: view-rise 0.5s var(--ease-out) both; }
@keyframes fade-out { to { opacity: 0; } }
@keyframes view-rise {
  from { opacity: 0; transform: translate3d(0, 0.75rem, 0); }
  to { opacity: 1; transform: none; }
}

/* ---------- Reduced motion: keep fades, drop movement ---------- */

@media (prefers-reduced-motion: reduce) {
  .film.film--running .film__chapter:not(.is-shown) .film__copy > * { transform: none; }
  .draw .plan { clip-path: none; }
  .gallery__frame img,
  .room__media img,
  .strip__frame img { transition: none; }
  .shot__open:hover .gallery__frame img,
  .room__link:hover .room__media img,
  .strip__open,
  .strip__frame img { transform: none; }
  .btn { transition: color 0.45s var(--ease-out); }
  .design-card.is-fresh,
  .view-in,
  .done:not([hidden]),
  .qa[open] .qa__a { animation: none; }
}

/* ---------- Print: never print a section still waiting to be revealed ---------- */

@media print {
  .reveal { opacity: 1; transform: none; }
  .masthead, .film__stage { position: static; }
}

/* ==========================================================================
   Round 3 (26.09): the CGI mark, reviews and trust, the people at the contact, the form's privacy line,
   real dates. One ink-and-champagne theme throughout; only the 3D scenes and the photographs are daylight.
   ========================================================================== */

/* The discreet CGI mark on AI imagery (and, in the same voice, "Built by KF Crafts" on a real photograph
   where it sits among CGI). Tiny and low-contrast by design; the footer line explains it. */
.cgi {
  position: absolute;
  right: 0.55rem;
  bottom: 0.45rem;
  z-index: 2;
  margin: 0;
  color: rgba(244, 241, 234, 0.64);
  font-family: var(--sans);
  font-size: 0.5625rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-shadow: 0 0 4px rgba(0, 0, 0, 0.6), 0 1px 12px rgba(0, 0, 0, 0.45);
  white-space: nowrap;
  pointer-events: none;
}
.cgi--real { letter-spacing: 0.16em; color: rgba(244, 241, 234, 0.7); }

/* ---------- Home · in their words: an ink panel inside a champagne hairline ---------- */
.reviews { padding-top: clamp(2.5rem, 5vw, 5rem); }
.reviews__panel {
  position: relative;
  display: grid;
  gap: clamp(2rem, 4vw, 3.5rem) var(--col-gap);
  padding: clamp(1.75rem, 5vw, 4.5rem) clamp(1.25rem, 5vw, 4.5rem);
  background:
    radial-gradient(120% 80% at 100% 0, rgba(227, 206, 146, 0.07), rgba(227, 206, 146, 0) 55%),
    var(--ink-2);
  box-shadow: 0 30px 80px -40px rgba(0, 0, 0, 0.8);
}
.reviews__panel::before {
  content: "";
  position: absolute;
  inset: 0.625rem;
  border: 1px solid var(--line);
  pointer-events: none;
}
.reviews__panel .h2 { font-size: clamp(2rem, 1.4rem + 2.4vw, 3.5rem); }
.reviews__head { display: grid; gap: 1.1rem; align-content: start; }
.reviews__score { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.35rem 0.75rem; margin-top: 0.5rem; }
.reviews__num { color: var(--text-strong); font-size: clamp(2.75rem, 2rem + 2.5vw, 4rem); font-weight: 200; line-height: 1; letter-spacing: -0.02em; }
.reviews__stars { color: var(--gold-hi); font-size: 1.125rem; letter-spacing: 0.18em; }
.reviews__on { flex-basis: 100%; color: var(--text-dim); font-size: 0.75rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; }
.reviews__all { justify-self: start; }
/* The reviews rail (speed pass 26.09 — owner: "the reviews should slide sideways"): a native scroll-snap
   track, one quote to a slide with the next one peeking in. Swipe or drag it on a phone (the browser's own
   momentum and snap — vertical page scrolling is untouched), trackpad or arrows/dots on desktop, keys when
   it has focus. Exactly the five reviews captured from Google, word for word, all five on every screen.
   main.js (initReviews) adds the dots, arrows, pause and a slow advance that stops on hover, touch or focus
   and never runs under reduced motion. Nothing is animated per frame by script: the scroll moves on the
   compositor. */
.reviews__carousel { position: relative; min-width: 0; }
.reviews__list {
  position: relative; /* slides measure their offsetLeft from here */
  display: flex;
  align-items: stretch;
  gap: clamp(1.25rem, 3vw, 2.5rem);
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.reviews__list::-webkit-scrollbar { display: none; }
.reviews__list:focus-visible { outline: 1px solid var(--champagne); outline-offset: 6px; }
.review {
  flex: 0 0 86%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.review__quote { margin: 0; }
.review__quote p {
  color: var(--text-strong);
  font-size: clamp(1.3125rem, 1.05rem + 1.05vw, 1.875rem);
  font-weight: 200;
  line-height: 1.3;
  letter-spacing: -0.005em;
  text-wrap: pretty;
}
.review__quote p::before { content: "\201C"; }
.review__quote p::after { content: "\201D"; }
.review--lead { border-top-color: var(--line-strong); }
.review__who { margin-top: 1rem; color: var(--champagne); font-size: 0.75rem; font-weight: 500; letter-spacing: 0.16em; text-transform: uppercase; }
.review__who span { color: var(--text-dim); font-weight: 400; letter-spacing: 0.08em; text-transform: none; }
.review__src { color: inherit; text-decoration: underline; text-decoration-color: rgba(216, 199, 156, 0.4); text-underline-offset: 0.25em; transition: color 0.3s; }
@media (hover: hover) {
  .review__src:hover { color: var(--champagne); }
}

/* Dots (a 44 px target around a 6 px mark), pause, previous, next. Shown only when the script runs. */
.reviews__nav { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-top: 1.25rem; }
.reviews__nav[hidden] { display: none; }
.reviews__dots { display: flex; margin-left: -19px; }
.reviews__dot {
  position: relative;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.reviews__dot::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: rgba(244, 241, 234, 0.28);
  transition: background-color 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}
.reviews__dot[aria-current="true"]::before { background: var(--champagne); transform: scale(1.35); }
.reviews__dot:focus-visible { outline: 1px solid var(--champagne); outline-offset: -8px; }
.reviews__buttons { display: flex; gap: 0.25rem; }
.reviews__btn {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  color: var(--text-strong);
  background: none;
  border: 1px solid var(--line);
  border-radius: 50%;
  cursor: pointer;
  transition: border-color 0.3s, color 0.3s;
}
.reviews__btn svg { width: 20px; height: 20px; }
.reviews__btn--play { border-color: transparent; color: var(--text-dim); }
.reviews__btn--play .i-play { display: none; }
.reviews__btn--play[aria-pressed="true"] .i-play { display: inline; }
.reviews__btn--play[aria-pressed="true"] .i-pause { display: none; }
.reviews__btn:focus-visible { outline: 1px solid var(--champagne); outline-offset: 2px; }
@media (hover: hover) {
  .reviews__btn:hover { color: var(--champagne); border-color: var(--line-strong); }
}
/* Nothing moves by itself under reduced motion: no pause button either. */
@media (prefers-reduced-motion: reduce) {
  .reviews__btn--play { display: none; }
}
/* Phones: swipe is the way through (native momentum and snap); the dots and the pause stay, the arrows go. */
@media (max-width: 767.98px) {
  .reviews__btn:not(.reviews__btn--play) { display: none; }
}
@media (min-width: 768px) {
  .review { flex-basis: 80%; }
}
@media (min-width: 1100px) {
  .reviews__panel { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .reviews__head { grid-column: 1 / 5; align-self: start; }
  .reviews__carousel { grid-column: 6 / 13; align-self: end; }
  .review { flex-basis: 84%; }
}

/* Why homeowners trust KF: ten short, true lines under the panel. */
.trust { margin-top: clamp(2rem, 4vw, 3.25rem); }
.trust__title {
  color: var(--text-strong);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.trust__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.875rem var(--col-gap);
  margin-top: 1.25rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
}
.trust__list li {
  position: relative;
  min-width: 0;
  padding-left: 1rem;
  color: var(--text-dim);
  font-size: 0.8125rem;
  line-height: 1.45;
}
.trust__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.5em;
  width: 5px;
  height: 5px;
  background: var(--champagne);
  transform: rotate(45deg);
}
.trust__list a { color: var(--text-strong); text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; }
@media (min-width: 1024px) {
  .trust__list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* The four promises that matter most, large; the other six behind a quiet disclosure. */
.trust__key {
  display: grid;
  gap: 1.5rem var(--col-gap);
  margin-top: 1.25rem;
}
.trust__key li { display: grid; gap: 0.35rem; min-width: 0; padding-top: 1rem; border-top: 1px solid var(--line); }
.trust__k {
  color: var(--text-strong);
  font-size: clamp(1.25rem, 1.05rem + 0.8vw, 1.625rem);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: -0.005em;
}
.trust__v { color: var(--text-dim); font-size: 0.875rem; line-height: 1.5; }
@media (min-width: 640px) { .trust__key { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .trust__key { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.trust__more { margin-top: 1.25rem; }
.trust__sum {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 44px;
  color: var(--text);
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  list-style: none;
  cursor: pointer;
}
.trust__sum::-webkit-details-marker { display: none; }
.trust__sum::after {
  content: "";
  width: 0.45rem;
  height: 0.45rem;
  margin-top: -0.2rem;
  border-right: 1px solid var(--champagne);
  border-bottom: 1px solid var(--champagne);
  transform: rotate(45deg);
  transition: transform 0.3s var(--ease-out);
}
.trust__more[open] .trust__sum::after { transform: rotate(-135deg); margin-top: 0.2rem; }
.trust__sum:focus-visible { outline: 2px solid var(--gold-hi); outline-offset: 3px; }
.trust__more .trust__list { margin-top: 0.5rem; }

/* ---------- The people at the contact, and every portrait slot ---------- */
.contact__people { display: flex; align-items: center; margin-bottom: 1.25rem; }
.contact__line { margin-left: 0.875rem; color: var(--text); font-size: 0.9375rem; line-height: 1.4; }
.portrait {
  position: relative;
  display: grid;
  place-items: center;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background:
    radial-gradient(120% 80% at 50% 12%, rgba(227, 206, 146, 0.16), rgba(227, 206, 146, 0) 60%),
    linear-gradient(180deg, #1b1915, #0c0b0a);
  border: 1px solid rgba(216, 199, 156, 0.3);
}
.portrait::after {
  content: "";
  position: absolute;
  right: 8%;
  bottom: 6%;
  width: 26%;
  aspect-ratio: 1;
  background: url("assets/logo/kf-seal-compact.svg") center / contain no-repeat;
  opacity: 0.14;
}
.portrait__initials {
  color: #d8c79c;
  font-family: var(--seal);
  font-size: clamp(2.25rem, 1.6rem + 2.4vw, 3.5rem);
  font-weight: 400;
  letter-spacing: 0.14em;
  text-indent: 0.14em;
}
.portrait img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.portrait.has-photo::after,
.portrait.has-photo .portrait__initials { display: none; }
.portrait--xs { width: 44px; height: 44px; aspect-ratio: 1; border-radius: 50%; }
.portrait--xs + .portrait--xs { margin-left: -10px; }
.portrait--xs::after { display: none; }
.portrait--xs .portrait__initials { font-size: 0.75rem; letter-spacing: 0.06em; text-indent: 0.06em; }

/* ---------- The form: privacy line, survey request ---------- */
.form__privacy { margin-top: 1rem; color: var(--muted); font-size: 0.75rem; line-height: 1.5; }
.form__privacy a { color: var(--text-dim); text-decoration: underline; text-decoration-color: var(--rule); text-underline-offset: 3px; }
.done__request { display: grid; justify-items: start; gap: 0.5rem; }
.done__request[hidden] { display: none; }
.done__request-status { color: var(--text-dim); font-size: 0.875rem; }

/* ---------- How it works: real months, if you start this week (main.js) ---------- */
.dates {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  margin-top: clamp(2rem, 4vw, 3rem);
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  color: var(--text-dim);
  font-size: 0.875rem;
}
.dates[hidden] { display: none; }
.dates__lead { flex-basis: 100%; color: var(--champagne); font-size: 0.6875rem; font-weight: 500; letter-spacing: 0.2em; text-transform: uppercase; }
.dates b { color: var(--text-strong); font-weight: 400; }
.dates__note { flex-basis: 100%; color: var(--muted); font-size: 0.75rem; }

@media (prefers-reduced-motion: reduce) {
  .film.film--running .film__chapter:not(.is-shown) .film__copy > * { filter: none; }
  .brand__seal { transition: none; }
}

/* ==========================================================================
   Round 4 (26.09): the details band, the garden visualiser's place, the materials, and the motion layer —
   masked headlines, clip-path image reveals, slow parallax, staggered grids, count-ups, the desktop cursor.
   One easing for all of it (--ease-expo), nothing bounces, everything is transform / opacity / clip-path,
   and all of it stands still under prefers-reduced-motion.
   ========================================================================== */

:root { --ease-expo: cubic-bezier(0.19, 1, 0.22, 1); }

/* ---------- The living details band, above the calculator ---------- */
.details { margin-bottom: clamp(2.25rem, 4.5vw, 4rem); }
.details__list {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min(84vw, 26rem);
  gap: 0.75rem;
  padding-inline: max(var(--gutter), env(safe-area-inset-left)) max(var(--gutter), env(safe-area-inset-right));
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: max(var(--gutter), env(safe-area-inset-left));
  scrollbar-width: none;
}
.details__list::-webkit-scrollbar { display: none; }
.details__item { min-width: 0; scroll-snap-align: start; }
.details__frame {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--ink-2);
}
.details__poster,
.details__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.details__video { opacity: 0; transition: opacity 1.2s var(--ease-out); }
.details__frame.is-playing .details__video { opacity: 1; }
.details__frame::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to top, rgba(10, 10, 10, 0.42), rgba(10, 10, 10, 0) 38%);
}
.details__cap {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  margin-top: 0.75rem;
  color: var(--text-dim);
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
}
.details__num { color: var(--champagne); font-size: 0.6875rem; font-variant-numeric: tabular-nums; letter-spacing: 0.18em; }
@media (min-width: 900px) {
  .details__list {
    grid-auto-flow: row;
    grid-template-columns: 1.25fr 1fr 1fr;
    gap: 2px;
    padding-inline: 0;
    overflow: visible;
  }
  .details__frame { aspect-ratio: auto; height: clamp(15rem, 30vw, 27rem); }
  .details__cap { padding-inline: 1.25rem 0; }
  .details__item:first-child .details__cap { padding-left: max(var(--gutter), env(safe-area-inset-left)); }
}

/* ---------- "See it in your garden" (Round 8, 28.09): one component, two layouts (js/reveal.js) ----------
   Phones, tablets and touch screens: the words, the frame, the three stops and the button, stacked. The frame is a
   before/after with a champagne hairline: untouched it wipes slowly from before to after and back (JS, only while on
   screen, never under reduced motion); a sideways drag takes it. Desktop with a mouse: css/visualiser-desktop.css.
   The split is one number, --s (0…1) on the stage: the "after" layer slides in by it while its picture slides back the
   same distance, so the picture stays put and only the edge moves (transforms only, on the compositor). cq units are
   the stage's own size (container-type: size). */
.visualiser { margin-bottom: clamp(3rem, 6vw, 5.5rem); scroll-margin-top: calc(var(--header-h) + 1rem); }
.rv__stage {
  --s: 0.5;
  position: relative;
  aspect-ratio: 4 / 3;
  max-height: 78svh;
  overflow: hidden;
  container-type: size;
  border: 1px solid var(--rule);
  background: var(--ink-2);
  touch-action: pan-y;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
@media (min-width: 900px) { .rv__stage { aspect-ratio: 16 / 9; } }
/* the calculator's view frame: gold corner ticks */
.rv__stage::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 8;
  pointer-events: none;
  background:
    linear-gradient(var(--champagne), var(--champagne)) left top / 18px 1px no-repeat,
    linear-gradient(var(--champagne), var(--champagne)) left top / 1px 18px no-repeat,
    linear-gradient(var(--champagne), var(--champagne)) right top / 18px 1px no-repeat,
    linear-gradient(var(--champagne), var(--champagne)) right top / 1px 18px no-repeat,
    linear-gradient(var(--champagne), var(--champagne)) left bottom / 18px 1px no-repeat,
    linear-gradient(var(--champagne), var(--champagne)) left bottom / 1px 18px no-repeat,
    linear-gradient(var(--champagne), var(--champagne)) right bottom / 18px 1px no-repeat,
    linear-gradient(var(--champagne), var(--champagne)) right bottom / 1px 18px no-repeat;
}
/* the picture box: "cover" the stage, centred (4:3 pictures; 16:9 from 900 px; the film is always 16:9) */
.rv__pic { position: absolute; left: 50%; top: 50%; pointer-events: none; width: max(100cqw, 133.334cqh); aspect-ratio: 4 / 3; transform: translate(-50%, -50%); }
@media (min-width: 900px) { .rv__pic { width: max(100cqw, 177.778cqh); aspect-ratio: 16 / 9; } }
.rv__film .rv__pic { width: max(100cqw, 177.778cqh); aspect-ratio: 16 / 9; }
.rv__pic img,
.rv__pic video { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.rv__after { position: absolute; inset: 0; z-index: 1; overflow: hidden; transform: translateX(calc(var(--s) * 100cqw)); will-change: transform; }
.rv__after > .rv__pic { transform: translate(-50%, -50%) translateX(calc(var(--s) * -100cqw)); will-change: transform; }
.rv__film { position: absolute; inset: 0; z-index: 3; overflow: hidden; background: var(--ink-2); opacity: 0; visibility: hidden; transition: opacity 0.7s var(--ease-out), visibility 0s linear 0.7s; }
.rv[data-mode="film"] .rv__film.is-ready { opacity: 1; visibility: visible; transition: opacity 0.7s var(--ease-out); }
.rv__video { object-fit: cover; }
.rv__shade {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(10, 10, 10, 0.5) 0%, rgba(10, 10, 10, 0) 24%), linear-gradient(0deg, rgba(10, 10, 10, 0.35) 0%, rgba(10, 10, 10, 0) 18%);
}
/* the hairline: 1 px of champagne and a small open diamond; 44 px to take hold of */
.rv__hair {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -22px;
  z-index: 6;
  width: 44px;
  cursor: ew-resize;
  touch-action: pan-y;
  transform: translateX(calc(var(--s) * 100cqw));
  transition: opacity 0.35s ease;
}
.rv__hair::before { content: ""; position: absolute; top: 0; bottom: 0; left: 50%; width: 1px; margin-left: -0.5px; background: var(--champagne); box-shadow: 0 0 10px rgba(10, 10, 10, 0.35); }
.rv__hair::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 11px;
  height: 11px;
  border: 1px solid var(--champagne);
  background: rgba(10, 10, 10, 0.4);
  transform: translate(-50%, -50%) rotate(45deg);
  transition: width 0.25s var(--ease-out), height 0.25s var(--ease-out), background-color 0.25s;
}
.rv__hair:focus-visible { outline: none; }
.rv__hair:focus-visible::after,
.rv.is-dragging .rv__hair::after { width: 15px; height: 15px; background: rgba(216, 199, 156, 0.3); }
.rv__hair:focus-visible::before { box-shadow: 0 0 0 1px rgba(216, 199, 156, 0.35); }
/* slim hairline tags, "Before" and "With your room · CGI" (each steps aside as the line nears its edge) */
.rv__tag {
  position: absolute;
  top: 0.85rem;
  z-index: 5;
  padding: 0.34rem 0.55rem 0.3rem;
  border: 1px solid rgba(216, 199, 156, 0.5);
  background: rgba(10, 10, 10, 0.26);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--ivory);
  font-size: 0.5625rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
  transition: opacity 0.35s ease;
}
.rv__tag--l { left: 0.75rem; }
.rv__tag--r { right: 0.75rem; color: var(--champagne); }
.rv__tag--film { left: 0.75rem; color: var(--champagne); opacity: 0; }
.rv__stage .cgi { z-index: 7; }
.rv.is-edge-l .rv__tag--l,
.rv.is-edge-r .rv__tag--r { opacity: 0; }
.rv[data-mode="film"] .rv__hair,
.rv[data-mode="film"] .rv__tag--l,
.rv[data-mode="film"] .rv__tag--r { opacity: 0; pointer-events: none; }
.rv[data-mode="film"] .rv__tag--film { opacity: 1; }
/* the three stops: what KF Studio makes from one photo */
.rv__side { margin-top: 0.9rem; }
.rv__stops { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.6rem; margin: 0; padding: 0; list-style: none; }
.rv__stop {
  position: relative;
  display: grid;
  align-content: start;
  gap: 0.3rem;
  width: 100%;
  min-height: 44px;
  padding: 0.7rem 0 0.35rem;
  border: 0;
  border-top: 1px solid rgba(244, 241, 234, 0.2);
  background: none;
  color: rgba(244, 241, 234, 0.66);
  font: inherit;
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0.14em;
  text-align: left;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.3s;
}
.rv__stop b { color: rgba(244, 241, 234, 0.62); font-family: var(--seal); font-size: 0.5625rem; font-weight: 500; letter-spacing: 0.2em; transition: color 0.3s; }
/* the champagne line fills over the stop that is showing (and runs with the film) */
.rv__stop::before { content: ""; position: absolute; top: -1px; left: 0; right: 0; height: 1px; background: var(--champagne); transform: scaleX(var(--p, 0)); transform-origin: left; }
.rv__stop[aria-pressed="true"] { --p: 1; color: var(--champagne); }
.rv__stop[aria-pressed="true"] b { color: var(--champagne); }
.rv__stop.is-loading span::after { content: " · loading"; color: rgba(244, 241, 234, 0.5); }
.rv__stop:focus-visible { outline: 1px solid var(--line-strong); outline-offset: 3px; }
@media (hover: hover) {
  .rv__stop:hover { color: var(--ivory); }
}
.rv__note { margin-top: 0.55rem; color: var(--text-dim); font-size: 0.75rem; line-height: 1.5; }
.vt__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-top: 1.25rem;
}
.vt__copy { max-width: 40rem; color: var(--text-dim); font-size: 0.9375rem; line-height: 1.6; }

.annexe__check { margin-top: 1.25rem; }
.annexe__check:empty { margin: 0; }

/* ---------- The materials: a slow drift under a hairline ---------- */
.materials {
  position: relative;
  margin-top: clamp(2.25rem, 4vw, 3.5rem);
  padding-block: 1.1rem;
  overflow: hidden;
  border-block: 1px solid var(--rule);
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}
.materials--top { margin: 0 0 clamp(1.5rem, 3vw, 2.5rem); }
.materials__rail { display: flex; width: max-content; }
.materials__list { display: flex; flex: none; gap: 0; }
.materials__list li {
  display: flex;
  align-items: center;
  flex: none;
  color: var(--text-dim);
  font-family: var(--seal);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  white-space: nowrap;
}
.materials__list li::after {
  content: "";
  width: 5px;
  height: 5px;
  margin-inline: 2.25rem;
  background: var(--gold);
  opacity: 0.7;
  transform: rotate(45deg);
}
@media (prefers-reduced-motion: no-preference) {
  .materials.is-running .materials__rail { animation: kf-drift-x 90s linear infinite; }
}
@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .materials:hover .materials__rail { animation-play-state: paused; }
}
@keyframes kf-drift-x { to { transform: translate3d(-50%, 0, 0); } }
@media (prefers-reduced-motion: reduce) {
  .materials { -webkit-mask-image: none; mask-image: none; }
  .materials__rail { width: auto; }
  .materials__list { flex-wrap: wrap; row-gap: 0.75rem; }
  .materials__list[aria-hidden="true"] { display: none; }
}

/* ---------- Masked headlines: each line rises out of its own slot (main.js splits the words) ---------- */
.mline {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  /* room for descenders and the light weight's overshoot, without moving a line */
  padding: 0.06em 0.02em 0.12em;
  margin: -0.06em -0.02em -0.12em;
}
.mline__i {
  display: inline-block;
  transition: transform 1.25s var(--ease-expo);
  transition-delay: calc(var(--li, 0) * 85ms);
}
/* Speed pass 26.09: 2D translates for everything waiting to be revealed. A resting translate3d made each
   waiting word its own GPU layer (127 layers on the phone), and re-layering them cost up to 70 ms a frame.
   The motion is the same; the browser still animates it on the compositor. */
.lines-wait .mline__i { transform: translate(0, 112%); }

/* ---------- Clip-path image reveals, with the picture settling inside its frame ---------- */
.clip-wait { clip-path: inset(12% 12% 12% 12%); }
.clip-wait img,
.clip-wait video { transform: scale(1.16); }
.clip-in {
  clip-path: inset(0 0 0 0);
  transition: clip-path 1.45s var(--ease-expo) var(--clip-delay, 0s);
}
.clip-in img,
.clip-in video { transition: transform 1.9s var(--ease-expo) var(--clip-delay, 0s), opacity 1.2s var(--ease-out); }

/* ---------- Staggered rises (reviews, trust) ---------- */
.rise-wait { opacity: 0; transform: translate(0, 1.5rem); }
.rise-in {
  transition: opacity 1s var(--ease-out) var(--rise-delay, 0s), transform 1.3s var(--ease-expo) var(--rise-delay, 0s);
}

/* Count-ups keep their width while the digits run. */
.count { font-variant-numeric: tabular-nums; }

/* ---------- Slow parallax: pictures drift a few percent inside their frames as the page moves
   (CSS scroll-driven animations, on the compositor; browsers without them keep the picture still). */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .band img,
    .annexe__frame img,
    .process__frame img {
      animation: kf-parallax linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
  }
}
@keyframes kf-parallax {
  from { translate: 0 -3.5%; scale: 1.09; }
  to { translate: 0 3.5%; scale: 1.09; }
}

/* ---------- The cursor (desktop, fine pointer, motion welcome): a hairline ring that trails the pointer
   and opens into "View" over photographs and rooms. The system cursor stays; this only accompanies it. */
.cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60;
  width: 0;
  height: 0;
  pointer-events: none;
  opacity: 0;
  visibility: hidden; /* Round 5 §C: never a ring waiting at the corner — only once a mouse has moved */
  transition: opacity 0.4s var(--ease-out), visibility 0s linear 0.4s;
}
.cursor.is-on { opacity: 1; visibility: visible; transition-delay: 0s; }
@media (hover: none), (pointer: coarse) {
  .cursor { display: none; }
}
.cursor__ring {
  position: absolute;
  left: -14px;
  top: -14px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 1px solid rgba(216, 199, 156, 0.7);
  border-radius: 50%;
  transition: transform 0.55s var(--ease-expo), background-color 0.4s var(--ease-out), border-color 0.4s var(--ease-out);
}
.cursor__label {
  color: var(--ink);
  font-size: 0.5rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  opacity: 0;
  transform: scale(0.5);
  transition: opacity 0.3s var(--ease-out), transform 0.45s var(--ease-expo);
}
.cursor.is-link .cursor__ring { transform: scale(0.45); background: rgba(216, 199, 156, 0.5); border-color: transparent; }
.cursor.is-view .cursor__ring { transform: scale(2.4); background: rgba(216, 199, 156, 0.92); border-color: transparent; }
.cursor.is-view .cursor__label { opacity: 1; transform: scale(0.42); }
.cursor.is-down .cursor__ring { transform: scale(0.8); }
.cursor.is-view.is-down .cursor__ring { transform: scale(2.1); }

@media (prefers-reduced-motion: reduce) {
  .lines-wait .mline__i,
  .clip-wait img,
  .clip-wait video { transform: none; }
  .clip-wait { clip-path: none; }
  .rise-wait { opacity: 1; transform: none; }
  .cursor { display: none; }
}
@media print {
  .lines-wait .mline__i, .clip-wait img { transform: none; }
  .clip-wait { clip-path: none; }
  .rise-wait { opacity: 1; transform: none; }
}

/* ==========================================================================
   Round 5 (26.09): KF Studio's place, "Open in KF Studio", one contact, the phone as its own experience.
   ========================================================================== */

/* ---------- KF Studio (#studio): the view the studio app mounts into (its own UI: css/studio.css) ----------
   main.js imports js/studio/app.js when the view opens; until then (and if it can't) a quiet holding card. */
.studio-view { min-height: 100vh; min-height: 100svh; }
.studio-view__root:empty { display: none; }
.studio-view[data-studio="ready"] .studio-view__wait { display: none; }
.studio-view__wait {
  display: grid;
  justify-items: center;
  gap: 1rem;
  max-width: 34rem;
  margin: clamp(3rem, 14vh, 9rem) auto clamp(3rem, 8vh, 6rem);
  padding-inline: max(var(--gutter), env(safe-area-inset-left)) max(var(--gutter), env(safe-area-inset-right));
  text-align: center;
}
.studio-view__seal { width: 64px; height: 64px; }
.studio-view__eyebrow { justify-content: center; }
.studio-view__eyebrow::after { content: ""; flex: none; width: 1.75rem; height: 1px; background: currentColor; }
.studio-view__title { font-size: var(--fs-h3); font-weight: 200; line-height: 1.12; letter-spacing: -0.015em; }
.studio-view__text { max-width: 30rem; color: var(--text-dim); }
.studio-view__alt { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.75rem 1.75rem; margin-top: 0.5rem; }
.studio-view__alt[hidden] { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .studio-view[data-studio="loading"] .studio-view__seal { animation: studio-breathe 2.4s ease-in-out infinite; }
}
@keyframes studio-breathe { 50% { opacity: 0.45; } }
/* An app of its own: its sticky controls own the foot of the screen, so the chat button steps aside. */
html[data-screen="studio"] .kfc-fab { display: none; }
/* Once the studio is up (html.studio-on, main.js) the software owns the window (judges 27.09): the site header
   steps aside — the studio's own bar carries the seal, back, the steps and close — so there is one bar, no gap
   and no double rule, and the app ends exactly at the bottom edge (css/studio.css .kfs--page). The concept
   banner stays. Nothing scrolls behind it: the FAQ, the footer and the call bar come back with the page. */
html.studio-on .masthead .header { display: none; }
html.studio-on .masthead.is-scrolled { top: 0; }
html.studio-on .studio-view { min-height: 0; padding: var(--banner-h, 0px) 0 0; }
html.studio-on #faq,
html.studio-on .footer,
html.studio-on [data-cta-bar] { display: none; }

/* "Open in KF Studio": a quiet card-link (Contact; the calculator has its own, in css/configurator.css). */
.head__more { max-width: 34rem; }
/* On the 12-column head it takes the intro's column, on its own row under it (without this it fell into one
   1/12 column and stood the words on end, 2000 px tall, integrator walk 27.09). */
@media (min-width: 1024px) {
  .head__more { grid-column: 9 / 13; align-self: start; }
}
.studio-link {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 1.25rem;
  min-height: 44px;
  padding: 0.95rem 1.1rem 1rem 1.25rem;
  border: 1px solid var(--line);
  background: linear-gradient(100deg, rgba(216, 199, 156, 0.07), rgba(216, 199, 156, 0) 60%);
  transition: border-color 0.35s var(--ease-out), background-color 0.35s var(--ease-out);
}
.studio-link__k {
  color: var(--champagne);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.studio-link__t { grid-column: 1; margin-top: 0.25rem; color: var(--text-dim); font-size: 0.875rem; line-height: 1.45; }
.studio-link__go {
  grid-column: 2;
  grid-row: 1 / span 2;
  position: relative;
  width: 1.5rem;
  height: 1px;
  background: var(--champagne);
  transition: transform 0.45s var(--ease-out);
}
.studio-link__go::after {
  content: "";
  position: absolute;
  right: 0;
  top: -3.5px;
  width: 8px;
  height: 8px;
  border-top: 1px solid var(--champagne);
  border-right: 1px solid var(--champagne);
  transform: rotate(45deg);
}
@media (hover: hover) {
  .studio-link:hover { border-color: var(--line-strong); background-color: rgba(216, 199, 156, 0.03); }
  .studio-link:hover .studio-link__go { transform: translateX(4px); }
}
.studio-link:focus-visible { outline-offset: 4px; }

/* ---------- One contact (§I): Hristiyan everywhere, one discreet line for the paperwork ---------- */
.contact__email {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--text);
  font-size: 0.9375rem;
  letter-spacing: 0.01em;
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-underline-offset: 4px;
}
.contact__paper,
.footer__paper {
  color: var(--muted);
  font-size: 0.75rem;
  line-height: 1.5;
  letter-spacing: 0.02em;
}
.contact__paper { margin-top: 0.5rem; }
/* Owner, 27.09: both owners' addresses. Ivan sits under Hristiyan as a second, quieter name — not a wall. */
.contact__label--2 { margin: 1.25rem 0 0; }
/* Round 8 (qa3: the contact block within ~1.2 screens on a laptop): on a wide screen Ivan and Hristiyan stand side by
   side — label, number, WhatsApp, email in two columns — instead of one under the other. Same content, same order. */
@media (min-width: 1200px) {
  .contact { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(1.25rem, 2vw, 2rem); }
  .contact > * { grid-column: 1; }
  .contact > .contact__people,
  .contact > .contact__paper { grid-column: 1 / -1; }
  .contact > :nth-child(n + 6):nth-child(-n + 9) { grid-column: 2; }
  .contact > :nth-child(2), .contact > :nth-child(6) { grid-row: 2; }
  .contact > :nth-child(3), .contact > :nth-child(7) { grid-row: 3; }
  .contact > :nth-child(4), .contact > :nth-child(8) { grid-row: 4; }
  .contact > :nth-child(5), .contact > :nth-child(9) { grid-row: 5; }
  .contact > .contact__paper { grid-row: 6; }
  .contact__label--2 { margin: 0; }
  .contact .contact__value { font-size: clamp(1.25rem, 1rem + 0.5vw, 1.5rem); }
}
.footer__paper { margin-top: 0.75rem; }
.contact__paper a,
.footer__paper a { color: var(--text-dim); text-decoration: underline; text-decoration-color: var(--rule); text-underline-offset: 3px; }
@media (pointer: coarse) {
  .contact__paper a,
  .footer__paper a { display: inline-block; padding-block: 13px; line-height: 18px; }
}
@media (hover: hover) {
  .contact__email:hover,
  .contact__paper a:hover,
  .footer__paper a:hover { color: var(--champagne); }
}

/* ---------- The phone as its own experience (§D) ----------
   The call bar: two quiet buttons of equal weight and the concierge's round "Ask", in the thumb's reach, the same
   hairline language as the rest of the site. */
.cta-bar__icon { display: none; }
@media (max-width: 999.98px) {
  .cta-bar {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: 0.5rem;
    padding-top: 8px;
    padding-bottom: calc(8px + env(safe-area-inset-bottom));
    background: var(--ink);
  }
  .cta-bar[hidden] { display: none; }
  .cta-bar__call {
    justify-content: center;
    gap: 0.55rem;
    min-height: 48px;
    padding: 0 1.1rem;
    border: 1px solid var(--line);
    font-size: 0.6875rem;
    letter-spacing: 0.14em;
    white-space: nowrap;
    -webkit-tap-highlight-color: transparent;
    transition: border-color 0.25s, color 0.25s;
  }
  .cta-bar__call--wa { border-color: var(--line-strong); color: var(--champagne); }
  .cta-bar__call:active { border-color: var(--champagne); }
  .cta-bar__icon { display: block; flex: none; width: 17px; height: 17px; color: var(--champagne); }
  .cta-bar .cta-bar__ask { align-self: center; width: 48px; height: 48px; }
}
@media (max-width: 359.98px) {
  .cta-bar__call { padding: 0 0.75rem; letter-spacing: 0.1em; }
}

/* Phone speed (Round 5 §10): the home blocks below the reel, the FAQ and the footer are laid out and painted only
   as they come near the screen (content-visibility: auto; each remembers its real height once it has been shown).
   The first paint then covers the reel and its words, not a 12,000 px page: ~0.4–0.9 s sooner on a 4G phone
   (measured 27.09), and whole-page style passes (the menu opening, the fonts arriving) touch far less.
   main.js arms the reveals in a block only once the block renders. */
@media (max-width: 899.98px) {
  #rooms { content-visibility: auto; contain-intrinsic-size: auto 900px; }
  #design { content-visibility: auto; contain-intrinsic-size: auto 1150px; } /* its height before it builds (judges 27.09) */
  #built { content-visibility: auto; contain-intrinsic-size: auto 650px; }
  #reviews { content-visibility: auto; contain-intrinsic-size: auto 1150px; }
  #enquire { content-visibility: auto; contain-intrinsic-size: auto 2400px; }
  #faq { content-visibility: auto; contain-intrinsic-size: auto 800px; }
  .footer { content-visibility: auto; contain-intrinsic-size: auto 760px; }
  /* Round 8: while the page glides to a place further down (main.js glideTo: "Send me this design", Contact), every
     block is laid out at its real height, so the place does not move under the glide (it came to rest 263 px short). */
  html.is-gliding :is(#rooms, #design, #built, #reviews, #enquire, #faq, .footer) { content-visibility: visible; }
}
