/* ============================================================
   BALMÂ FINEST PROPERTY — Val d'Isère
   Brand charter extracted from "BALMÂ FINEST PROPERTY I Brochure général.pdf":
   backgrounds sampled at #291F1D / #1E1614, copper accent ramp #785848 → #C8A080,
   display face ivymode (Adobe Fonts kit yim7vvk), text face Poppins.
   Corners are square throughout, as in the brochure.
   ============================================================ */

:root {
  /* ---- Backgrounds ---- */
  --bg:          #291F1D;
  --bg-2:        #2E2422;
  --bg-3:        #342A27;
  --ink:         #1E1614;

  /* ---- Text ---- */
  --fg:          #F4F1ED;
  --fg-soft:     #C9C0B9;
  --muted:       #8E827B;

  /* ---- Accent + lines ---- */
  --accent:      #A9836A;
  --beige:       #C8AD8B;
  --accent-hi:   #C8A080;
  --accent-lo:   #785848;
  /* The brochure gold is not one gradient stop pair: sampled from the page 8
     letters, it cycles dark bronze, mid gold and champagne highlights like
     metal leaf. Every gold wordmark shares this ramp. */
  --gold: linear-gradient(100deg,
    #66452F 0%, #8A6249 12%, #C49C74 24%, #DDBE95 33%, #B08761 43%,
    #77503E 55%, #A47A5C 67%, #D6B28A 79%, #96725C 90%, #5C4234 100%);
  --line:        rgba(244, 241, 237, 0.14);
  --line-strong: rgba(244, 241, 237, 0.26);

  /* ---- Layout ---- */
  --maxw:        1240px;
  --pad:         clamp(22px, 5vw, 80px);
  --radius:      0px;

  /* ---- Motion + type ---- */
  --ease:        cubic-bezier(0.22, 1, 0.36, 1);
  --serif:       "ivymode", "Cormorant Garamond", Georgia, serif;
  --sans:        "Poppins", system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* ============================================================
   BASE
   ============================================================ */

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.7;
  letter-spacing: 0.015em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* NO overflow-x clamp here: overflow-x on body (clip or hidden) breaks
     every position:sticky descendant in iOS Safari — the hero canvas, the
     manifesto, the day/night stage all unpin. Horizontal overflow is
     handled where it happens (each pinned strip clips itself). */
}

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }

h1, h2, h3 {
  margin: 0;
  font-family: var(--serif);
  font-weight: 200;
  line-height: 1.06;
  letter-spacing: 0.01em;
}
/* Titles' italic accents: beige, per the client (gold stays on wordmarks) */
em {
  font-style: italic;
  color: var(--beige);
}

::selection { background: var(--accent-lo); color: var(--fg); }

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

/* ---- Shared bits ---------------------------------------------------- */
.eyebrow {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--beige);
  margin: 0 0 26px;
}

.lede {
  font-size: 14px;
  color: var(--fg-soft);
  max-width: 71ch;
  margin: 26px 0 0;
  line-height: 1.85;
}

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--sans); font-size: 11px; font-weight: 500;
  letter-spacing: 0.24em; text-transform: uppercase;
  padding: 17px 40px; border-radius: var(--radius);
  white-space: nowrap;
  transition: background .4s var(--ease), color .4s var(--ease),
              border-color .4s var(--ease), transform .4s var(--ease);
}
/* --mx / --my are written by the magnetic pointer handler in site.js, and
   --press by :active. Both live in one transform so hover colour changes
   never fight the movement. */
.btn { transform: translate3d(var(--mx, 0px), var(--my, 0px), 0) scale(var(--press, 1)); }
.btn--light { color: var(--fg); border: 1px solid var(--line-strong); }
/* Surface CTAs are static: no magnetic pull (excluded in site.js), no press scale */
.surface__cta { transform: none; }
.btn--light:hover { background: var(--fg); color: var(--ink); border-color: var(--fg); }
.btn--solid { color: var(--ink); background: var(--fg); border: 1px solid var(--fg); }
.btn--solid { transform: none; }  /* excluded from the magnetic pull: it must not move */
.btn--solid:hover { background: transparent; border-color: var(--fg); color: var(--fg); }

/* ---- Scroll progress ------------------------------------------------ */
.scroll-progress {
  position: fixed; top: 0; left: 0; height: 2px; width: 0;
  background: var(--accent); z-index: 200; transition: width .1s linear;
}

/* ============================================================
   NAV
   ============================================================ */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 150;
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px;
  height: 72px;
  padding: 0 var(--pad);
  transition: background .5s var(--ease), backdrop-filter .5s var(--ease), height .5s var(--ease);
}
/* Gradient backdrop so the nav stays readable over bright frames of the
   fly-through. It fades out once the solid scrolled state takes over. */
.nav::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(to bottom, rgba(30,22,20,0.78) 0%, rgba(30,22,20,0.34) 55%, rgba(30,22,20,0) 100%);
  transition: opacity .5s var(--ease);
}
.nav.is-scrolled::before { opacity: 0; }
.nav.is-scrolled {
  height: 64px;
  background: rgba(30, 22, 20, 0.82);
  backdrop-filter: blur(16px) saturate(120%);
  border-bottom: 1px solid var(--line);
}
.nav__brand {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  align-self: center;
  font-family: var(--serif); font-weight: 300;
  font-size: 20px; line-height: 1.1;
  color: var(--fg); white-space: nowrap;
}
/* Each line carries its own letter-spacing AND the full compensating
   padding, so both glyph runs are truly centred on the same axis. */
.nav__brand-word { letter-spacing: 0.34em; padding-left: 0.34em; }
.nav__brand-tag {
  font-family: var(--sans); font-size: 6.5px; font-weight: 400; line-height: 1;
  /* letter-spacing leaves a phantom space after the last letter; the
     padding rebalances it, same trick as the wordmark above */
  letter-spacing: 0.42em; padding-left: 0.42em;
  text-transform: uppercase; color: var(--muted);
}
.nav__links { display: flex; gap: clamp(18px, 2.4vw, 36px); }
.nav__links a {
  font-size: 11px; font-weight: 400; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--fg-soft); position: relative; padding: 4px 0; white-space: nowrap;
}
.nav__links a::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 1px; width: 0;
  background: var(--accent); transition: width .4s var(--ease);
}
.nav__links a:hover { color: var(--fg); }
.nav__links a:hover::after { width: 100%; }

.nav__end { display: flex; align-items: center; gap: 20px; }

.lang {
  display: inline-flex; align-items: center; gap: 8px;
  background: none; border: 0; padding: 0; cursor: pointer;
  font-family: var(--sans); font-size: 11px; letter-spacing: 0.16em;
  color: var(--muted);
}
.lang__opt { color: var(--muted); text-decoration: none; transition: color .3s var(--ease); }
.lang__opt:hover { color: var(--fg); }
.lang__opt.is-on { color: var(--fg); }
.lang__sep { width: 1px; height: 11px; background: var(--line-strong); }

.nav__cta {
  font-size: 11px; font-weight: 500; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--fg); border: 1px solid var(--line-strong);
  padding: 12px 26px; border-radius: var(--radius); white-space: nowrap;
  transition: background .35s var(--ease), color .35s var(--ease), border-color .35s var(--ease);
}
.nav__cta:hover { background: var(--fg); color: var(--ink); border-color: var(--fg); }

/* ============================================================
   SCRUB HERO
   362 frames · 2000vh. The height sets the pace, not the frame count:
   keeping it at 2000vh preserves the pacing while the canvas blends
   between the sparser frames.
   ============================================================ */
.scrub { position: relative; height: 1300vh; background: var(--bg); }
.scrub__stage { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; }
.scrub__canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.scrub__scrim {
  position: absolute; inset: 0; pointer-events: none;
  /* Lightened per the client: the film reads clearer, the veil only does
     what caption legibility strictly requires. */
  background:
    radial-gradient(ellipse 78% 62% at 50% 48%, rgba(30,22,20,0.12) 0%, rgba(30,22,20,0.24) 62%, rgba(30,22,20,0.38) 100%),
    linear-gradient(to top, rgba(30,22,20,0.55) 0%, rgba(30,22,20,0.10) 40%, rgba(30,22,20,0) 62%),
    linear-gradient(to bottom, rgba(30,22,20,0.32) 0%, rgba(30,22,20,0) 24%);
}

/* Loader */
.loader {
  position: absolute; inset: 0; z-index: 20;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 26px;
  background: var(--bg); transition: opacity .8s var(--ease), visibility .8s;
}
.loader.is-done { opacity: 0; visibility: hidden; }
.loader__brand { font-family: var(--serif); font-size: 22px; letter-spacing: 0.5em; padding-left: 0.5em; color: var(--fg); }
.loader__track { width: 180px; height: 1px; background: var(--line); overflow: hidden; }
.loader__bar { display: block; height: 100%; width: 0; background: var(--accent); transition: width .25s var(--ease); }
.loader__pct { font-size: 10px; letter-spacing: 0.24em; color: var(--muted); }

/* Beats */
.scrub__beat {
  position: absolute; left: var(--pad); bottom: clamp(72px, 14vh, 150px); z-index: 10;
  max-width: 780px; opacity: 0; will-change: opacity, transform;
}
.scrub__beat--center {
  /* flex centring: renderBeats owns the transform (fade offset), so the
     vertical centring must not live in transform */
  left: 0; right: 0; top: 0; bottom: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  max-width: none; text-align: center; padding: 0 var(--pad);
}
.scrub__eyebrow {
  font-size: 10px; font-weight: 400; letter-spacing: 0.44em; text-transform: uppercase;
  color: var(--fg); margin: 0 0 34px; padding-left: 0.44em;
  text-shadow: 0 1px 22px rgba(0,0,0,0.8);
}
.scrub__title {
  font-family: var(--serif); font-weight: 200;
  font-size: clamp(56px, 11vw, 156px); line-height: 1; letter-spacing: 0.14em;
  padding-left: 0.14em;
  color: var(--beige);
  filter: drop-shadow(0 2px 30px rgba(0,0,0,0.75));
}
.scrub__wordmark {
  font-size: clamp(10px, 1.1vw, 12px); font-weight: 300;
  letter-spacing: 0.52em; text-transform: uppercase; padding-left: 0.52em;
  color: var(--fg); margin: 26px 0 0;
  text-shadow: 0 1px 22px rgba(0,0,0,0.85);
}
.scrub__quote {
  font-family: var(--serif); font-weight: 200; font-style: italic;
  font-size: clamp(30px, 4.6vw, 66px); line-height: 1.2; color: var(--fg);
  margin: 0; max-width: 18ch;
  text-shadow: 0 2px 50px rgba(0,0,0,0.5);
}
.scrub__beat-title {
  font-family: var(--serif); font-weight: 200; line-height: 1.1;
  font-size: clamp(34px, 4.6vw, 56px); color: var(--fg);
  text-shadow: 0 2px 50px rgba(0,0,0,0.5);
}
.scrub__beat-title em { color: var(--fg); }
.scrub__beat-copy {
  font-size: 14px; color: var(--fg-soft);
  margin: 24px 0 0; max-width: 44ch; line-height: 1.75;
  text-shadow: 0 1px 20px rgba(0,0,0,0.5);
}
.scrub__beat .btn { margin-top: 34px; }

/* ============================================================
   MANIFESTO — gold fill on scroll
   White letterspaced caps; a gradient twin sits on top and is unclipped
   from the top down as --gf runs 0 to 1 (site.js, initGoldfill).
   ============================================================ */
.manifesto { position: relative; height: 230vh; background: var(--ink); }
.manifesto__sticky {
  position: sticky; top: 0; height: 100vh; height: 100svh;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 0 var(--pad);
  overflow: hidden;
}
/* The printed spread is not empty either: page 8 sets the gold block on a
   weave of vertical hairlines, and the back cover carries the radial grain.
   Both are reproduced here, held far back. */
.manifesto__sticky::before {
  content: ""; position: absolute; inset: -10%;
  background: url("assets/img/footer-texture.jpg") center / cover no-repeat;
  opacity: 0.5;
}
.goldfill { position: relative; z-index: 2; }
.goldfill {
  position: relative; margin: 0; width: 100%; max-width: 1500px;
  font-family: var(--serif); font-weight: 200;
  text-align: center;
  letter-spacing: 0.02em;
  font-size: clamp(24px, 3.4vw, 54px);
  line-height: 1.7;
}
.goldfill__base, .goldfill__over { display: block; }
/* The manifesto's supporting paragraph, under the gold-filling statement */
.manifesto__copy {
  position: relative; z-index: 2;
  margin: clamp(30px, 5vh, 54px) auto 0;
  max-width: 75ch; text-align: center;
  font-size: 14px; line-height: 1.9;
  color: var(--fg-soft);
}
.goldfill__base { color: var(--fg); }
.goldfill__over {
  position: absolute; inset: 0;
  color: var(--beige);
  /* the beige twin is revealed top-down as --gf runs 0 to 1 on scroll */
  clip-path: inset(0 0 calc(100% - var(--gf, 0) * 100%) 0);
}

/* ============================================================
   ENVIRO — the film that opens
   The stage is taller than the viewport; the film is stuck inside it and
   its clip-path margins close to zero as --vx runs 0 to 1, so the frame
   opens to full bleed mid-read, Apple style.
   ============================================================ */
.enviro { background: var(--bg); padding-top: clamp(100px, 15vh, 190px); }

/* ---- Counter-scroll gallery -------------------------------------------
   The block pins for its extra travel; initVlife slides column A up and
   column B down by the same distance, scrubbed by the scroll. */
.vlife { height: 180vh; }
.vlife__pin {
  position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden;
  display: grid; grid-template-columns: minmax(380px, 1.1fr) 1fr 1fr;
  /* one row locked to the pin: without it the implicit row grows to the
     tallest column (~2500px) and the centred text ends up off screen */
  grid-template-rows: 100%;
  gap: clamp(24px, 3vw, 56px);
  align-items: center;
  padding: 0 var(--pad);
  max-width: none;
}
.enviro__head { text-align: left; }
.enviro__title { font-size: clamp(30px, 4.5vw, 56px); line-height: 1.16; }
.vlife__col {
  display: flex; flex-direction: column; gap: clamp(16px, 2vw, 28px);
  will-change: transform; align-self: start;
}
.vlife__col figure { margin: 0; overflow: hidden; }
.vlife__col img { width: 100%; height: auto; display: block; }
/* Bottom padding gives back the film's initial 3vh clip inset, so the
   VISIBLE gap below the figures equals the gap above them. */
.figures {
  padding: clamp(36px, 6vh, 70px) var(--pad)
           max(14px, calc(clamp(36px, 6vh, 70px) - 3vh));
}
.figures__line {
  list-style: none; margin: 0; padding: 0;
  position: relative;
  display: flex; justify-content: space-between; gap: clamp(20px, 3vw, 40px);
  text-align: center;
}
/* Hairline segments BETWEEN the figures, level with the numerals; --sk
   (initStatsLine) still draws them in as the band climbs the viewport. */
.figures__sep {
  flex: 1 1 0; height: 1px; align-self: flex-start;
  margin-top: clamp(15px, 1.6vw, 23px);
  background: var(--line-strong);
  transform: scaleX(var(--sk, 0)); transform-origin: left center;
}
.stat { flex: 0 1 auto; }
.stat__num {
  display: block; font-family: var(--serif); font-weight: 200;
  font-size: clamp(30px, 3.2vw, 46px); line-height: 1; color: var(--fg);
}
.stat__unit { font-size: 0.5em; color: var(--beige); }
.stat__label {
  display: block; margin-top: 12px;
  font-size: 10px; font-weight: 400; letter-spacing: 0.26em; text-transform: uppercase;
  color: var(--muted);
}
.enviro__stage { position: relative; height: 130vh; margin-top: 0; }
.enviro__film {
  position: sticky; top: 0;
  width: 100%; height: 100vh; height: 100svh; object-fit: cover; display: block;
  /* full bleed on arrival: the frame-opening clip was retired */
}

/* ============================================================
   MATTER (architecture + materials)
   ============================================================ */
.matter { background: var(--bg); padding: clamp(100px, 15vh, 190px) var(--pad); }
.matter__inner {
  max-width: var(--maxw); margin: 0 auto;
  display: grid; grid-template-columns: 0.85fr 1fr; gap: clamp(40px, 7vw, 110px);
  align-items: start;
}

/* Sticky media column: the three renders are stacked and cross-faded, so the
   frame never moves while the chapters scroll past it. */
.matter__media {
  position: sticky; top: 12vh;
  aspect-ratio: 3 / 4; overflow: hidden; background: var(--bg-3);
}
.matter__shot {
  position: absolute; inset: 0; margin: 0;
  opacity: 0; transform: scale(1.04);
  transition: opacity 1s var(--ease), transform 1.6s var(--ease);
}
.matter__shot.is-on { opacity: 1; transform: none; }
.matter__shot img { width: 100%; height: 100%; object-fit: cover; }

.matter__text { max-width: 520px; }
.matter__title { font-size: clamp(30px, 4.5vw, 56px); line-height: 1.14; }

.chapter { padding: clamp(52px, 11vh, 110px) 0; border-bottom: 1px solid var(--line); }
.chapter:last-child { border-bottom: 0; }
.chapter__name {
  font-family: var(--sans); font-size: 10px; font-weight: 500;
  letter-spacing: 0.3em; text-transform: uppercase; color: var(--muted);
  margin: 0 0 20px; transition: color .6s var(--ease);
}
.chapter.is-on .chapter__name { color: var(--beige); }
.chapter__copy {
  margin: 0; font-size: 14px; line-height: 1.8;
  color: var(--muted); max-width: 52ch;
  transition: color .6s var(--ease);
}
.chapter.is-on .chapter__copy { color: var(--fg); }

/* ============================================================
   SURFACES
   ============================================================ */
.surfaces { background: var(--ink); padding: clamp(100px, 15vh, 190px) var(--pad); }
.surfaces__inner { max-width: var(--maxw); margin: 0 auto; }
.surfaces__head { text-align: center; }
/* This eyebrow reads white, per the client */
.surfaces__head .eyebrow { color: var(--fg); }
.surfaces__title {
  font-size: clamp(30px, 4.5vw, 56px); letter-spacing: 0.16em; padding-left: 0.16em;
  text-transform: uppercase;
  color: var(--beige);
}
.surfaces__grid {
  margin-top: clamp(50px, 8vh, 90px);
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(20px, 3vw, 40px);
  align-items: stretch;
}
.surface {
  border: 1px solid var(--line);
  padding: clamp(32px, 4vw, 56px);
  display: flex; flex-direction: column;
}
.surface--lead { background: var(--bg-2); border-color: var(--line-strong); }
.surface__name {
  font-family: var(--sans); font-size: 11px; font-weight: 500;
  letter-spacing: 0.28em; text-transform: uppercase; color: var(--fg);
  margin: 0 0 34px;
}
.surface__figure {
  font-family: var(--serif); font-weight: 200;
  font-size: clamp(40px, 5.6vw, 76px); line-height: 1.1; color: var(--fg);
  margin: 0;
}
.surface__figure span {
  font-family: var(--sans); font-size: 12px; font-weight: 300;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--beige);
  margin-left: 10px; vertical-align: middle;
}
.surface__figure--sub { font-size: clamp(28px, 3.6vw, 48px); color: var(--fg-soft); margin-top: 6px; }
.surface__note {
  font-family: var(--serif); font-style: italic; font-weight: 300;
  font-size: 20px; line-height: 1.7; color: var(--fg-soft);
  margin: 30px 0 0; max-width: 44ch;
}
.surface__list {
  list-style: none; margin: 26px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 9px;
}
.surface__list li {
  font-size: 13px; color: var(--fg-soft); letter-spacing: 0.03em;
  padding-left: 20px; position: relative;
}
.surface__list li::before {
  content: ""; position: absolute; left: 0; top: 0.72em;
  width: 8px; height: 1px; background: var(--beige);
}
.surface__actions { display: flex; flex-wrap: nowrap; align-items: stretch; gap: 10px; margin-top: auto; padding-top: 30px; }
/* Compact CTAs so both fit side by side, French labels included.
   The pair mixes an <a> and a <button>: margin, line-height and
   appearance are pinned so both boxes are strictly identical. */
.surface__actions .surface__cta {
  padding: 12px 16px; font-size: 10px; letter-spacing: 0.14em;
  flex: 0 1 auto; min-width: 0;
  margin: 0; line-height: 1; appearance: none; -webkit-appearance: none;
}
@media (max-width: 640px) {
  /* Lightbox: the image owns the full width; the arrows anchor to the
     bottom corners of the screen (absolute: the flex order + negative
     margin trick drifted whenever the caption wrapped) */
  .lightbox { flex-direction: column; gap: 14px; padding: 56px 14px 78px; }
  .lightbox__stage { max-width: 100%; order: 1; }
  .lightbox__stage img { max-height: 62vh; }
  .lightbox__arrow {
    width: 46px; height: 46px;
    position: absolute; bottom: max(18px, env(safe-area-inset-bottom));
  }
  .lightbox__arrow--prev { left: 14px; }
  .lightbox__arrow--next { right: 14px; }

  .surface__actions { flex-wrap: wrap; }
}
.surface__gallery { background: none; cursor: pointer; }
.surface__price {
  margin: 14px 0 0;
  font-family: var(--serif); font-weight: 200;
  font-size: clamp(20px, 2.2vw, 28px); line-height: 1.2;
  color: var(--beige);
}
.surfaces__legal {
  margin: 20px 0 0;
  font-size: 11px; letter-spacing: 0.08em;
  color: var(--muted);
}
.surface__cta { margin-top: 22px; align-self: flex-start;
  font-size: 10px; letter-spacing: 0.26em; text-transform: uppercase; color: var(--muted);
}
.surfaces__rarity {
  margin: clamp(40px, 6vh, 64px) 0 0; text-align: center;
  font-size: 11px; letter-spacing: 0.26em; text-transform: uppercase;
  color: var(--fg);
}

/* ============================================================
   PRIVATE QUARTERS (triptych)
   The three interiors the fly-through never walks through.
   ============================================================ */
.quarters { background: var(--bg); padding: clamp(100px, 15vh, 190px) 0; }
.quarters__title { font-size: clamp(30px, 4.5vw, 56px); line-height: 1.14; }
/* Arrow-driven carousel: the row slides one tile at a time (site.js,
   initStrips); every tile opens the lightbox. */
.quarters__inner { display: flex; flex-direction: column; gap: clamp(40px, 7vh, 72px); }
.quarters__head {
  padding: 0 var(--pad);
  display: flex; align-items: flex-end; justify-content: space-between; gap: 30px;
}
.quarters__nav { display: flex; gap: 10px; }
.strip__arrow {
  width: 52px; height: 52px; display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 1px solid var(--line-strong); color: var(--fg);
  font-size: 18px; cursor: pointer; border-radius: var(--radius);
  transition: background .35s var(--ease), color .35s var(--ease), opacity .35s var(--ease);
}
.strip__arrow:hover { background: var(--fg); color: var(--ink); }
.strip__arrow[disabled] { opacity: 0.3; pointer-events: none; }
.strip { padding-left: var(--pad); overflow: hidden; }
.strip__row {
  display: flex; gap: clamp(14px, 2vw, 24px);
  width: max-content; will-change: transform;
  transition: transform .7s var(--ease);
}
.tile { margin: 0; flex: 0 0 auto; width: clamp(240px, 26vw, 400px); cursor: pointer; }
.tile img {
  width: 100%; aspect-ratio: 3 / 4; object-fit: cover;
  background: var(--bg-3); display: block;
}
.tile figcaption {
  margin-top: 13px; font-size: 9px; letter-spacing: 0.24em;
  text-transform: uppercase; color: var(--fg);
}

/* ============================================================
   DAY TO NIGHT (scroll-driven dissolve, same camera position)
   site.js sets --dn from 0 (day) to 1 (night) across the section.
   ============================================================ */
.daynight { position: relative; height: 260vh; background: var(--ink); }
.daynight__stage { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; }
.daynight__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.daynight__img--night { opacity: var(--dn, 0); }
.daynight__scrim {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(to top, rgba(30,22,20,0.92) 0%, rgba(30,22,20,0.34) 42%, rgba(30,22,20,0) 68%),
    linear-gradient(to right, rgba(30,22,20,0.58) 0%, rgba(30,22,20,0.1) 55%, rgba(30,22,20,0) 85%);
}
.daynight__content {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 0 var(--pad) clamp(70px, 13vh, 130px);
}
.daynight__title { font-size: clamp(30px, 4.5vw, 56px); color: var(--fg); line-height: 1.14; text-shadow: 0 2px 40px rgba(0,0,0,0.55); }
.daynight__title em { text-shadow: none; }
.daynight__copy {
  font-size: 14px; color: var(--fg); max-width: 75ch;
  margin: 28px 0 0; line-height: 1.8; text-shadow: 0 1px 24px rgba(0,0,0,0.85);
}

/* ============================================================
   REGISTRY — the services ledger
   Serif rows on hairlines; on fine pointers a small image follows the
   cursor down the list. Rows without an image simply hide it.
   ============================================================ */
.registry { background: var(--bg); padding: clamp(110px, 17vh, 210px) var(--pad); }
.registry__inner { max-width: var(--maxw); margin: 0 auto; }
.registry__title { font-size: clamp(30px, 4.5vw, 56px); line-height: 1.18; }
.registry__lede { max-width: 71ch; }
.registry__list {
  list-style: none; margin: clamp(46px, 8vh, 88px) 0 0; padding: 0;
  border-top: 1px solid var(--line);
}
.entry { border-bottom: 1px solid var(--line); padding: clamp(30px, 5vh, 54px) 0; }
.entry__row {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  gap: clamp(20px, 4vw, 60px);
}
/* Rows without renders keep no phantom spacing below */
.entry__row:not(:last-child) { margin-bottom: clamp(20px, 3.5vh, 34px); }
/* Four renders per service, always visible */
.entry__media {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(10px, 1.6vw, 20px);
}
.entry__media img { width: 100%; height: auto; aspect-ratio: 3 / 4; object-fit: cover; }
.entry__name {
  margin: 0; font-family: var(--serif); font-weight: 200;
  font-size: clamp(26px, 3.4vw, 52px); color: var(--fg);
  transition: opacity .4s var(--ease);
}
.entry:hover .entry__name { color: var(--beige); }
.entry__copy {
  margin: 0; font-size: 14px; color: var(--fg-soft);
  max-width: 46ch; text-align: right;
}


/* ============================================================
   LIGHTBOX — full-size viewer for the interior renders
   ============================================================ */
.lightbox {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: center; justify-content: center; gap: 18px;
  background: rgba(20, 14, 12, 0.94);
  padding: clamp(16px, 4vh, 48px);
}
.lightbox[hidden] { display: none; }
.lightbox__stage { margin: 0; max-width: min(86vw, 1100px); max-height: 88vh; text-align: center; }
.lightbox__stage img {
  max-width: 100%; max-height: 80vh; width: auto; height: auto;
  margin: 0 auto; box-shadow: 0 30px 80px rgba(0,0,0,0.55);
}
.lightbox__stage figcaption {
  margin-top: 14px; font-size: 10px; letter-spacing: 0.26em; text-transform: uppercase;
  color: var(--fg-soft);
}
.lightbox__arrow, .lightbox__close {
  background: none; border: 1px solid var(--line-strong); color: var(--fg);
  width: 52px; height: 52px; display: inline-flex; align-items: center; justify-content: center;
  font-size: 18px; cursor: pointer;
  transition: background .3s var(--ease), color .3s var(--ease);
}
.lightbox__arrow:hover, .lightbox__close:hover { background: var(--fg); color: var(--ink); }
.lightbox__close { position: absolute; top: clamp(14px, 3vh, 30px); right: clamp(14px, 3vh, 30px); }

/* Pause control over the film */
.enviro__pause {
  position: absolute; right: clamp(18px, 3vw, 44px); bottom: clamp(18px, 4vh, 44px); z-index: 5;
  width: 52px; height: 52px; cursor: pointer;
  background: rgba(30, 22, 20, 0.55); border: 1px solid var(--line-strong);
  backdrop-filter: blur(8px);
  transition: background .3s var(--ease);
}
.enviro__pause::before {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 14px; height: 14px;
  background:
    linear-gradient(var(--fg), var(--fg)) left center / 4px 100% no-repeat,
    linear-gradient(var(--fg), var(--fg)) right center / 4px 100% no-repeat;
}
.enviro__pause[data-playing="false"]::before {
  background: none;
  border-left: 12px solid var(--fg); border-top: 7px solid transparent; border-bottom: 7px solid transparent;
  width: 0; height: 0;
}
.enviro__pause:hover { background: rgba(30, 22, 20, 0.85); }

/* ============================================================
   CONTACT
   ============================================================ */
.contact { position: relative; padding: clamp(100px, 15vh, 190px) var(--pad); overflow: hidden; }
.contact__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.contact__scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(to right, rgba(30,22,20,0.96) 0%, rgba(30,22,20,0.90) 46%, rgba(30,22,20,0.88) 100%),
    linear-gradient(to bottom, rgba(30,22,20,0.5) 0%, rgba(30,22,20,0) 26%);
}
.contact__inner {
  position: relative; z-index: 2;
  max-width: var(--maxw); margin: 0 auto;
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(40px, 7vw, 100px); align-items: start;
}
.contact__title { font-size: clamp(30px, 4.5vw, 56px); line-height: 1.2; }
.contact__copy { font-size: 14px; color: var(--fg-soft); max-width: 65ch; margin: 30px 0 0; }
.contact__direct { margin-top: clamp(36px, 5vh, 56px); }
.contact__row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 20px;
  padding: 18px 0; border-bottom: 1px solid var(--line);
  transition: padding-left .35s var(--ease);
}
.contact__row:not(.contact__row--static):hover { padding-left: 8px; }
.contact__label { font-size: 10px; letter-spacing: 0.24em; text-transform: uppercase; color: var(--muted); }
.contact__value { font-family: var(--serif); font-size: clamp(16px, 1.6vw, 20px); color: var(--fg); }

/* ---- Form ---- */
.form { display: grid; grid-template-columns: 1fr 1fr; gap: 22px 20px; }
.form__row { display: flex; flex-direction: column; justify-content: flex-end; gap: 8px; }  /* a wrapped label never pushes its field out of line */
.form__row--full { grid-column: 1 / -1; }
.form label {
  font-size: 10px; letter-spacing: 0.24em; text-transform: uppercase; color: var(--fg-soft);
}
.form input, .form select, .form textarea {
  font-family: var(--sans); font-size: 15px; font-weight: 300; color: var(--fg);
  background: rgba(244,241,237,0.05);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  padding: 14px 16px; width: 100%;
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
.form textarea { resize: vertical; min-height: 92px; }
.form select { appearance: none; cursor: pointer; }
.form select option { background: var(--ink); color: var(--fg); }
.form input:hover, .form select:hover, .form textarea:hover { border-color: var(--fg-soft); }
.form input:focus, .form select:focus, .form textarea:focus {
  outline: none; border-color: var(--accent-hi); background: rgba(244,241,237,0.08);
}
.form input[aria-invalid="true"], .form select[aria-invalid="true"], .form textarea[aria-invalid="true"] { border-color: #C9736A; }
.form__foot { grid-column: 1 / -1; display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.form__status { margin: 0; font-size: 13px; color: var(--accent-hi); }
.form__status.is-error { color: #D98A80; }

/* ============================================================
   FOOTER
   ============================================================ */
.footer {
  position: relative; overflow: hidden;
  background: var(--ink); padding: clamp(70px, 10vh, 120px) var(--pad) 44px;
}
/* The texture is already very dark, so it only needs holding back enough for
   the legal lines to stay legible over it. */
.footer__bg {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0.55;
}
.footer::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgba(30,22,20,0.55) 0%, rgba(30,22,20,0.8) 100%);
}
.footer > *:not(.footer__bg) { position: relative; z-index: 2; }
.footer__inner { max-width: var(--maxw); margin: 0 auto; text-align: center; padding-bottom: 54px; border-bottom: 1px solid var(--line); }
.footer__brand {
  font-family: var(--serif); font-weight: 200;
  font-size: clamp(34px, 4.6vw, 62px); letter-spacing: 0.2em; padding-left: 0.2em;
  color: var(--beige);
}
.footer__tagline {
  font-size: 10px; letter-spacing: 0.5em; text-transform: uppercase; padding-left: 0.5em;
  color: var(--muted); margin: 18px 0 0;
}
.footer__base {
  max-width: var(--maxw); margin: 34px auto 0;
  /* 1fr | auto | 1fr keeps the copyright on the true centre of the line,
     whatever the two side columns weigh */
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: start; gap: 20px;
}
.footer__base > .footer__legal { text-align: center; }
.footer__legal { font-size: 11px; letter-spacing: 0.04em; color: var(--muted); }
.footer__col { display: flex; flex-direction: column; gap: 8px; }
.footer__col--right { text-align: right; }
.footer__legal a {
  color: var(--muted); text-decoration: none;
  border-bottom: 1px solid rgba(142,130,123,0.35);
  transition: color 0.25s ease, border-color 0.25s ease;
}
.footer__legal a:hover { color: var(--fg); border-color: var(--fg); }

/* ============================================================
   SECTION OVERLAP
   Adapted from the sticky-stack pattern: there, every panel pins at the same
   top offset and they pile up. That needs panels shorter than the viewport,
   and these sections run 0.7 to 1.6 screens, so pinning would clip them.
   Same read, no clipping: each section is positioned, so it paints over its
   predecessor in DOM order, and a small negative margin plus a soft leading
   shadow makes it ride over the tail of the one before.
   The hero keeps its own bridge — its last frames already dissolve to --bg —
   so the overlap starts one section later.
   ============================================================ */
main > section { position: relative; }
main > section:not(#hero) + section {
  margin-top: calc(-1 * clamp(24px, 5vh, 64px));
  box-shadow: 0 -46px 70px -34px rgba(18, 12, 10, 0.8);
}

/* ============================================================
   CURSOR
   Fine pointers only: the native cursor is replaced by a copper dot and a
   trailing ring that swells over anything interactive. Form fields keep
   the native caret cursor, and everything reverts under reduced motion.
   ============================================================ */
@media (hover: hover) and (pointer: fine) {
  body.has-cursor, body.has-cursor a, body.has-cursor button,
  body.has-cursor .entry, body.has-cursor label { cursor: none; }
  body.has-cursor input, body.has-cursor textarea, body.has-cursor select { cursor: auto; }
}
.cursor { display: none; }
body.has-cursor .cursor { display: block; }
.cursor__dot, .cursor__ring {
  position: fixed; left: 0; top: 0; z-index: 400; pointer-events: none;
  border-radius: 999px;
}
.cursor__dot {
  width: 6px; height: 6px; margin: -3px 0 0 -3px;
  background: var(--accent-hi);
  transform: translate3d(var(--cx, -100px), var(--cy, -100px), 0);
}
.cursor__ring {
  width: 34px; height: 34px; margin: -17px 0 0 -17px;
  border: 1px solid rgba(200, 160, 128, 0.55);
  transform: translate3d(var(--rx, -100px), var(--ry, -100px), 0) scale(var(--rs, 1));
  transition: border-color .3s var(--ease);
}
.cursor.is-link .cursor__ring { border-color: rgba(200, 160, 128, 0.95); }
.cursor.is-hidden { opacity: 0; }

/* ============================================================
   REVEAL + MOTION LAYER
   ============================================================ */
.reveal, [data-reveal] { opacity: 0; transform: translateY(26px); transition: opacity 1s var(--ease), transform 1s var(--ease); }
.reveal.is-visible, [data-reveal].is-visible { opacity: 1; transform: none; }

.ml-reveal .ml-line { overflow: hidden; padding-bottom: 0.08em; margin-bottom: -0.08em; }
.ml-reveal .ml-line__inner {
  display: block; transform: translateY(110%);
  transition: transform 0.95s var(--ease); transition-delay: var(--ml-delay, 0s);
  will-change: transform;
}
.ml-reveal.is-shown .ml-line__inner { transform: translateY(0); }

/* NOTE: the engine's original hidden state for eyebrows was
   clip-path: inset(0 0 100% 0). That zeroes the element's intersection
   rectangle, so the IntersectionObserver that is supposed to reveal it
   never fires and the eyebrow stays invisible for good. Fade + translate
   instead: same effect, no deadlock. */
.ml-eyebrow { opacity: 0; transform: translateY(8px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }
.ml-eyebrow.is-shown { opacity: 1; transform: none; }

.stat__num.is-counting { font-variant-numeric: tabular-nums; }


/* Press feedback rides the same composed transform as the magnetic offset. */
.btn:active, .nav__cta:active { --press: 0.975; transition-duration: 0.12s; }

body.intro-ready .nav { opacity: 0; transform: translateY(-12px); }
body.intro-ready.is-loaded .nav {
  opacity: 1; transform: translateY(0);
  transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 1200px) {
}

@media (max-width: 1100px) {
  .nav__links { gap: 16px; }
  .nav__links a { font-size: 10px; letter-spacing: 0.14em; }
}

@media (max-width: 980px) {
  .matter__inner, .contact__inner { grid-template-columns: 1fr; gap: 44px; }
  /* One column: the sticky-band mechanic never behaved on real phones, so
     site.js moves each render inline above its own chapter and drops the
     media column entirely. Editorial reading: image, then its text. */
  .matter__media { display: none; }
  .chapter .matter__shot {
    position: static; inset: auto; margin: 0 0 26px;
    opacity: 1; transform: none;
    aspect-ratio: 3 / 4; overflow: hidden;
  }
  .chapter { padding: clamp(38px, 8vh, 64px) 0; }
  /* No is-on spotlight in the one-column reading: every chapter reads lit */
  .chapter__name { color: var(--beige); }
  .chapter__copy { color: var(--fg); }
  .figures__line { flex-wrap: wrap; justify-content: center; gap: 34px 40px; }
  .figures__sep { display: none; }
  .surfaces__grid { grid-template-columns: 1fr; }
  .nav__links { display: none; }
}

/* 820px = the JS isSmall breakpoint: below it the scrub renders a single static
   frame, so the hero must come back to one viewport height. */
@media (max-width: 820px) {
  /* Counter-scroll gallery relaxes into a plain spread: text, then the
     ten photos in two quiet columns. */
  .vlife { height: auto; }
  .vlife__pin {
    position: static; height: auto; overflow: visible;
    display: block;
    padding-top: 0;
  }
  .vlife__pin .enviro__head { margin-bottom: 34px; }
  /* One finger-swipeable lane, ~1.6 photos in view, native snap */
  .vlife__slider {
    display: flex; gap: 12px;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    margin: 0 calc(-1 * var(--pad));
    padding: 0 var(--pad);
    scrollbar-width: none;
  }
  .vlife__slider::-webkit-scrollbar { display: none; }
  .vlife__slider figure {
    margin: 0; flex: 0 0 62%;
    scroll-snap-align: start;
  }
  .vlife__slider img { width: 100%; height: auto; display: block; }
  .vlife__col { transform: none !important; }

  /* The phone gets the real scroll-scrub, just paced for flick scrolling:
     shorter than the desktop 2000vh but still a long, deliberate journey. */
  .scrub { height: 900vh; }
  .scrub__beat { max-width: none; right: var(--pad); }

  /* Interiors strip: arrows give way to a finger-swipeable lane with
     native snap, same gesture as the Val d'Isère slider. */
  .quarters__nav { display: none; }
  .strip {
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    scroll-padding-left: var(--pad);
    padding-right: var(--pad);
    scrollbar-width: none;
  }
  .strip::-webkit-scrollbar { display: none; }
  .strip__row { transition: none; transform: none !important; }
  .tile { width: 62vw; scroll-snap-align: start; }
}

@media (max-width: 640px) {
  .form { grid-template-columns: 1fr; }
  .footer__base { grid-template-columns: 1fr; text-align: center; justify-items: center; }
  .footer__col--right { text-align: center; }
  /* Keep the conversion path on phones: compact CTA instead of hiding it */
  .nav { gap: 12px; }
  .nav__cta { font-size: 9px; letter-spacing: 0.14em; padding: 10px 14px; white-space: nowrap; }
  .daynight { height: 200vh; }
  /* Service rows stack: name above copy; renders in 2 columns */
  .entry__row { grid-template-columns: 1fr; gap: 10px; }
  .entry__copy { text-align: left; max-width: none; }
  .entry__media { grid-template-columns: repeat(2, 1fr); }
  /* The photo behind the contact form fights the inputs at this width */
  .contact__scrim {
    background:
      linear-gradient(to bottom, rgba(30,22,20,0.96) 0%, rgba(30,22,20,0.92) 100%);
  }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; }
  html { scroll-behavior: auto; }
  /* The fly-through is user-driven (scroll = playhead), so it stays; only
     its autonomous easing is disabled in script.js. */
  .reveal, [data-reveal] { opacity: 1; transform: none; transition: none; }
  .ml-reveal .ml-line { overflow: visible; padding-bottom: 0; margin-bottom: 0; }
  .ml-reveal .ml-line__inner { transform: none !important; transition: none !important; }
  .ml-eyebrow { clip-path: none !important; opacity: 1 !important; transition: none !important; }
  .btn:active, .nav__cta:active { --press: 1; }
  body.intro-ready .nav { opacity: 1 !important; transform: none !important; transition: none !important; }
  .enviro__film { clip-path: none !important; }
  .btn, .nav__cta { transform: none !important; }
  .manifesto { height: auto; }
  /* relative, not static: the ::before texture (inset -10%) must keep this
     overflow-hidden box as its containing block or it widens the page */
  .manifesto__sticky { position: relative; height: auto; padding: clamp(120px, 20vh, 240px) var(--pad); }
  .goldfill__over { clip-path: none !important; }
  .figures__sep { transform: none !important; }
  .enviro__pause { display: none; }
  .matter__shot { transition: none !important; }
  .entry__media img { transition: none !important; }
  .vlife { height: auto; }
  .vlife__pin { position: static; height: auto; overflow: visible; align-items: start; grid-template-rows: auto auto; }
  .vlife__col { transform: none !important; }
  .strip__row { transition: none; }
  /* Show the lit facade rather than freezing the dissolve half way.
     Everything joins the flow: the 16:9 stage clipped the copy on phones,
     so the night render becomes a plain image and the text sits below it. */
  .daynight { height: auto; }
  .daynight__stage { position: static; height: auto; aspect-ratio: auto; overflow: visible; }
  .daynight__img { display: none; }
  .daynight__img--night {
    display: block; position: static; inset: auto;
    width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover;
    opacity: 1;
  }
  .daynight__scrim { display: none; }
  .daynight__content { position: static; padding: clamp(40px, 8vh, 80px) var(--pad); }
}
