/* IJWestern — Landing
   Visual system: light-mode, parchment whites, survey ink, single accent of laterite gold.
   Typography: Inter only — Regular 400, Semi-bold 600, Bold 700.
   Light 300 left the site in step 2; nothing uses it and it is no
   longer requested. */

:root {
  --ground-white: #F7F4EF;
  --survey-ink: #1A1916;
  --laterite-gold: #B8832A;
  --laterite-gold-deep: #8E6620;
  --stone-surface: #EDE9E2;
  /* The hero photograph's sky is blown to pure white — sampled #FFFFFF
     across the whole top band — so the band the frame sits in is pure
     white too, and the image reads as a window rather than as a card
     laid on parchment. This is the one white on the site that is not
     --ground-white, and it is used only by .hero and its scrim. */
  --hero-sky-white: #FFFFFF;
  --contour-gray: #857F77;
  --contour-gray-soft: #C8C2BA;
  --forest-mist: #D8E8D4;
  --ghats-deep: #2D5235;

  --font-inter: "Inter", system-ui, -apple-system, "Segoe UI", Roboto,
                "Helvetica Neue", Arial, sans-serif;
  /* One family, per the client decision. The role tokens below are kept
     as aliases: every font-family in both stylesheets already goes
     through one of them, so the swap happens here and nowhere else. */
  --font-display: var(--font-inter);
  --font-body: var(--font-inter);
  --font-mono: var(--font-inter);
  --font-eyebrow: var(--font-inter);
  /* Was SF Pro (rejected on licensing); kept as an alias so the one rule
     that uses it needs no change. */
  --font-sf: var(--font-inter);

  /* ── Type scale (step 2) ─────────────────────────────────────────
     Three weights and six sizes, and nothing outside them. Every
     font-weight and every fixed font-size in all three stylesheets
     goes through a token below — if you are about to write a literal,
     add a token instead. Legibility was the brief: the whole fixed
     ramp came up roughly 2px, and Light 300 is gone.

     --fw-display and --fw-accent move together and are the one open
     choice in this step. The headlines carry an emphasis span (the
     `em` inside them) that has read as a weight step since step 1 of
     the revamp — gold was tried there and rejected — so the accent has
     to stay one notch above whatever the headline is:

       Option A, bold:      display 700, accent 800
       Option B, semi-bold: display 600, accent 700

     Flip the two lines below and the whole site follows. */
  --fw-display: 700;
  --fw-accent:  800;
  --fw-bold:    700;
  --fw-strong:  600;
  --fw-body:    400;

  --fs-micro:   12px;   /* uppercase keys and eyebrows   (was 10, 10.5) */
  --fs-label:   13px;   /* tags, table heads, small keys (was 11, 11.5) */
  --fs-meta:    14px;   /* meta rows, chips, crumbs      (was 12, 12.5) */
  --fs-ui:      15px;   /* nav, buttons, footer links    (was 13, 13.5) */
  --fs-body-s:  16px;   /* secondary body, descriptions  (was 14, 14.5) */
  --fs-body:    17px;   /* lead paragraphs, prose, inputs(was 15, 15.5) */

  /* Headline metrics by size band. Bold Inter is wider than Light, so
     the tracking is tighter than it was and the leading is looser —
     0.94 was survivable at 300 and collides at 700. */
  --lh-display: 0.98;  --ls-display: -0.03em;    /* 40px and up */
  --lh-heading: 1.04;  --ls-heading: -0.026em;   /* 24 to 39px  */
  --lh-card:    1.1;   --ls-card:    -0.02em;    /* 17 to 23px  */

  --max-w: 1440px;
  --gutter: clamp(20px, 4vw, 64px);

  /* Floating header: gap from viewport top, pill height, logo height.
     Hero spacing is derived from these — change here, not in .hero. */
  --topbar-gap: clamp(12px, 1.4vw, 20px);
  --topbar-h: 56px;
  /* The brand pill sits a little taller than the other two header
     pieces at rest, per the client, and collapses to --coin on scroll. */
  --brand-pill-h: 64px;
  --brand-logo-h: 48px;
  /* The mark is a portrait shape, so its bubble is a rounded tile, not
     a pill — a pill's semicircular ends fought the tall block. The
     condensed tile keeps the same corner ratio at the smaller size. */
  --brand-bubble-r: 18px;
  --brand-bubble-r-sm: 13px;
  /* Collapsed header pill diameter. */
  --coin: 48px;

  /* One corner radius for every image surface on the site. Media goes
     through these three and never through a literal, so the rounding
     stays consistent across styles.css, project.css and projects.css. */
  --radius-media-sm: 12px;
  --radius-media:    18px;
  --radius-media-lg: 24px;
  --rule: 1px solid color-mix(in oklab, var(--survey-ink) 12%, transparent);
  --rule-strong: 1px solid color-mix(in oklab, var(--survey-ink) 22%, transparent);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--ground-white);
  color: var(--survey-ink);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  font-feature-settings: "ss01", "cv11";
  text-rendering: optimizeLegibility;
}

img { display: block; max-width: 100%; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }

/* ─── Type scale ───────────────────────────────────────────────── */
.t-display {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-style: normal;
  letter-spacing: var(--ls-display);
  line-height: var(--lh-display);
  text-wrap: balance;
}

.t-lead {
  font-family: var(--font-body);
  font-size: clamp(17px, 1vw + 9px, 20px);
  line-height: 1.55;
  color: color-mix(in oklab, var(--survey-ink) 78%, transparent);
  text-wrap: pretty;
  max-width: 50ch;
  font-weight: var(--fw-body);
}

.t-label {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--contour-gray);
  font-weight: var(--fw-strong);
}

.t-mono {
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: 0.02em;
  color: var(--survey-ink);
  font-weight: var(--fw-strong);
}

.t-section-title {
  font-family: var(--font-display);
  font-size: clamp(48px, 7vw, 112px);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  font-weight: var(--fw-display);
}

/* The phase qualifier inside a project title. Sized in em so it scales
   with whatever heading it lands in — 27px card name, 76px project h1,
   84px launch headline all get the same proportion. Regular weight
   against the heading's bold is what makes it read as a qualifier
   rather than as more title. */
.pname-phase {
  /* em-scaled, with a floor: 0.46em of the 24px card name is 11px, which
     fell below the 14px location line sitting under it and undid step 2's
     whole point. The floor is --fs-label, so the qualifier never drops
     out of the legible range on the smallest title it appears in. */
  font-size: max(var(--fs-label), 0.46em);
  font-weight: var(--fw-body);
  letter-spacing: 0.002em;
  margin-left: 0.36em;
  white-space: nowrap;
  color: color-mix(in oklab, currentColor 74%, transparent);
}

/* ─── Frame & shell ───────────────────────────────────────────── */
.shell {
  max-width: var(--max-w);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.rule-top { border-top: var(--rule); }
.rule-bottom { border-bottom: var(--rule); }

/* ─── Top bar — floating glass pill ───────────────────────────────
   The bar itself is a transparent fixed layer; only the nav is glass.
   Logo sits outside it to the left, CTA outside it to the right. */
.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  padding: var(--topbar-gap) var(--gutter) 0;
  /* The layer spans full width but is mostly empty — let clicks reach
     the page beneath, and re-enable them on the three real children. */
  pointer-events: none;
}
.topbar-inner {
  position: relative;
  max-width: var(--max-w);
  margin: 0 auto;
  /* Logo and CTA are pushed to the edges; the pill is centred out of flow
     below, so neither side's width can shift it off centre. */
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: clamp(12px, 2vw, 28px);
  /* The pill no longer contributes height — hold the row open ourselves so
     the hero's --topbar-h offset stays accurate. */
  min-height: var(--topbar-h);
}
.topbar-inner > * { pointer-events: auto; }

.brand-mark {
  display: inline-flex;
  align-items: center;
  gap: 0;
  white-space: nowrap;
  /* The same glass as the nav pill. Without it the mark was a bare 42px
     shape next to a glass pill and a solid gold button — three pieces
     with nothing in common, and no guaranteed contrast once a photo or
     an ink band scrolled under it. */
  height: var(--brand-pill-h);
  padding: 0 16px;
  border-radius: var(--brand-bubble-r);
  backdrop-filter: blur(20px) saturate(1.7);
  -webkit-backdrop-filter: blur(20px) saturate(1.7);
  background: color-mix(in oklab, var(--ground-white) 55%, transparent);
  border: 1px solid color-mix(in oklab, var(--survey-ink) 9%, transparent);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.8) inset,
    0 10px 26px -22px rgba(26, 25, 22, 0.30),
    0 2px 8px -6px rgba(26, 25, 22, 0.10);
  transition: background 0.3s ease, border-color 0.3s ease;
}
.brand-mark:hover {
  background: color-mix(in oklab, var(--ground-white) 72%, transparent);
  border-color: color-mix(in oklab, var(--survey-ink) 16%, transparent);
}

.brand-logo {
  height: var(--brand-logo-h);
  width: auto;
  /* Override the global img{max-width:100%} — inside an auto-width flex
     parent it resolves circularly and collapses the logo to 0. */
  max-width: none;
  flex: none;
  display: block;
  /* Sits above the wordmark so the text reads as sliding out from behind it. */
  position: relative;
  z-index: 1;
}

/* Wordmark. Hover-initiated at every scroll position, per the client:
   the pill widens to take it rather than the name sitting there. The
   inner padding is inside the clipped box so it vanishes with the
   text. */
.brand-word {
  display: block;
  overflow: hidden;
  max-width: 0;
  flex: none;
  transition: max-width 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.brand-word > span {
  display: block;
  padding: 0 6px 0 11px;
  font-family: var(--font-sf);
  font-weight: var(--fw-bold);
  font-size: var(--fs-body);
  letter-spacing: -0.015em;
  line-height: 1;
  color: var(--survey-ink);
  white-space: nowrap;
  opacity: 0;
  transform: translateX(-10px);
  transition: opacity 0.3s ease,
              transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.brand-mark:hover .brand-word,
.brand-mark:focus-visible .brand-word,
.brand-mark:focus-within .brand-word { max-width: 300px; }
.brand-mark:hover .brand-word > span,
.brand-mark:focus-visible .brand-word > span,
.brand-mark:focus-within .brand-word > span {
  opacity: 1;
  transform: translateX(0);
}

.brand-mark .stroke {
  height: 16px; width: 1px;
  background: color-mix(in oklab, var(--survey-ink) 25%, transparent);
}
.brand-mark .sub {
  font-family: var(--font-eyebrow);
  font-size: var(--fs-micro);
  font-weight: var(--fw-strong);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--contour-gray);
  white-space: nowrap;
}

/* The glass pill — centred on the container, independent of the
   logo and CTA widths (and of the wordmark expanding on hover). */
.nav {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: clamp(4px, 0.8vw, 14px);
  height: var(--topbar-h);
  padding: 0 clamp(12px, 1.4vw, 22px);
  border-radius: 999px;
  white-space: nowrap;
  backdrop-filter: blur(20px) saturate(1.7);
  -webkit-backdrop-filter: blur(20px) saturate(1.7);
  background: color-mix(in oklab, var(--ground-white) 55%, transparent);
  border: 1px solid color-mix(in oklab, var(--survey-ink) 9%, transparent);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.8) inset,
    0 10px 26px -22px rgba(26, 25, 22, 0.30),
    0 2px 8px -6px rgba(26, 25, 22, 0.10);
}
.nav-link {
  position: relative;
  font-size: var(--fs-ui);
  letter-spacing: 0.01em;
  color: color-mix(in oklab, var(--survey-ink) 72%, transparent);
  padding: 0 10px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition: color 0.25s;
  font-weight: var(--fw-strong);
  /* Own stacking context, so the ::after box below can sit at z-index
     -1 — above this link's own ground and below its label — without
     falling behind the glass nav's background. */
  isolation: isolate;
}
/* Hover and current-page state is an ink box behind the label (client,
   4 Sep), replacing the gold rule that used to wipe in under it. The
   box grows out of the label's own centre with a little overshoot in
   the easing, rather than fading in flat.

   The geometry is deliberately unchanged — same 10px padding, same
   34px height — because the nav pill's width is measured against the
   brand tile and the header CTA (step 9, the 900px menu range), and
   padding the links out to make room for the box would put that back
   into overlap.

   11px matches the rounded rows the mobile menu panel already uses, so
   the two states of the same link are the same shape. The nav pill and
   the CTA stay pills; this is a box inside a pill on purpose. */
.nav-link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 11px;
  background: var(--survey-ink);
  opacity: 0;
  transform: scale(0.72);
  transition: opacity 0.26s ease,
              transform 0.34s cubic-bezier(0.34, 1.3, 0.5, 1);
}
.nav-link:hover,
.nav-link.active { color: var(--ground-white); }
.nav-link:hover::after,
.nav-link.active::after { opacity: 1; transform: scale(1); }
.topbar-right {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 18px;
}

/* ── Header over a dark section ────────────────────────────────────
   The three floating pieces are light glass, which over the ink bands
   (new launch, the project CTA, the footer) read as light stickers laid
   on the page. `on-dark` is set from JS when a [data-ground="dark"]
   section is under the header's own band, and flips the glass rather
   than the geometry, so nothing moves as it crosses the boundary. */
.topbar.on-dark .brand-mark,
.topbar.on-dark .nav {
  background: color-mix(in oklab, var(--survey-ink) 52%, transparent);
  border-color: color-mix(in oklab, var(--ground-white) 18%, transparent);
  box-shadow:
    0 1px 0 color-mix(in oklab, var(--ground-white) 14%, transparent) inset,
    0 12px 30px -24px rgba(0, 0, 0, 0.75);
}
.topbar.on-dark .brand-mark:hover {
  background: color-mix(in oklab, var(--survey-ink) 68%, transparent);
  border-color: color-mix(in oklab, var(--ground-white) 30%, transparent);
}
.topbar.on-dark .brand-word > span { color: var(--ground-white); }
.topbar.on-dark .brand-mark .stroke {
  background: color-mix(in oklab, var(--ground-white) 30%, transparent);
}
.topbar.on-dark .brand-mark .sub,
.topbar.on-dark .nav-link {
  color: color-mix(in oklab, var(--ground-white) 72%, transparent);
}
/* Over an ink band the pill is dark glass, so an ink box would be
   invisible in it — the box inverts and the label goes back to ink. */
.topbar.on-dark .nav-link::after { background: var(--ground-white); }
.topbar.on-dark .nav-link:hover,
.topbar.on-dark .nav-link.active { color: var(--survey-ink); }
.topbar.on-dark .phone-link {
  color: color-mix(in oklab, var(--ground-white) 78%, transparent);
}
/* The gold CTA needs no new colour, but its white inner highlights are
   tuned for a light ground and glare against ink. */
.topbar.on-dark .btn-primary {
  box-shadow:
    0 1px 0 color-mix(in oklab, white 22%, transparent) inset,
    0 0 0 1px color-mix(in oklab, white 10%, transparent) inset,
    0 2px 12px -6px rgba(0, 0, 0, 0.6);
}

.phone-link {
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: 0.02em;
  color: color-mix(in oklab, var(--survey-ink) 78%, transparent);
  transition: color 0.2s;
  white-space: nowrap;
  font-weight: var(--fw-strong);
}
.phone-link:hover { color: var(--laterite-gold); }

@media (max-width: 1280px) {
  .brand-mark .stroke,
  .brand-mark .sub { display: none; }
}

/* The wordmark adds ~170px to the pill, which at 768 collided with the
   centred nav pill and at 390 pushed the CTA off screen entirely (the
   header is fixed, so that overflow never showed up in a document-width
   check — it just clipped). Mark only below 900. */
@media (max-width: 900px) {
  /* Hover-expanded, the pill would run into the centred nav pill here,
     and the mark alone is the whole lockup at this size anyway. */
  .brand-word { display: none; }
  .brand-mark { padding: 0 15px; }
}

/* ── Condensed header: three coins ─────────────────────────────────
   Past 80px of scroll the three pieces collapse to same-size glass
   coins and expand again on hover, focus or tap. Nothing here animates
   `width` — each pill is width:auto and the collapsing child carries a
   max-width transition, which is the only way this stays smooth. The
   spacing that would otherwise show beside a collapsed child lives as
   padding *inside* the clipped box, so it disappears with it.

   Collapsed diameters all resolve to --coin. The mark is a portrait
   shape — 28px tall is 15.75px wide — so its padding is set from the
   width, not the height: 15.75 + 2x16. The menu coin is 48 square, and
   the CTA is a 22px arrow + 2x12 inside a 1px border. */
.topbar.is-condensed .brand-mark,
.topbar.is-condensed .nav,
.topbar.is-condensed .btn-compact { height: var(--coin); }

.topbar.is-condensed .brand-mark { padding: 0 16px; border-radius: var(--brand-bubble-r-sm); }
.topbar.is-condensed .brand-logo { height: 28px; }
.topbar.is-condensed .brand-mark:hover,
.topbar.is-condensed .brand-mark:focus-visible { padding: 0 16px 0 14px; }

/* Menu. The coin stays put as the links open beside it, so there is an
   anchor for the eye rather than an icon that swaps for a list. */
.nav-coin {
  display: none;
  width: var(--coin);
  height: var(--coin);
  flex: none;
  align-items: center;
  justify-content: center;
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  color: color-mix(in oklab, var(--survey-ink) 78%, transparent);
  transition: color 0.3s ease;
}
.nav-coin:hover { color: var(--survey-ink); }
.nav-coin .bar {
  display: block;
  height: 1.5px;
  border-radius: 2px;
  background: currentColor;
  transition: width 0.4s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.nav-coin .bars { display: grid; gap: 4px; justify-items: start; }
.nav-coin .bar:nth-child(1) { width: 16px; }
.nav-coin .bar:nth-child(2) { width: 11px; }
.nav-coin .bar:nth-child(3) { width: 14px; }
.nav:hover .nav-coin .bar,
.nav:focus-within .nav-coin .bar,
.nav.is-open .nav-coin .bar { width: 16px; }

.nav-items {
  display: inline-flex;
  align-items: center;
  gap: clamp(4px, 0.8vw, 14px);
}
.topbar.is-condensed .nav { padding: 0; gap: 0; }
.topbar.is-condensed .nav-coin { display: inline-flex; }
.topbar.is-condensed .nav-items {
  max-width: 0;
  min-width: 0;
  overflow: hidden;
  transition: max-width 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.topbar.is-condensed .nav:hover .nav-items,
.topbar.is-condensed .nav:focus-within .nav-items,
.topbar.is-condensed .nav.is-open .nav-items { max-width: 560px; }
.topbar.is-condensed .nav:hover,
.topbar.is-condensed .nav:focus-within,
.topbar.is-condensed .nav.is-open { padding-right: 16px; }

/* CTA. Gold glass rather than solid gold once it is a coin — solid gold
   at 48px over a photograph read as a dot of paint. */
.topbar.is-condensed .btn-primary {
  background: color-mix(in oklab, var(--laterite-gold) 74%, transparent);
  backdrop-filter: blur(20px) saturate(1.5);
  -webkit-backdrop-filter: blur(20px) saturate(1.5);
  border-color: color-mix(in oklab, white 26%, transparent);
}
.topbar.is-condensed .btn-primary:hover {
  background: color-mix(in oklab, var(--laterite-gold) 88%, transparent);
}
.topbar.is-condensed .btn-compact { padding: 0 12px; gap: 0; }
.topbar.is-condensed .cta-label {
  display: block;
  max-width: 0;
  min-width: 0;
  overflow: hidden;
  transition: max-width 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.topbar.is-condensed .cta-label > span {
  display: block;
  padding-right: 10px;
  white-space: nowrap;
}
.topbar.is-condensed .topbar-right:hover .cta-label,
.topbar.is-condensed .topbar-right:focus-within .cta-label { max-width: 220px; }
.topbar.is-condensed .topbar-right:hover .btn-compact,
.topbar.is-condensed .topbar-right:focus-within .btn-compact { padding-left: 17px; }

.topbar .brand-mark,
.topbar .nav,
.topbar .btn-compact {
  transition: background 0.3s ease, border-color 0.3s ease,
              height 0.45s cubic-bezier(0.2, 0.7, 0.2, 1),
              padding 0.45s cubic-bezier(0.2, 0.7, 0.2, 1),
              border-radius 0.45s cubic-bezier(0.2, 0.7, 0.2, 1),
              box-shadow 0.3s ease;
}

@media (prefers-reduced-motion: reduce) {
  .topbar .brand-mark, .topbar .nav, .topbar .btn-compact,
  .nav-items, .cta-label, .brand-word, .brand-word > span,
  .nav-coin, .nav-coin .bar { transition: none !important; }
}

/* ─── Buttons ─────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  height: 50px;
  padding: 0 22px;
  font-size: var(--fs-ui);
  font-weight: var(--fw-bold);
  letter-spacing: 0.01em;
  border: 1px solid var(--survey-ink);
  border-radius: 999px;
  transition: background 0.3s cubic-bezier(0.2, 0.7, 0.2, 1),
              color 0.3s, border-color 0.3s,
              transform 0.3s, box-shadow 0.3s;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  white-space: nowrap;
}
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(180deg,
    color-mix(in oklab, white 50%, transparent) 0%,
    transparent 45%,
    color-mix(in oklab, black 12%, transparent) 100%);
  opacity: 0.45;
  pointer-events: none;
  transition: opacity 0.3s;
}
.btn:hover { transform: translateY(-1px); }
.btn:hover::before { opacity: 0.65; }
.btn:active { transform: translateY(0); }

.btn .arrow {
  display: inline-flex;
  width: 24px; height: 24px;
  align-items: center; justify-content: center;
  border-radius: 999px;
  background: currentColor;
  transition: transform 0.3s cubic-bezier(0.2, 0.7, 0.2, 1), background 0.3s;
  position: relative;
  z-index: 1;
}
.btn .arrow svg { color: var(--ground-white); }
.btn:hover .arrow { transform: rotate(-45deg) translate(2px, 0); }

.btn-compact { height: 42px; padding: 0 16px; font-size: var(--fs-meta); gap: 10px; }
.btn-compact .arrow { width: 22px; height: 22px; }

/* Primary — gold "Laterite" CTA — white type, soft inner glass */
.btn-primary {
  background: var(--laterite-gold);
  color: var(--ground-white);
  border-color: color-mix(in oklab, var(--laterite-gold) 80%, var(--survey-ink));
  box-shadow:
    0 1px 0 color-mix(in oklab, white 55%, transparent) inset,
    0 0 0 1px color-mix(in oklab, white 18%, transparent) inset,
    0 8px 24px -10px color-mix(in oklab, var(--laterite-gold) 70%, transparent),
    0 2px 4px rgba(26, 25, 22, 0.18);
}
.btn-primary .arrow { background: rgba(255,255,255,0.18); }
.btn-primary .arrow svg { color: var(--ground-white); }
.btn-primary:hover {
  background: color-mix(in oklab, var(--laterite-gold) 92%, black);
  box-shadow:
    0 1px 0 color-mix(in oklab, white 60%, transparent) inset,
    0 0 0 1px color-mix(in oklab, white 22%, transparent) inset,
    0 12px 32px -10px color-mix(in oklab, var(--laterite-gold) 80%, transparent),
    0 4px 8px rgba(26, 25, 22, 0.25);
}

/* Glass variant — adds a backdrop blur (useful on photo / dark backgrounds) */
.btn-glass {
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
}

/* ─── Buy now (client, 3 Nov 2026) ───────────────────────────────
   One CTA, three homes: the project hero (a <button>, 50px), and the
   home and projects-index cards (a <span> inside the card's own link,
   `.buy-sm`, 40px). Markup is BuyNowInner in components.jsx.

   At rest it is the site's gold pill. On hover, in order:
     - ink floods in from the tag icon outward (clip-path circle),
     - the tag swings on its hole,
     - the label rolls up and its copy rolls in from below,
     - a light sheen crosses the pill,
     - the coin turns gold and the arrow flies out top-right and comes
       back in from bottom-left,
     - the pill lifts 2px; pressing it sinks it.
   "Active" means hovered, keyboard-focused, or inside a focused link. */
.buy {
  --buy-h: 50px;
  --buy-ease: cubic-bezier(.65, 0, .25, 1);
  --buy-pop: cubic-bezier(.2, .8, .2, 1);
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: var(--buy-h);
  padding: 0 7px 0 18px;
  border-radius: 999px;
  border: 1px solid color-mix(in oklab, var(--laterite-gold) 80%, var(--survey-ink));
  background: var(--laterite-gold);
  color: var(--ground-white);
  font-family: var(--font-body);
  font-size: var(--fs-ui);
  font-weight: var(--fw-bold);
  letter-spacing: 0.01em;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  box-shadow:
    0 1px 0 color-mix(in oklab, white 55%, transparent) inset,
    0 8px 24px -10px color-mix(in oklab, var(--laterite-gold) 70%, transparent),
    0 2px 4px rgba(26, 25, 22, 0.18);
  transition: transform .45s var(--buy-pop), box-shadow .45s var(--buy-pop),
              border-color .45s ease;
  -webkit-tap-highlight-color: transparent;
}
.buy-sm {
  --buy-h: 40px;
  gap: 8px;
  padding: 0 5px 0 14px;
  font-size: var(--fs-meta);
}

.buy-fill {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--survey-ink);
  clip-path: circle(0% at 26px 50%);
  transition: clip-path .6s var(--buy-ease);
}
.buy-sm .buy-fill { clip-path: circle(0% at 21px 50%); }

.buy-sheen {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(105deg, transparent 30%,
    color-mix(in oklab, white 34%, transparent) 50%, transparent 70%);
  transform: translateX(-130%);
  pointer-events: none;
}

.buy-ic { display: inline-flex; flex: none; transform-origin: 68% 32%; }

.buy-label {
  position: relative;
  flex: none;
  display: inline-block;
  overflow: hidden;
  height: 1.25em;
  line-height: 1.25em;
}
.buy-label > span {
  display: block;
  transition: transform .5s var(--buy-ease);
}
.buy-label > span::after {
  content: attr(data-t);
  position: absolute;
  left: 0;
  top: 100%;
}

.buy-coin {
  display: grid;
  place-items: center;
  width: calc(var(--buy-h) - 14px);
  height: calc(var(--buy-h) - 14px);
  margin-left: 2px;
  border-radius: 999px;
  overflow: hidden;
  flex: none;
  background: color-mix(in oklab, white 22%, transparent);
  transition: background .45s ease, transform .45s var(--buy-pop);
}
.buy-sm .buy-coin { width: 30px; height: 30px; }
.buy-coin svg { display: block; }

/* Active */
:is(.buy:hover, .buy:focus-visible, a:focus-visible .buy) {
  transform: translateY(-2px);
  border-color: var(--survey-ink);
  box-shadow:
    0 1px 0 color-mix(in oklab, white 30%, transparent) inset,
    0 14px 30px -12px rgba(26, 25, 22, .55),
    0 4px 8px rgba(26, 25, 22, .22);
}
:is(.buy:hover, .buy:focus-visible, a:focus-visible .buy) .buy-fill {
  clip-path: circle(150% at 26px 50%);
}
:is(.buy:hover, .buy:focus-visible, a:focus-visible .buy) .buy-sheen {
  transform: translateX(130%);
  transition: transform .9s var(--buy-ease) .12s;
}
:is(.buy:hover, .buy:focus-visible, a:focus-visible .buy) .buy-ic {
  animation: buySwing .9s var(--buy-pop);
}
:is(.buy:hover, .buy:focus-visible, a:focus-visible .buy) .buy-label > span {
  transform: translateY(-100%);
}
:is(.buy:hover, .buy:focus-visible, a:focus-visible .buy) .buy-coin {
  background: var(--laterite-gold);
}
:is(.buy:hover, .buy:focus-visible, a:focus-visible .buy) .buy-coin svg {
  animation: buyArrow .6s var(--buy-ease);
}
.buy:active { transform: translateY(0) scale(.97); transition-duration: .15s; }
.buy:focus-visible { outline: 2px solid var(--laterite-gold); outline-offset: 3px; }

@keyframes buySwing {
  0% { transform: rotate(0); }
  30% { transform: rotate(-16deg); }
  60% { transform: rotate(9deg); }
  80% { transform: rotate(-4deg); }
  100% { transform: rotate(0); }
}
@keyframes buyArrow {
  0%   { transform: translate(0, 0); }
  45%  { transform: translate(160%, -160%); }
  46%  { transform: translate(-160%, 160%); }
  100% { transform: translate(0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .buy, .buy-fill, .buy-label > span, .buy-coin { transition: none; }
  .buy-sheen { display: none; }
  :is(.buy:hover, .buy:focus-visible, a:focus-visible .buy) { transform: none; }
  :is(.buy:hover, .buy:focus-visible, a:focus-visible .buy) .buy-ic,
  :is(.buy:hover, .buy:focus-visible, a:focus-visible .buy) .buy-coin svg { animation: none; }
  .buy:active { transform: none; }
}

/* Secondary — outlined, fills with ink on hover */
.btn-secondary {
  background: color-mix(in oklab, var(--ground-white) 35%, transparent);
  color: var(--survey-ink);
  border-color: color-mix(in oklab, var(--survey-ink) 75%, transparent);
  backdrop-filter: blur(10px) saturate(1.3);
  -webkit-backdrop-filter: blur(10px) saturate(1.3);
}
.btn-secondary .arrow { background: var(--survey-ink); }
.btn-secondary .arrow svg { color: var(--ground-white); }
.btn-secondary:hover {
  background: var(--survey-ink);
  color: var(--ground-white);
  border-color: var(--survey-ink);
}
.btn-secondary:hover .arrow { background: var(--laterite-gold); }

.btn[disabled] { opacity: 0.55; pointer-events: none; }

.btn-ghost {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  font-size: var(--fs-ui);
  letter-spacing: 0.01em;
  border-bottom: 1px solid currentColor;
  border-radius: 0;
}
.btn-ghost:hover { color: var(--laterite-gold); }

/* ─── Hero ────────────────────────────────────────────────────── */
/* Step 10 (4 Sep 2026) — one photograph, held at viewport height.

   The section is exactly the viewport tall (svh, so a phone's
   collapsing address bar cannot make it taller than the screen) and
   the frame inside it is inset on all four sides: clear of the
   floating header above, and off both edges and the foot. Nothing of
   the portfolio below shows under it, which is the point of the step.

   --hero-top is derived from the header rather than typed. The brand
   tile is the tallest piece in the bar and it is centred on a shorter
   --topbar-h row, so the bar's real bottom edge is
   --topbar-gap + (--brand-pill-h + --topbar-h) / 2; taking the whole
   tile height instead is deliberately generous, and the third term is
   the clearance under it. Change a header token and this follows.

   The copy stands on the photograph's blown-out sky — headline left,
   lead right, the one CTA centred under both. */
.hero {
  --hero-top: calc(var(--topbar-gap) + var(--brand-pill-h)
                   + clamp(12px, 1.6vw, 24px));
  --hero-inset: clamp(14px, 1.7vw, 26px);
  display: flex;
  height: 100vh;            /* fallback where svh is not supported */
  height: 100svh;
  min-height: 480px;
  padding: var(--hero-top) var(--hero-inset) var(--hero-inset);
  /* Not --ground-white: see --hero-sky-white. The band around the
     frame is the same white the sky is blown to, so the top edge of
     the photograph has nothing to butt against. The handover to the
     portfolio's parchment happens across that section's own rule-top,
     a 3% step over a hairline. */
  background: var(--hero-sky-white);
}
.hero-frame {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  border-radius: var(--radius-media-lg);
  overflow: hidden;
  background: var(--stone-surface);
  /* Keep the frame's own layers in one stacking context — the copy
     sits at z-index 2 inside it and must never reach the header. */
  isolation: isolate;
}

/* The photograph layer is taller than the frame at both ends so the
   parallax has somewhere to travel: --hero-drift above and below. At
   rest it sits centred in that slack and the scroll handler walks it
   down, so the frame stays covered at both extremes of the travel.
   The handler writes the transform straight to this node, and the
   amount is HERO_PARALLAX in app.jsx — the two have to agree. */
.hero-photo {
  --hero-drift: 8%;
  position: absolute;
  left: 0;
  right: 0;
  top: calc(-1 * var(--hero-drift));
  bottom: calc(-1 * var(--hero-drift));
  will-change: transform;
}
.hero-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Biased above centre: on a wide, short frame a centred crop eats
     the sky the headline stands on. */
  object-position: 50% 42%;
}

/* The sky is blown out, not white, and a narrow frame crops the
   photograph so the horizon rides higher in it. This lifts the light
   at the top just enough that ink type always has ground to sit on;
   over the desktop crop it is all but invisible. */
.hero-sky {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    color-mix(in oklab, var(--hero-sky-white) 72%, transparent) 0%,
    color-mix(in oklab, var(--hero-sky-white) 48%, transparent) 22%,
    color-mix(in oklab, var(--hero-sky-white) 16%, transparent) 40%,
    transparent 56%);
}

.hero-copy {
  position: absolute;
  z-index: 2;
  top: clamp(24px, 4.2vh, 58px);
  left: 0;
  right: 0;
  /* The frame is near full-bleed; the copy is not. Past ~1536 it holds
     the site's own content width and centres, so the headline does not
     run the width of a 27-inch monitor. */
  max-width: calc(var(--max-w) + 96px);
  margin-inline: auto;
  padding: 0 clamp(22px, 4vw, 72px);
  display: grid;
  /* The right track is sized to the lead itself, not to a share of
     the row: the CTA sits under the lead and flushes to its right
     edge, and that only holds if the track and the paragraph are the
     same width. The leftover goes to the headline. */
  grid-template-columns: minmax(0, 1.6fr) minmax(0, clamp(280px, 26vw, 400px));
  column-gap: clamp(24px, 3.4vw, 60px);
  row-gap: clamp(16px, 3vh, 36px);
  align-items: start;
}
.hero-copy .hero-headline {
  grid-column: 1;
  margin: 0;
  /* Bigger than the hero it replaces. The left track is about 770px at
     1440 against the old text column's 827px, but "Ground you can
     stand on." measures roughly 10.8em at 700 with --ls-display, so
     4.8vw still holds the couplet on two lines everywhere the
     two-column copy exists — and the cap is 84px, not 66. */
  font-size: clamp(40px, 4.8vw, 84px);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
}
.hero-headline .ln-1,
.hero-headline .ln-2 { display: block; }
.hero-headline .ln-2 { margin-top: 2px; }
.hero-headline .ln-2 em {
  font-style: normal;
  font-weight: var(--fw-accent);
  color: var(--survey-ink);
}
.hero-copy .hero-lead {
  grid-column: 2;
  /* Hung near the headline's last line rather than its first: an 80px
     block and a 17px block sharing a top edge read as a mistake. The
     margin lifts it clear of that baseline (client, 4 Sep) so the lead
     and the CTA under it read as one cluster. */
  align-self: end;
  margin: 0 0 clamp(12px, 2.4vh, 32px);
  max-width: none;
  font-size: var(--fs-body);
}
.hero-cta {
  /* On the photograph, at the foot of the frame and centred (client,
     4 Sep). It left .hero-copy's grid to get here, so it is a sibling
     of the copy and is not carried by the copy's scroll fade — it
     rides the frame out of view instead.

     Centred with left/right + justify-content rather than
     translateX(-50%), because the entrance animation owns `transform`
     and the two would fight. The row spans the frame, so only the
     button itself takes pointer events. */
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: clamp(22px, 4vh, 52px);
  display: flex;
  justify-content: center;
  pointer-events: none;
}
.hero-cta .btn { pointer-events: auto; }

/* One column below 1080: the two tracks stop being able to hold the
   couplet on two lines and a 44ch paragraph beside it at once. */
@media (max-width: 1080px) {
  .hero-copy {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(12px, 2.2vh, 24px);
  }
  .hero-copy .hero-headline { font-size: clamp(32px, 7vw, 68px); }
  .hero-copy .hero-lead {
    grid-column: 1;
    align-self: start;
    margin-bottom: 0;
    max-width: 54ch;
  }
  /* .hero-cta is out of this grid — it sits on the photograph. */
}

/* A phone crops the frame to a portrait sliver of a landscape
   photograph, so the sky is a smaller share of it and the copy runs
   past the horizon. The scrim reaches further down to meet it — which
   reads as morning haze over the fields rather than as an overlay. */
@media (max-width: 760px) {
  .hero-sky {
    background: linear-gradient(
      to bottom,
      color-mix(in oklab, var(--hero-sky-white) 84%, transparent) 0%,
      color-mix(in oklab, var(--hero-sky-white) 70%, transparent) 32%,
      color-mix(in oklab, var(--hero-sky-white) 34%, transparent) 56%,
      transparent 76%);
  }
}

/* Short frames. Two cases and they want different things: a laptop at
   1440x720 keeps two columns and only needs the type to come down,
   while a phone on its side needs everything smaller. Guarding the
   first on min-width keeps it off portrait phones, where 3.9vw would
   resolve to 15px. */
@media (min-width: 1081px) and (max-height: 760px) {
  .hero-copy { top: clamp(16px, 2.6vh, 34px); row-gap: clamp(10px, 2vh, 22px); }
  .hero-copy .hero-headline { font-size: clamp(28px, 3.9vw, 60px); }
}
@media (max-height: 560px) and (orientation: landscape) {
  .hero-copy { top: 14px; row-gap: 10px; }
  .hero-copy .hero-headline { font-size: clamp(24px, 3.4vw, 42px); }
  .hero-copy .hero-lead { font-size: var(--fs-body-s); max-width: 48ch; }
}

/* Shared CTA row. It was written for the old hero's text column and
   lived in that band; the hero no longer uses it but the About page's
   hero does, so it stays — verbatim, `margin-top: auto` included. */
.cta-row {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: auto;
}

/* ─── New Launch ──────────────────────────────────────────────── */
.new-launch {
  /* --nl-peek is how much of the next card is left showing, which is
     what tells the eye the row scrolls. --nl-gap is the space between
     cards, so the visible sliver is peek minus gap. */
  --nl-peek: clamp(44px, 5vw, 84px);
  --nl-gap: clamp(12px, 1.4vw, 20px);
  background: var(--survey-ink);
  color: var(--ground-white);
  /* The top always clears the floating header, or the logo, the menu
     coin and the CTA sit on the photograph when the section is
     scrolled to. */
  padding: max(clamp(56px, 7vw, 104px), calc(var(--topbar-gap) + var(--brand-pill-h) + 16px)) 0
           clamp(48px, 6vw, 88px);
  position: relative;
  overflow: hidden;
}
/* A faint wash so the ink band is not a flat rectangle. */
.new-launch::before {
  content: "";
  position: absolute;
  inset: -20% -10% auto -10%;
  height: 140%;
  background:
    radial-gradient(60% 50% at 15% 0%, color-mix(in oklab, var(--laterite-gold) 12%, transparent), transparent 70%),
    radial-gradient(50% 40% at 90% 100%, color-mix(in oklab, var(--ghats-deep) 30%, transparent), transparent 70%);
  pointer-events: none;
}
.new-launch > .shell { position: relative; z-index: 1; }

/* Tags. `.nl-tag` is this section's own pill — `.status-stamp` is the
   portfolio card's and is left alone. */
.nl-tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 28px;
  padding: 0 12px;
  border-radius: 999px;
  font-size: var(--fs-label);
  font-weight: var(--fw-strong);
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.nl-tag .dot { width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
.nl-tag.is-new { background: var(--laterite-gold); color: var(--survey-ink); }
.nl-tag.is-status {
  background: color-mix(in oklab, var(--ground-white) 12%, transparent);
  border: 1px solid color-mix(in oklab, var(--ground-white) 22%, transparent);
  color: color-mix(in oklab, var(--ground-white) 88%, transparent);
  backdrop-filter: blur(8px);
}
.nl-tag.is-status .dot { background: #6FBF7F; }
/* Amber for Layout in-progress, matching the portfolio card's dot. */
.nl-tag.is-status.is-progress .dot { background: #F0C868; }
/* The lead card wears the gold "Latest launch" pill; the rest carry
   their portfolio number in the same slot so the row never collapses. */
.nl-tag.is-num {
  background: color-mix(in oklab, var(--ground-white) 12%, transparent);
  border: 1px solid color-mix(in oklab, var(--ground-white) 22%, transparent);
  color: color-mix(in oklab, var(--ground-white) 88%, transparent);
  backdrop-filter: blur(8px);
  font-variant-numeric: tabular-nums;
}

/* ── The carousel ──────────────────────────────────────────────────
   One card per community in a scroll-snap row. The cards stretch to a
   common height so the CTA row does not jump as the track advances. */
/* The mask is what turns a clipped card into a deliberate peek. It
   fades to transparent rather than to the ink, so the section's own
   wash shows through and there is no band to match. Each edge drops
   its fade once there is nothing more to scroll to that side. */
.nl-view { position: relative; }
.nl-view.is-focused {
  outline: 2px solid var(--laterite-gold);
  outline-offset: 6px;
  border-radius: var(--radius-media);
}
.nl-track {
  --nl-fade: var(--nl-peek);
  --nl-fade-l: 0px;
  --nl-fade-r: var(--nl-fade);
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--nl-fade-l),
                                      #000 calc(100% - var(--nl-fade-r)), transparent 100%);
          mask-image: linear-gradient(to right, transparent 0, #000 var(--nl-fade-l),
                                      #000 calc(100% - var(--nl-fade-r)), transparent 100%);
  display: flex;
  align-items: stretch;
  gap: var(--nl-gap);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.nl-track::-webkit-scrollbar { display: none; }
.nl-view.at-end .nl-track { --nl-fade-l: var(--nl-fade); --nl-fade-r: 0px; }
/* The ring sits on the wrapper because the mask would eat it. */
.nl-track:focus-visible { outline: none; }
.nl-slide {
  flex: 0 0 calc(100% - var(--nl-peek));
  min-width: 0;
  display: flex;
  flex-direction: column;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
/* The last card cannot align to the left edge — there is no scroll
   room left — so it snaps to the right one instead. */
.nl-slide:last-child { scroll-snap-align: end; }

/* The photographic stage. --par is set from JS for the parallax drift. */
.nl-stage {
  position: relative;
  flex: none;
  width: 100%;
  aspect-ratio: 21 / 9;
  max-height: 60vh;
  border-radius: var(--radius-media-lg);
  overflow: hidden;
  background: #262320;
}
.nl-frames { position: absolute; inset: 0; }
.nl-frames img {
  position: absolute;
  inset: -6% 0 -6% 0;
  width: 100%;
  height: 112%;
  object-fit: cover;
  opacity: 0;
  transform: translateY(var(--par, 0px)) scale(1.04);
  transition: opacity 1.1s ease;
  will-change: transform;
}
.nl-frames img.is-live { opacity: 1; }

.nl-scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(20,19,17,0.92) 0%, rgba(20,19,17,0.45) 38%, rgba(20,19,17,0.05) 70%),
    linear-gradient(to right, rgba(20,19,17,0.6) 0%, transparent 55%);
  pointer-events: none;
}

/* Bottom offset clears the tiles, which are pulled up over this edge. */
.nl-over {
  position: absolute;
  left: clamp(20px, 3vw, 44px);
  right: clamp(20px, 3vw, 44px);
  bottom: clamp(58px, 5.4vw, 86px);
  z-index: 2;
}
.nl-tags { display: flex; gap: 8px; flex-wrap: wrap; }
.nl-name {
  font-size: clamp(36px, 5.6vw, 84px);
  font-weight: var(--fw-display);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  margin: 14px 0 0;
  text-shadow: 0 2px 30px rgba(0,0,0,0.5);
}
.nl-place {
  margin: 10px 0 0;
  font-size: var(--fs-ui);
  letter-spacing: 0.02em;
  color: color-mix(in oklab, var(--ground-white) 76%, transparent);
  font-weight: var(--fw-strong);
}

.nl-dots {
  position: absolute;
  top: clamp(18px, 2.4vw, 30px);
  right: clamp(20px, 3vw, 44px);
  z-index: 3;
  display: flex;
  gap: 7px;
}
.nl-dot {
  width: 26px; height: 3px;
  border-radius: 999px;
  border: 0;
  padding: 0;
  cursor: pointer;
  background: color-mix(in oklab, var(--ground-white) 30%, transparent);
  transition: background 0.4s ease, width 0.4s ease;
}
.nl-dot:hover { background: color-mix(in oklab, var(--ground-white) 60%, transparent); }
.nl-dot.is-on { background: var(--laterite-gold); width: 42px; }

/* Figure tiles, lifted over the stage's bottom edge. The rise-in is the
   site's own .reveal, so only hover state lives here. */
.nl-tiles {
  position: relative;
  z-index: 3;
  margin-top: clamp(-52px, -3.6vw, -30px);
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(10px, 1vw, 16px);
  padding: 0 clamp(12px, 2vw, 32px);
}
.nl-tile {
  border-radius: 14px;
  padding: 18px 20px 16px;
  background: color-mix(in oklab, var(--survey-ink) 92%, transparent);
  border: 1px solid color-mix(in oklab, var(--ground-white) 20%, transparent);
  backdrop-filter: blur(18px) saturate(140%);
  box-shadow: 0 18px 40px -22px rgba(0, 0, 0, 0.8);
}
.nl-tile:hover {
  border-color: color-mix(in oklab, var(--laterite-gold) 60%, transparent);
  background: color-mix(in oklab, var(--survey-ink) 98%, transparent);
}
.nl-tile .v {
  font-size: clamp(24px, 2.4vw, 34px);
  font-weight: var(--fw-display);
  letter-spacing: var(--ls-heading);
  line-height: var(--lh-heading);
  font-variant-numeric: tabular-nums slashed-zero;
}
.nl-tile .v .unit {
  font-size: var(--fs-meta);
  font-weight: var(--fw-body);
  margin-left: 5px;
  color: color-mix(in oklab, var(--ground-white) 58%, transparent);
}
.nl-tile .k {
  margin-top: 6px;
  font-size: var(--fs-label);
  letter-spacing: 0.03em;
  color: color-mix(in oklab, var(--ground-white) 55%, transparent);
  font-weight: var(--fw-strong);
}

.nl-foot {
  margin-top: auto;
  padding-top: clamp(28px, 3.4vw, 48px);
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 64px);
  align-items: end;
}
.nl-intro {
  margin: 0;
  font-size: clamp(17px, 1.3vw, 20px);
  line-height: 1.6;
  color: color-mix(in oklab, var(--ground-white) 80%, transparent);
  max-width: 54ch;
}
.nl-docs {
  margin: 14px 0 0;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--fs-meta);
  color: color-mix(in oklab, var(--ground-white) 62%, transparent);
  font-weight: var(--fw-strong);
}
.nl-docs .tick {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 999px;
  background: color-mix(in oklab, var(--laterite-gold) 22%, transparent);
  color: var(--laterite-gold);
  flex: none;
}
.nl-cta { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }

/* Dots and arrows sit under the track, outside the cards, so they read
   as controls for the row rather than part of any one card. */
.nl-rail {
  margin-top: clamp(22px, 2.6vw, 34px);
  padding-top: clamp(18px, 2vw, 26px);
  border-top: 1px solid color-mix(in oklab, var(--ground-white) 14%, transparent);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.nl-rail-dots { display: flex; align-items: center; gap: 8px; }
.nl-rail-dot {
  width: 28px; height: 3px;
  border: 0;
  padding: 0;
  border-radius: 999px;
  cursor: pointer;
  background: color-mix(in oklab, var(--ground-white) 26%, transparent);
  transition: background 0.4s ease, width 0.4s ease;
}
.nl-rail-dot:hover { background: color-mix(in oklab, var(--ground-white) 60%, transparent); }
.nl-rail-dot.is-on { background: var(--laterite-gold); width: 46px; }
.nl-rail-dot:focus-visible { outline: 2px solid var(--laterite-gold); outline-offset: 5px; }
.nl-arrows { display: flex; gap: 10px; }
.nl-arrow {
  width: 42px; height: 42px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  cursor: pointer;
  color: var(--ground-white);
  background: color-mix(in oklab, var(--ground-white) 8%, transparent);
  border: 1px solid color-mix(in oklab, var(--ground-white) 30%, transparent);
  transition: background 0.3s ease, border-color 0.3s ease, color 0.3s ease;
}
.nl-arrow svg { display: block; }
.nl-arrow.is-prev svg { transform: rotate(180deg); }
.nl-arrow:hover {
  background: var(--ground-white);
  color: var(--survey-ink);
  border-color: var(--ground-white);
}
.nl-arrow:focus-visible { outline: 2px solid var(--laterite-gold); outline-offset: 3px; }

/* The track scrolls on x, which makes it clip on y as well: the CTA
   row sits on its bottom edge, so the buttons' shadow and hover lift
   were being cut flat. Room below, taken back with a negative margin. */
.nl-track { padding-bottom: 18px; margin-bottom: -18px; }

/* Desktop: the section is one screen tall (client, 3 Nov). It clears
   the floating header at the top, and the photograph takes whatever
   height the tiles, the intro, the CTAs and the rail leave it, rather
   than sizing itself off the card's width. Capped at 1080px so a very
   tall window does not stretch it into a poster. */
@media (min-width: 1025px) {
  .new-launch {
    height: clamp(640px, 100vh, 1080px);
    height: clamp(640px, 100svh, 1080px);
    padding: calc(var(--topbar-gap) + var(--brand-pill-h) + clamp(12px, 2.2vh, 28px)) 0
             clamp(18px, 3vh, 36px);
    display: flex;
    flex-direction: column;
  }
  .new-launch > .shell,
  .nl-carousel {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  .new-launch > .shell { width: 100%; }
  .nl-view {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  .nl-track { flex: 1 1 auto; min-height: 0; }
  .nl-stage {
    flex: 1 1 0;
    min-height: 220px;
    aspect-ratio: auto;
    max-height: none;
  }
  .nl-name { font-size: clamp(36px, min(5.6vw, 8.4vh), 84px); }
  .nl-foot { padding-top: clamp(16px, 2.6vh, 40px); }
  .nl-rail {
    margin-top: clamp(12px, 2vh, 28px);
    padding-top: clamp(12px, 1.6vh, 22px);
  }
}

@media (max-width: 1024px) {
  .new-launch { --nl-peek: 40px; }
  .nl-stage { aspect-ratio: 3 / 2; max-height: none; }
  /* The tiles no longer overlap the stage here, so the name drops to the
     stage's own bottom edge instead of clearing them. */
  .nl-over { bottom: clamp(20px, 3vw, 32px); }
  .nl-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 16px; padding: 0; }
  .nl-foot { grid-template-columns: minmax(0, 1fr); }
  .nl-cta { justify-content: flex-start; }
}
@media (max-width: 560px) {
  /* Phones: full-width cards with no peek and no edge mask, so every
     slide, the last included, sits on the same margins. Swipe, the dots
     and the arrows carry the "there is more" cue. */
  .new-launch { --nl-peek: 0px; --nl-gap: 12px; }
  .nl-track { -webkit-mask-image: none; mask-image: none; }
  .nl-slide:last-child { scroll-snap-align: start; }

  .nl-stage { aspect-ratio: 3 / 2; border-radius: var(--radius-media); }
  .nl-dots { display: none; }
  /* Tags pinned to the top of the photograph, name and place to its foot. */
  .nl-over {
    top: 14px; bottom: 16px; left: 16px; right: 16px;
    display: flex; flex-direction: column;
  }
  .nl-tags { margin-bottom: auto; gap: 6px; }
  .nl-tag { height: 26px; padding: 0 10px; font-size: var(--fs-micro); }
  .nl-tag.is-num { display: none; }
  .nl-name { font-size: clamp(28px, 8.4vw, 34px); margin-top: 0; }
  .nl-place { margin-top: 6px; font-size: var(--fs-meta); }

  /* One figures panel split by hairlines, not four boxes. */
  .nl-tiles {
    margin-top: 12px;
    gap: 0;
    border-radius: 14px;
    overflow: hidden;
    background: color-mix(in oklab, var(--survey-ink) 92%, transparent);
    border: 1px solid color-mix(in oklab, var(--ground-white) 18%, transparent);
  }
  .nl-tile, .nl-tile:hover {
    padding: 12px 14px;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .nl-tile:nth-child(odd) { border-right: 1px solid color-mix(in oklab, var(--ground-white) 14%, transparent); }
  .nl-tile:nth-child(-n+2) { border-bottom: 1px solid color-mix(in oklab, var(--ground-white) 14%, transparent); }
  .nl-tile .v { font-size: clamp(18px, 5.6vw, 22px); white-space: nowrap; }
  .nl-tile .v .unit { margin-left: 4px; }
  .nl-tile .k { margin-top: 3px; font-size: var(--fs-micro); }

  .nl-foot { padding-top: 20px; gap: 20px; }
  .nl-intro { font-size: var(--fs-body-s); }
  .nl-rail { gap: 12px; }
  .nl-rail-dot { width: 22px; }
  .nl-rail-dot.is-on { width: 36px; }
  .nl-arrow { width: 38px; height: 38px; }
  /* Primary first once they stack. */
  .nl-cta { flex-direction: column-reverse; }
  .nl-cta .btn { width: 100%; justify-content: space-between; }
}

@media (prefers-reduced-motion: reduce) {
  .nl-frames img, .nl-tile, .nl-dot, .nl-rail-dot, .nl-arrow { transition: none !important; }
  .nl-frames img { transform: none !important; }
  /* The track still scrolls on a press, it just does not glide. */
  .nl-track { scroll-behavior: auto; }
}

.status-stamp {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  border: 1px solid color-mix(in oklab, var(--ground-white) 50%, transparent);
  padding: 8px 12px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  width: max-content;
  white-space: nowrap;
  font-weight: var(--fw-strong);
}
.status-stamp .dot { width: 7px; height: 7px; border-radius: 999px; background: var(--laterite-gold); }
.status-stamp.available .dot { background: var(--forest-mist); }
.status-stamp.completed .dot { background: var(--contour-gray-soft); }

.new-launch .btn-secondary {
  background: color-mix(in oklab, var(--ground-white) 8%, transparent);
  color: var(--ground-white);
  border-color: color-mix(in oklab, var(--ground-white) 55%, transparent);
}
.new-launch .btn-secondary .arrow { background: var(--ground-white); }
.new-launch .btn-secondary .arrow svg { color: var(--survey-ink); }
.new-launch .btn-secondary:hover {
  background: var(--ground-white);
  color: var(--survey-ink);
  border-color: var(--ground-white);
}
.new-launch .btn-secondary:hover .arrow { background: var(--survey-ink); }
.new-launch .btn-secondary:hover .arrow svg { color: var(--ground-white); }

/* ─── Portfolio ───────────────────────────────────────────────── */
.portfolio {
  padding: clamp(80px, 10vw, 160px) 0 clamp(64px, 8vw, 120px);
}
.portfolio-head {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: clamp(24px, 4vw, 80px);
  align-items: end;
  padding-bottom: clamp(40px, 5vw, 72px);
}
.portfolio-head h2 {
  margin: 12px 0 0;
  font-size: clamp(48px, 6.6vw, 100px);
  font-family: var(--font-display);
  letter-spacing: var(--ls-display);
  line-height: var(--lh-display);
  font-weight: var(--fw-display);
}
.portfolio-head h2 em { font-style: normal; font-weight: var(--fw-accent); color: var(--survey-ink); }
.portfolio-head .right {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-bottom: 10px;
}

.filter-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  border-top: var(--rule);
  border-bottom: var(--rule);
  padding: 14px 0;
  margin-bottom: 0;
}
.chip {
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  font-weight: var(--fw-strong);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid color-mix(in oklab, var(--survey-ink) 18%, transparent);
  color: color-mix(in oklab, var(--survey-ink) 70%, transparent);
  cursor: pointer;
  transition: all 0.2s;
  background: transparent;
  white-space: nowrap;
}
.chip:hover { border-color: var(--survey-ink); color: var(--survey-ink); }
.chip.active { background: var(--survey-ink); color: var(--ground-white); border-color: var(--survey-ink); }
.chip .count { margin-left: 6px; color: color-mix(in oklab, currentColor 60%, transparent); }

/* Index table */
.plot-index {
  display: grid;
  grid-template-columns: 56px 1.4fr 1.4fr 1fr 0.8fr 0.6fr 56px;
  border-bottom: var(--rule);
}
.plot-index .row {
  display: contents;
}
.plot-index .row > * {
  border-top: var(--rule);
  padding: 20px 12px;
  display: flex;
  align-items: center;
  font-size: var(--fs-body-s);
}
.plot-index .row > *:first-child { padding-left: 0; }
.plot-index .row > *:last-child { padding-right: 0; justify-content: flex-end; }
.plot-index .row .num { font-family: var(--font-mono); font-size: var(--fs-label); color: var(--contour-gray); letter-spacing: 0.04em; }
.plot-index .row .name { font-family: var(--font-display); font-size: 28px; letter-spacing: -0.015em; line-height: 1.02; font-weight: var(--fw-strong); }
.plot-index .row .loc { color: color-mix(in oklab, var(--survey-ink) 70%, transparent); font-size: var(--fs-ui); }
.plot-index .row .status { font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: 0.1em; text-transform: uppercase; }
.plot-index .row .status .dot { display: inline-block; width: 7px; height: 7px; border-radius: 999px; margin-right: 8px; }
.plot-index .row .status.completed .dot { background: var(--contour-gray-soft); }
.plot-index .row .status.available .dot { background: var(--laterite-gold); }
.plot-index .row .status.ongoing .dot { background: var(--ghats-deep); }
.plot-index .row .area { font-family: var(--font-mono); font-size: var(--fs-ui); color: var(--survey-ink); white-space: nowrap; }
.plot-index .row .year { font-family: var(--font-mono); font-size: var(--fs-ui); color: var(--contour-gray); }
.plot-index .row .open { color: var(--contour-gray); font-family: var(--font-mono); font-size: 18px; transition: color 0.2s;
  font-weight: var(--fw-strong);
}
.plot-index .row.is-hovered { background: color-mix(in oklab, var(--stone-surface) 80%, transparent); }
.plot-index .row.is-hovered .open { color: var(--laterite-gold); }
.plot-index .header > * {
  border-top: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 14px !important;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--contour-gray);
}

.plot-cards {
  margin-top: clamp(40px, 5vw, 80px);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(16px, 1.8vw, 26px);
}
/* Slightly larger cards: the grid runs half a gutter past the shell on each
   side. Phones keep the full gutter. */
@media (min-width: 641px) {
  .plot-cards { margin-inline: calc(var(--gutter) * -0.5); }
}

/* ─── Glass project card ──────────────────────────────────────────
   Landscape art or photograph behind, a frosted panel in front. The
   panel holds a hidden row that expands on hover/focus, so the resting
   card stays quiet and the detail arrives on intent. */
.pc {
  position: relative;
  display: block;
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-media);
  overflow: hidden;
  isolation: isolate;
  background: var(--stone-surface);
  box-shadow: 0 1px 2px rgba(26,25,22,.05), 0 10px 30px -16px rgba(26,25,22,.28);
  transition:
    transform .55s cubic-bezier(.22,.7,.2,1),
    box-shadow .55s cubic-bezier(.22,.7,.2,1);
}
.pc:hover,
.pc:focus-visible {
  transform: translateY(-6px);
  box-shadow: 0 4px 8px rgba(26,25,22,.07), 0 28px 60px -22px rgba(26,25,22,.42);
}
.pc:focus-visible { outline: 2px solid var(--laterite-gold); outline-offset: 3px; }

.pc-bg { position: absolute; inset: 0; z-index: 0; }
.pc-bg img { width: 100%; height: 100%; object-fit: cover; }
.pc-bg,
.pc-bg img,
.pc-bg svg { transition: transform 1.1s cubic-bezier(.22,.7,.2,1); }
.pc:hover .pc-bg,
.pc:hover .pc-bg img,
.pc:hover .pc-bg svg { transform: scale(1.06); }

/* Hover video — layered over the still (its own first frame). Shared by the
   home and projects cards; see HoverVideo in components.jsx. */
.hover-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  pointer-events: none;
  transition: opacity .45s ease, transform 1.1s cubic-bezier(.22,.7,.2,1);
}
.hover-video.is-playing { opacity: 1; }
.pc:hover .pc-bg .hover-video { transform: scale(1.06); }

.pc-scrim {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(20,19,17,.42) 0%,
    rgba(20,19,17,.06) 34%,
    rgba(20,19,17,.30) 66%,
    rgba(20,19,17,.72) 100%);
  transition: opacity .55s ease;
}
.pc:hover .pc-scrim { opacity: .88; }

/* Status chip, glass */
.pc-tag {
  position: absolute; top: 14px; z-index: 3;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 12px;
  border-radius: 100px;
  font-size: var(--fs-label); font-weight: var(--fw-strong); letter-spacing: .01em;
  -webkit-backdrop-filter: blur(14px) saturate(1.5);
  backdrop-filter: blur(14px) saturate(1.5);
  border: 1px solid rgba(247,244,239,.26);
  background: rgba(247,244,239,.16);
  color: var(--ground-white);
  white-space: nowrap;
}
.pc-tag { left: 14px; max-width: calc(100% - 28px); overflow: hidden; text-overflow: ellipsis; }
.pc-tag .dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.pc-tag.is-selling  .dot { background: #7BD68F; box-shadow: 0 0 0 3px rgba(123,214,143,.22); }
.pc-tag.is-progress .dot { background: #F0C868; box-shadow: 0 0 0 3px rgba(240,200,104,.22); }

/* The frosted panel */
.pc-glass {
  position: absolute; left: 10px; right: 10px; bottom: 10px; z-index: 3;
  padding: 16px 16px 14px;
  border-radius: 14px;
  -webkit-backdrop-filter: blur(20px) saturate(1.7);
  backdrop-filter: blur(20px) saturate(1.7);
  background: linear-gradient(180deg, rgba(247,244,239,.20), rgba(247,244,239,.12));
  border: 1px solid rgba(247,244,239,.24);
  color: var(--ground-white);
  transition: background .5s ease, border-color .5s ease;
}
.pc:hover .pc-glass {
  background: linear-gradient(180deg, rgba(247,244,239,.28), rgba(247,244,239,.17));
  border-color: rgba(247,244,239,.4);
}
.pc-name {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  /* Was 22-28px; brought down to read as a card title (client, 3 Nov). */
  font-size: clamp(18px, 1.3vw, 21px);
  letter-spacing: var(--ls-card);
  line-height: var(--lh-card);
}
.pc-loc {
  margin-top: 4px;
  font-size: var(--fs-meta);
  color: rgba(247,244,239,.76);
  font-weight: var(--fw-strong);
}
/* Buy now (client, 3 Nov). The panel is name and place on the left
   and a Buy now column on the right that opens on hover. The column
   animates from 0px to the button's width — px to px, so it actually
   travels — while the button fades and slides in. `overflow-x: clip`
   (not hidden) clips the opening sideways without cutting the button's
   lift and shadow vertically. The card is the link; the button is part
   of it, so both go to the project page. */
.pc-glass {
  --pc-cta-w: 150px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 0px;
  align-items: center;
  column-gap: 0;
  transition:
    background .5s ease, border-color .5s ease,
    grid-template-columns .5s cubic-bezier(.22,.7,.2,1),
    column-gap .5s cubic-bezier(.22,.7,.2,1);
}
.pc-id { min-width: 0; }
.pc-cta {
  min-width: 0;
  display: flex;
  justify-content: flex-end;
  overflow-x: clip;
  opacity: 0;
  transform: translateX(12px);
  transition: opacity .35s ease, transform .5s cubic-bezier(.22,.7,.2,1);
}
.pc-cta .buy { flex: none; }
@media (hover: hover) {
  .pc:hover .pc-glass,
  .pc:focus-visible .pc-glass {
    grid-template-columns: minmax(0, 1fr) var(--pc-cta-w);
    column-gap: 12px;
  }
  .pc:hover .pc-cta,
  .pc:focus-visible .pc-cta {
    opacity: 1;
    transform: none;
    transition-delay: .12s, .08s;
  }
}
/* Touch screens have no hover, so the button is simply there. */
@media (hover: none) {
  .pc-glass {
    grid-template-columns: minmax(0, 1fr) var(--pc-cta-w);
    column-gap: 12px;
    padding: 12px 12px 12px 14px;
  }
  .pc-cta { opacity: 1; transform: none; }
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .pc-glass { background: rgba(26,25,22,.72); }
  .pc-tag { background: rgba(26,25,22,.6); }
}

@media (prefers-reduced-motion: reduce) {
  .pc, .pc-bg, .pc-bg img, .pc-bg svg, .pc-cta,
  .pc-glass, .pc-name, .pc-loc { transition: none; }
  .pc:hover { transform: none; }
}

/* "Explore all projects": the sixth cell of the home grid, the same 3:2
   card as the five beside it, kept quiet on purpose: a stone surface, a
   hairline, ink type and an outlined arrow coin. On hover the card lifts
   with the others, the hairline warms to gold, a faint gold wash grows out
   of the coin, the coin fills gold and turns to point the way in, and the
   title steps right. */
.pc-all {
  color: var(--survey-ink);
  border: 1px solid rgba(26,25,22,.09);
  box-shadow: none;
  transition:
    transform .55s cubic-bezier(.22,.7,.2,1),
    box-shadow .55s cubic-bezier(.22,.7,.2,1),
    border-color .5s ease;
}
.pc-all:hover,
.pc-all:focus-visible { border-color: rgba(184,131,42,.45); }
.pc-all-glass {
  position: absolute; inset: 0; z-index: 1;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: clamp(18px, 1.8vw, 26px);
}
.pc-all-fill {
  position: absolute; inset: 0; z-index: -1;
  background: rgba(184,131,42,.08);
  clip-path: circle(0% at calc(100% - 40px) 40px);
  transition: clip-path .9s cubic-bezier(.65,0,.25,1);
}
.pc-all:hover .pc-all-fill,
.pc-all:focus-visible .pc-all-fill { clip-path: circle(150% at calc(100% - 40px) 40px); }
.pc-all-coin {
  position: absolute; z-index: 2;
  top: 22px; right: 22px;
  width: 36px; height: 36px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: 1px solid rgba(26,25,22,.22);
  color: var(--survey-ink);
  transition: transform .6s cubic-bezier(.22,.7,.2,1), background .45s ease,
    border-color .45s ease, color .45s ease;
}
.pc-all:hover .pc-all-coin,
.pc-all:focus-visible .pc-all-coin {
  background: var(--laterite-gold);
  border-color: var(--laterite-gold);
  color: var(--ground-white);
  transform: rotate(45deg);
}
.pc-all-body { position: relative; display: flex; flex-direction: column; gap: 8px; }
.pc-all-eyebrow {
  font-size: var(--fs-micro);
  font-weight: var(--fw-strong);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(26,25,22,.56);
}
.pc-all-title {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-size: clamp(24px, 2.1vw, 32px);
  letter-spacing: var(--ls-heading);
  line-height: var(--lh-heading);
  transition: transform .6s cubic-bezier(.22,.7,.2,1);
}
.pc-all:hover .pc-all-title,
.pc-all:focus-visible .pc-all-title { transform: translateX(4px); }
@media (prefers-reduced-motion: reduce) {
  .pc-all, .pc-all-fill, .pc-all-coin, .pc-all-title { transition: none; }
  .pc-all:hover .pc-all-coin, .pc-all:hover .pc-all-title { transform: none; }
}

/* ─── Method ──────────────────────────────────────────────────── */
.method {
  background: var(--stone-surface);
  padding: clamp(80px, 10vw, 160px) 0;
}
.method-head {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: clamp(24px, 4vw, 80px);
  align-items: end;
  padding-bottom: clamp(40px, 5vw, 80px);
}
.method-head h2 {
  margin: 14px 0 0;
  font-size: clamp(40px, 5vw, 80px);
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  letter-spacing: var(--ls-display);
  line-height: var(--lh-display);
}
.method-head h2 em { font-style: normal; font-weight: var(--fw-accent); color: var(--survey-ink); }
.method-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  border-top: var(--rule-strong);
}
.method-step {
  padding: 32px 24px 32px 0;
  border-right: var(--rule);
  display: flex;
  flex-direction: column;
  gap: 24px;
  min-height: 280px;
}
.method-step:last-child { border-right: 0; }
.method-step .title {
  font-family: var(--font-display);
  font-size: 36px;
  letter-spacing: -0.02em;
  line-height: 1;
}
.method-step .desc {
  font-size: var(--fs-body-s);
  line-height: 1.6;
  color: color-mix(in oklab, var(--survey-ink) 75%, transparent);
  max-width: 28ch;
  font-weight: var(--fw-body);
}
.method-step .icn {
  margin-top: auto;
  align-self: flex-start;
}
.method-grid .method-step:not(:first-child) { padding-left: 24px; }

/* ─── Footer ──────────────────────────────────────────────────── */
.footer {
  background: var(--survey-ink);
  color: var(--ground-white);
  padding: clamp(72px, 8vw, 120px) 0 28px;
  position: relative;
  overflow: hidden;
}
.footer::before {
  content: "";
  position: absolute;
  inset: -1px 0 auto 0;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    color-mix(in oklab, var(--laterite-gold) 60%, transparent) 50%,
    transparent 100%);
}

.footer-mark-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 32px;
  align-items: end;
  padding-bottom: clamp(40px, 5vw, 64px);
  margin-bottom: clamp(40px, 5vw, 64px);
  border-bottom: 1px solid color-mix(in oklab, var(--ground-white) 14%, transparent);
}

.ijw-mark {
  display: inline-flex;
  align-items: center;
  gap: 18px;
}
/* Footer signature: the mark plus the name. The client asked for the
   black file in header and footer both (3 Sep). The mark is two-tone —
   solid block, knocked-out counters — so straight onto the ink footer
   the block reads as absence and the mark loses its silhouette. The
   plate gives it its ground back, which is the only way the black file
   works here. One rule to delete if the footer ever goes light. */
.ijw-logo {
  height: 56px;
  width: auto;
  max-width: none;
  flex: none;
  display: block;
  padding: 9px;
  border-radius: var(--radius-media-sm);
  background: var(--ground-white);
  box-sizing: content-box;
}
.ijw-name {
  font-family: var(--font-sf);
  font-weight: var(--fw-bold);
  font-size: 22px;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--ground-white);
  white-space: nowrap;
}

.footer-pitch {
  margin: 22px 0 0;
  font-family: var(--font-display);
  font-size: clamp(20px, 1.6vw, 26px);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-heading);
  color: var(--ground-white);
  max-width: 40ch;
}
.footer-cta {
  display: flex;
  justify-content: flex-end;
  align-items: end;
  padding-bottom: 8px;
}
.footer-cta .btn-primary {
  background: var(--laterite-gold);
  color: var(--ground-white);
}

.footer-top {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 32px;
  padding-bottom: clamp(40px, 5vw, 64px);
  border-bottom: 1px solid color-mix(in oklab, var(--ground-white) 14%, transparent);
}

.footer-col h4 {
  font-family: var(--font-eyebrow);
  font-size: var(--fs-micro);
  font-weight: var(--fw-strong);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--ground-white) 55%, transparent);
  margin: 0 0 18px;
}
.footer-col ul {
  list-style: none;
  margin: 0; padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.footer-col li a,
.footer-col li span {
  font-size: var(--fs-ui);
  color: var(--ground-white);
  transition: color 0.2s;
  position: relative;
  font-weight: var(--fw-strong);
}
.footer-col li a:hover { color: var(--laterite-gold); }
.footer-col li span { display: inline-block; }

.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 22px;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.02em;
  color: color-mix(in oklab, var(--ground-white) 55%, transparent);
  font-weight: var(--fw-strong);
}
.footer-bottom-right {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.footer-bottom-right .dot-sep {
  color: color-mix(in oklab, var(--ground-white) 30%, transparent);
}
.footer-bottom-right a:hover { color: var(--laterite-gold); }
.footer-bottom-right { flex-wrap: wrap; }
.footer-ck {
  appearance: none; background: none; border: 0; padding: 0;
  font: inherit; letter-spacing: inherit; color: inherit; cursor: pointer;
}
.footer-ck:hover { color: var(--laterite-gold); }
.footer-ck:focus-visible { outline: 2px solid var(--laterite-gold); outline-offset: 3px; border-radius: 4px; }

/* ─── Cookie notice (track.js) ─────────────────────────────────
   A floating card, bottom left on a computer and full width on a
   phone. Injected by track.js, so it appears on every public page
   and never inside the dashboard. Sits under the modal (400) and
   over the header (50). */
.ck {
  position: fixed;
  z-index: 300;
  left: max(24px, env(safe-area-inset-left));
  bottom: max(24px, env(safe-area-inset-bottom));
  width: min(460px, calc(100vw - 48px));
  padding: 26px 26px 24px;
  border-radius: var(--radius-media-lg);
  background: var(--ground-white);
  border: 1px solid color-mix(in oklab, var(--survey-ink) 14%, transparent);
  box-shadow:
    0 2px 4px color-mix(in oklab, var(--survey-ink) 10%, transparent),
    0 24px 60px -14px color-mix(in oklab, var(--survey-ink) 38%, transparent);
  color: var(--survey-ink);
  font-family: var(--font-body);
  opacity: 0;
  transform: translateY(18px) scale(.98);
  transform-origin: 0% 100%;
  transition: opacity .38s ease, transform .5s cubic-bezier(.2, 1.3, .4, 1);
}
.ck.is-in { opacity: 1; transform: none; }
.ck-t {
  margin: 0 0 8px;
  font-size: clamp(19px, 0.4vw + 15px, 21px);
  font-weight: var(--fw-accent);
  letter-spacing: -0.015em;
  line-height: 1.2;
}
.ck-b {
  margin: 0;
  font-size: var(--fs-body-s);
  font-weight: var(--fw-body);
  line-height: 1.5;
  color: color-mix(in oklab, var(--survey-ink) 84%, transparent);
  text-wrap: pretty;
}
.ck-a { display: flex; gap: 10px; margin-top: 20px; }
.ck-a .btn { flex: 1 1 0; justify-content: center; font-size: var(--fs-ui); font-weight: var(--fw-bold); }
.ck-note {
  padding: 16px 20px;
  font-size: var(--fs-ui);
  font-weight: var(--fw-strong);
}

@media (max-width: 640px) {
  .ck {
    left: max(12px, env(safe-area-inset-left));
    right: max(12px, env(safe-area-inset-right));
    bottom: max(12px, env(safe-area-inset-bottom));
    width: auto;
    padding: 22px 20px 20px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .ck { transition: opacity .2s linear; transform: none; }
}

/* ─── Image slot placeholder styling ──────────────────────────── */
image-slot {
  --slot-bg: var(--stone-surface);
  --slot-fg: var(--contour-gray);
}
image-slot::part(frame) {
  background: transparent;
}
image-slot::part(ring) {
  display: none;
}
/* Hide image-slot's empty caption by default — the on-brand SVG placeholder
   takes over. Reveal a subtle "drop image" hint on hover only. */
image-slot::part(empty) {
  background: transparent;
  color: rgba(255, 255, 255, 0);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  transition: background 0.25s, color 0.25s;
}
image-slot:hover::part(empty) {
  background: rgba(0, 0, 0, 0.35);
  color: rgba(255, 255, 255, 0.85);
}
.visual-frame {
  position: relative;
  border-radius: var(--radius-media-lg);
  overflow: hidden;
}
.visual-frame > .placeholder-art,
.visual-frame > .placeholder-art svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.visual-frame > image-slot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  will-change: transform;
}

/* ─── Story Behind ───────────────────────────────────────────── */
.story {
  padding: clamp(80px, 10vw, 140px) 0 clamp(64px, 7vw, 96px);
  background: var(--stone-surface);
  position: relative;
  overflow: hidden;
}
.story-main {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: clamp(32px, 4vw, 72px);
  align-items: start;
}
.story-body { display: flex; flex-direction: column; }

.story-title {
  font-size: clamp(40px, 5vw, 80px);
  line-height: var(--lh-display);
  margin: 0 0 36px;
  font-weight: var(--fw-display);
  letter-spacing: var(--ls-display);
}
.story-title em { font-style: normal; font-weight: var(--fw-accent); color: var(--survey-ink); }

.story-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(16px, 2vw, 36px);
}
.story-p {
  font-size: var(--fs-body);
  line-height: 1.65;
  color: color-mix(in oklab, var(--survey-ink) 82%, transparent);
  margin: 0;
  text-wrap: pretty;
  font-weight: var(--fw-body);
}
.story-p .lead-letter {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: var(--fw-bold);
  letter-spacing: -0.015em;
  color: var(--survey-ink);
  margin-right: 2px;
}

.story-portrait {
  position: relative;
  aspect-ratio: 3 / 4;
  background: var(--survey-ink);
  overflow: hidden;
}
.story-portrait .portrait-label {
  position: absolute;
  bottom: 16px; left: 16px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ground-white);
  z-index: 3;
  mix-blend-mode: difference;
}

/* Credits strip at the bottom — small, neatly aligned */
.story-credits {
  margin: clamp(48px, 5vw, 80px) 0 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
  padding-top: 20px;
  border-top: var(--rule);
}
.story-credits .cred { display: flex; flex-direction: column; gap: 4px; }
.story-credits dt {
  font-family: var(--font-eyebrow);
  font-size: var(--fs-micro);
  font-weight: var(--fw-strong);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--contour-gray);
}
.story-credits dd {
  margin: 0;
  font-family: var(--font-display);
  font-size: 20px;
  letter-spacing: -0.015em;
  color: var(--survey-ink);
  font-weight: var(--fw-strong);
}

/* ─── Register Interest ──────────────────────────────────────── */
.register {
  padding: clamp(80px, 10vw, 160px) 0;
  background: var(--ground-white);
  position: relative;
  overflow: hidden;
}
.register::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(
    60% 60% at 90% 0%,
    color-mix(in oklab, var(--laterite-gold) 14%, transparent) 0%,
    transparent 60%
  );
  pointer-events: none;
}
.register-grid {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1.05fr;
  gap: clamp(40px, 5vw, 88px);
  align-items: start;
}
.register-title {
  font-size: clamp(40px, 4.8vw, 76px);
  line-height: var(--lh-display);
  margin: 18px 0 38px;
  font-weight: var(--fw-display);
  letter-spacing: var(--ls-display);
}
.register-title em { font-style: normal; font-weight: var(--fw-accent); color: var(--survey-ink); }

.register-points {
  margin-top: 36px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  border-top: var(--rule);
  padding-top: 24px;
}
.reg-point {
  display: grid;
  grid-template-columns: 16px 1fr;
  gap: 14px;
  align-items: start;
}
.reg-point .dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--laterite-gold);
  margin-top: 8px;
}
.reg-point .rp-k {
  font-family: var(--font-display);
  font-size: 19px;
  letter-spacing: -0.015em;
  margin-bottom: 2px;
  font-weight: var(--fw-strong);
}
.reg-point .rp-v {
  font-size: var(--fs-ui);
  line-height: 1.55;
  color: color-mix(in oklab, var(--survey-ink) 70%, transparent);
  font-weight: var(--fw-body);
}

/* Form */
.register-form {
  background: color-mix(in oklab, white 60%, transparent);
  border: 1px solid color-mix(in oklab, var(--survey-ink) 12%, transparent);
  border-radius: 18px;
  padding: clamp(20px, 2.5vw, 36px);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.8) inset,
    0 0 0 1px rgba(255, 255, 255, 0.45) inset,
    0 24px 60px -24px rgba(26, 25, 22, 0.18),
    0 6px 12px -8px rgba(26, 25, 22, 0.08);
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.form-row.two {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.field-k {
  font-family: var(--font-eyebrow);
  font-size: var(--fs-micro);
  font-weight: var(--fw-strong);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--contour-gray);
}
.field-k .opt {
  text-transform: none;
  letter-spacing: 0;
  font-weight: var(--fw-body);
  color: color-mix(in oklab, var(--contour-gray) 70%, transparent);
  font-size: var(--fs-micro);
}
.field input,
.field select,
.field textarea {
  font: inherit;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  color: var(--survey-ink);
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid color-mix(in oklab, var(--survey-ink) 14%, transparent);
  border-radius: 10px;
  padding: 12px 14px;
  width: 100%;
  outline: none;
  transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;
}
.field textarea { resize: vertical; min-height: 88px; }
.field input::placeholder,
.field textarea::placeholder {
  color: color-mix(in oklab, var(--survey-ink) 38%, transparent);
}
.field select {
  appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23857F77' stroke-width='1.4'><path d='M2 5 L6 9 L10 5'/></svg>");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px;
  padding-right: 36px;
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  border-color: var(--laterite-gold);
  background: white;
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--laterite-gold) 22%, transparent);
}

.form-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 6px;
  flex-wrap: wrap;
}
.form-hint {
  font-size: var(--fs-micro);
  letter-spacing: 0.03em;
  color: var(--contour-gray);
  max-width: 48ch;
  line-height: 1.5;
  text-transform: none;
  font-weight: var(--fw-body);
}

/* ─── The two forms (client, 3 Nov 2026) ─────────────────────────
   forms.jsx. Built on the field primitives above; these rules add only
   what the old forms did not have: the country-code chip, the two
   radio choices, the visit fields that open under them, and the
   confirmation that replaces the fields once a form is sent. `fm-`
   collides with nothing in any of the five stylesheets. */

/* Phone: the chip and the number share one row. The real <select> is
   laid over the chip at opacity 0, so the chip shows "+91" and the
   open list shows the country names. */
.fm-phone {
  display: flex;
  gap: 8px;
  min-width: 0;
}
.fm-phone input { flex: 1 1 auto; min-width: 0; }
.fm-cc {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 0 12px 0 14px;
  font-size: var(--fs-body);
  font-weight: var(--fw-strong);
  color: var(--survey-ink);
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid color-mix(in oklab, var(--survey-ink) 14%, transparent);
  border-radius: 10px;
  transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;
}
.fm-cc-chev { color: var(--contour-gray); }
.field .fm-cc select {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
  padding: 0;
  border: 0;
  /* Inherits the field's font so the open list matches on desktop. */
  font-size: var(--fs-body);
}
.fm-cc:focus-within {
  border-color: var(--laterite-gold);
  background: white;
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--laterite-gold) 22%, transparent);
}

/* The two choices. A real radio input under each, kept focusable and
   checked by the keyboard, drawn as a ring that fills gold. */
.fm-choice {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}
.fm-choice legend {
  padding: 0;
  margin-bottom: 6px;
}
.fm-choice-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.fm-radio {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 13px 14px;
  font-size: var(--fs-ui);
  font-weight: var(--fw-strong);
  color: var(--survey-ink);
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid color-mix(in oklab, var(--survey-ink) 14%, transparent);
  border-radius: 10px;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;
}
.fm-radio input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
  pointer-events: none;
}
.fm-radio-dot {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  border-radius: 999px;
  border: 1.5px solid color-mix(in oklab, var(--survey-ink) 30%, transparent);
  display: grid;
  place-items: center;
  transition: border-color 0.2s;
}
.fm-radio-dot::after {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--laterite-gold);
  transform: scale(0);
  transition: transform 0.22s cubic-bezier(.3, 1.5, .5, 1);
}
.fm-radio:hover { border-color: color-mix(in oklab, var(--survey-ink) 28%, transparent); }
.fm-radio.is-on {
  background: white;
  border-color: var(--laterite-gold);
}
.fm-radio.is-on .fm-radio-dot { border-color: var(--laterite-gold); }
.fm-radio.is-on .fm-radio-dot::after { transform: scale(1); }
.fm-radio:focus-within {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--laterite-gold) 22%, transparent);
}

/* The visit fields open under the choice. The collapse is a grid row
   going 0fr -> 1fr; the negative margin takes back the form's own 14px
   gap while it is closed, or a call back would leave a hole above the
   foot. The inner fieldset carries 3px of padding against a 3px
   negative margin so its overflow clip does not cut the focus ring. */
.fm-more {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  margin-top: -14px;
  transition: grid-template-rows 0.38s cubic-bezier(.2, .7, .2, 1),
              opacity 0.26s ease, margin-top 0.38s cubic-bezier(.2, .7, .2, 1);
}
.fm-more.is-open {
  grid-template-rows: 1fr;
  opacity: 1;
  margin-top: 0;
}
.fm-more-in {
  min-height: 0;
  overflow: hidden;
  border: 0;
  min-width: 0;
  margin: -3px;
  padding: 3px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* A dropdown or date with nothing chosen yet shows its prompt as a value,
   in full ink, beside text boxes whose placeholders are at 38%. `is-empty`
   (set from forms.jsx) brings the prompt down to the placeholder colour;
   the open list keeps full-ink options. */
.field select.is-empty,
.field input.is-empty,
.field input.is-empty::-webkit-datetime-edit {
  color: color-mix(in oklab, var(--survey-ink) 38%, transparent);
}
.field select option { color: var(--survey-ink); }
.field input[type="date"] { min-height: 50px; }

/* The spam trap: off-screen, not display:none, so form-filling software
   still sees it. Real visitors never meet it, and it is out of the tab
   order and hidden from screen readers. */
.fm-trap {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
/* When a form could not be sent, said plainly, with the office number. */
.fm-error {
  padding: 12px 14px;
  border-radius: 10px;
  font-size: var(--fs-ui);
  line-height: 1.5;
  color: #8A2E14;
  background: color-mix(in oklab, #B4482A 10%, white);
  border: 1px solid color-mix(in oklab, #B4482A 30%, transparent);
}
.fm-error b { font-weight: var(--fw-bold); }
.fm-error a { color: inherit; font-weight: var(--fw-strong); text-decoration: underline; }

/* Sent. */
.fm-done {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
  padding: clamp(8px, 1.4vw, 18px) 0;
  animation: fmDoneIn 0.5s cubic-bezier(.2, .7, .2, 1) both;
}
.fm-done-tick {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 999px;
  color: var(--ghats-deep);
  background: color-mix(in oklab, var(--ghats-deep) 12%, transparent);
}
.fm-done-title {
  margin: 4px 0 0;
  font-family: var(--font-display);
  font-size: clamp(26px, 2.2vw, 32px);
  font-weight: var(--fw-display);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-heading);
  color: var(--survey-ink);
  outline: none;
}
.fm-done-text {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: color-mix(in oklab, var(--survey-ink) 76%, transparent);
  max-width: 46ch;
}
.fm-done-text p { margin: 0; }
.fm-done-text strong { font-weight: var(--fw-strong); color: var(--survey-ink); }
.fm-done-again {
  margin-top: 6px;
  padding: 0;
  font: inherit;
  font-size: var(--fs-ui);
  font-weight: var(--fw-strong);
  color: var(--laterite-gold-deep);
  background: none;
  border: 0;
  border-bottom: 1px solid currentColor;
  cursor: pointer;
}
.fm-done-again:hover { color: var(--survey-ink); }
@keyframes fmDoneIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

@media (max-width: 640px) {
  .fm-choice-row { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .fm-more { transition: none; }
  .fm-radio-dot::after { transition: none; }
  .fm-done { animation: none; }
}

/* ─── Modal (step 5) ─────────────────────────────────────────────
   One overlay for the whole site. This step opens the visit form in
   it; steps 6, 7 and 9 bring the photo lightbox, the layout viewer
   and Build a home to the same panel. Nothing here is page-scoped,
   so it lives in styles.css and every page gets it.

   The panel carries the site's identity rather than inventing one:
   --radius-media-lg is the same corner the photographs use, the head
   runs on the type scale, and the ground is the parchment white with
   the same glass the header pills and the register card already wear.

   `md-` collides with nothing — pp-, wm-, bh-, px-, nl- and lb- are
   the prefixes already in use. */
.md-root {
  --md-anim: 200ms;      /* MD_ANIM_MS in modal.jsx tracks this */
  position: fixed;
  inset: 0;
  z-index: 400;          /* the header is 50, the project lightbox 200 */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: max(var(--topbar-gap), 20px) var(--gutter);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* Blurs and darkens the page behind it, per the client. Fixed rather
   than inset in the flow, so it keeps covering the page when a tall
   panel scrolls the overlay. */
.md-scrim {
  position: fixed;
  inset: 0;
  background: color-mix(in oklab, var(--survey-ink) 48%, transparent);
  backdrop-filter: blur(16px) saturate(1.15);
  -webkit-backdrop-filter: blur(16px) saturate(1.15);
  opacity: 0;
  transition: opacity var(--md-anim) ease;
}
.md-root.is-shown .md-scrim { opacity: 1; }

.md-panel {
  position: relative;
  width: 100%;
  max-width: 640px;
  /* `auto` on both sides, so a panel taller than the overlay still
     keeps its top padding when it scrolls — `align-items: center`
     alone clips it. */
  margin: auto;
  background: color-mix(in oklab, var(--ground-white) 82%, white);
  border: 1px solid color-mix(in oklab, var(--survey-ink) 12%, transparent);
  border-radius: var(--radius-media-lg);
  padding: clamp(24px, 3vw, 40px);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.8) inset,
    0 0 0 1px rgba(255, 255, 255, 0.45) inset,
    0 40px 100px -32px rgba(26, 25, 22, 0.5),
    0 10px 24px -14px rgba(26, 25, 22, 0.3);
  outline: none;
  opacity: 0;
  transform: translateY(14px) scale(0.99);
  transition:
    opacity var(--md-anim) ease,
    transform var(--md-anim) cubic-bezier(0.2, 0.8, 0.2, 1);
}
.md-root.is-shown .md-panel { opacity: 1; transform: none; }

/* The panel itself takes focus on open, so a keyboard reader needs to
   see where it landed. Pointer users never trigger this. */
.md-panel:focus-visible {
  box-shadow:
    0 0 0 3px color-mix(in oklab, var(--laterite-gold) 30%, transparent),
    0 40px 100px -32px rgba(26, 25, 22, 0.5);
}

/* Sizes. `form` is step 5's, `media` is step 6's photo viewer, and
   `wide` is here for the layout viewer in step 7, which needs the room. */
.md-root.md-form  .md-panel { max-width: 640px; }
.md-root.md-media .md-panel { max-width: 1120px; }
.md-root.md-wide  .md-panel { max-width: 1040px; }

.md-close {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 38px;
  height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  border: 1px solid color-mix(in oklab, var(--survey-ink) 12%, transparent);
  background: color-mix(in oklab, white 55%, transparent);
  color: var(--survey-ink);
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}
.md-close:hover {
  background: var(--survey-ink);
  border-color: var(--survey-ink);
  color: var(--ground-white);
}

.md-head {
  /* Clear of the close button. */
  padding-right: 46px;
  margin-bottom: 26px;
}
.md-eyebrow {
  display: block;
  font-family: var(--font-eyebrow);
  font-size: var(--fs-micro);
  font-weight: var(--fw-strong);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--laterite-gold);
  margin-bottom: 10px;
}
.md-title {
  font-family: var(--font-display);
  font-size: clamp(26px, 3.2vw, 34px);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-heading);
  font-weight: var(--fw-display);
  margin: 0;
}
.md-title em { font-style: normal; font-weight: var(--fw-accent); }
.md-lead {
  margin: 12px 0 0;
  font-size: var(--fs-body-s);
  line-height: 1.55;
  font-weight: var(--fw-body);
  color: color-mix(in oklab, var(--survey-ink) 70%, transparent);
}

/* The panel is already the card, so the form inside it drops its own
   glass, border and padding rather than stacking a second one. */
.md-form .register-form {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}

@media (max-width: 640px) {
  .md-root { padding: 12px; }
  .md-panel { padding: 22px 18px 24px; border-radius: var(--radius-media); }
  .md-head { padding-right: 42px; margin-bottom: 20px; }
  .md-title { font-size: 24px; }
  .md-close { top: 12px; right: 12px; width: 34px; height: 34px; }
}

/* Body scroll lock. The scrollbar's width comes off the body as
   padding, and the fixed header has to take the same offset or it
   sits a few pixels wide of the content it floats over. On overlay
   scrollbars --md-sbw is 0 and both rules are no-ops. */
body.md-locked {
  overflow: hidden;
  padding-right: var(--md-sbw, 0px);
}
body.md-locked .topbar {
  padding-right: calc(var(--gutter) + var(--md-sbw, 0px));
}

@media (prefers-reduced-motion: reduce) {
  .md-scrim,
  .md-panel { transition: none; }
  .md-panel { transform: none; }
}

/* ─── Reveal animation ────────────────────────────────────────── */
/* Elements get .reveal (initial) and gain .in when scrolled into view.
   IntersectionObserver in app.jsx adds the .in class. */
.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition:
    opacity 0.9s cubic-bezier(0.2, 0.7, 0.2, 1),
    transform 1s cubic-bezier(0.2, 0.7, 0.2, 1);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
.reveal.in { opacity: 1; transform: translateY(0); }

.reveal-x {
  opacity: 0;
  transform: translateX(24px);
  transition:
    opacity 1s cubic-bezier(0.2, 0.7, 0.2, 1),
    transform 1s cubic-bezier(0.2, 0.7, 0.2, 1);
  transition-delay: var(--reveal-delay, 0ms);
}
.reveal-x.in { opacity: 1; transform: translateX(0); }

.reveal-fade {
  opacity: 0;
  filter: blur(6px);
  transition:
    opacity 1.1s ease,
    filter 1.1s ease;
  transition-delay: var(--reveal-delay, 0ms);
}
.reveal-fade.in { opacity: 1; filter: blur(0); }

/* Hero — animates on initial load, no observer needed */
@keyframes heroRise {
  0% { opacity: 0; transform: translateY(28px); }
  100% { opacity: 1; transform: translateY(0); }
}
@keyframes heroFade {
  0% { opacity: 0; filter: blur(8px); }
  100% { opacity: 1; filter: blur(0); }
}
/* The frame opens out of a small inset rather than fading in: the
   photograph is the whole hero, so it should arrive as a widening
   window. The radius travels with it (`round`), or the corners square
   off for the length of the animation. */
@keyframes heroFrameOpen {
  0%   { opacity: 0; clip-path: inset(9% 5% 9% 5% round var(--radius-media-lg)); }
  100% { opacity: 1; clip-path: inset(0 0 0 0 round var(--radius-media-lg)); }
}
/* The CTA arrives as a gold dot and opens into the button. The dot is
   the button itself, clipped to a 14px circle at its own centre — the
   background is already laterite gold, so nothing extra is drawn and
   the label is simply outside the clip until the pill widens past it.
   `round 999px` matches .btn's own radius; if that ever stops being a
   pill, this has to follow it.

   Two animations, deliberately on two elements: the wrapper pops the
   dot in (scale, with a little overshoot in the easing) and the button
   opens the clip. Putting both on the button would mean one `animation`
   shorthand carrying a transform and a clip-path on the same timeline,
   and the pop has to finish before the opening starts. `backwards`
   holds the dot state through the delay, so nothing flashes at full
   width on the first frame. */
@keyframes heroCtaDot {
  0%   { opacity: 0; transform: translateY(7px) scale(0.3); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes heroCtaOpen {
  0%   { clip-path: inset(calc(50% - 7px) calc(50% - 7px) round 999px); }
  100% { clip-path: inset(0 0 0 0 round 999px); }
}
/* The settle is on the <img>, not on .hero-photo — the scroll handler
   owns that node's transform and would overwrite it mid-animation. */
@keyframes heroPhotoSettle {
  0%   { transform: scale(1.09); }
  100% { transform: scale(1); }
}
.hero-frame     { animation: heroFrameOpen 1.25s 0.05s cubic-bezier(0.2,0.7,0.2,1) backwards; }
.hero-photo img { animation: heroPhotoSettle 2s 0.05s cubic-bezier(0.2,0.7,0.2,1) backwards; }
.hero-sky       { animation: heroFade 1.4s 0.15s ease backwards; }
.hero-headline  { animation: heroFade 1.2s 0.40s cubic-bezier(0.2,0.7,0.2,1) backwards; }
.hero-lead      { animation: heroRise 0.9s 0.62s cubic-bezier(0.2,0.7,0.2,1) backwards; }
.hero-cta       { animation: heroCtaDot 0.42s 0.95s cubic-bezier(0.34,1.45,0.5,1) backwards; }
.hero-cta .btn  { animation: heroCtaOpen 0.72s 1.34s cubic-bezier(0.2,0.8,0.2,1) backwards; }

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal-x, .reveal-fade,
  .hero-frame, .hero-photo, .hero-photo img, .hero-sky, .hero-copy, .hero-copy > *,
  .hero-cta, .hero-cta .btn,
  .pc, .pc *, .method-step, .method-step * {
    animation: none !important;
    transition: none !important;
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
}

/* ─── Card hover ──────────────────────────────────────────────── */
/* Old .plot-card hover block removed with the card redesign. */

/* Story portrait hover */
.story-portrait {
  transition: transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1),
              box-shadow 0.6s ease;
}
.story-portrait:hover {
  transform: translateY(-3px);
  box-shadow: 0 20px 50px -20px rgba(26, 25, 22, 0.35);
}
.story-portrait .placeholder-art {
  transition: transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.story-portrait:hover .placeholder-art {
  transform: scale(1.04);
}

/* Method step hover — top accent + icon lift */
.method-step {
  transition: background 0.4s ease, transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
  position: relative;
}
.method-step::after {
  content: "";
  position: absolute;
  left: 0;
  top: -1px;
  width: 0;
  height: 1px;
  background: var(--laterite-gold);
  transition: width 0.7s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.method-step:hover::after { width: 100%; }
.method-step .title { transition: color 0.4s ease; }
.method-step:hover .title { color: var(--laterite-gold); }
.method-step .icn {
  transition: transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1),
              color 0.4s ease;
  color: var(--contour-gray);
}
.method-step:hover .icn {
  transform: translateY(-4px) rotate(-3deg);
  color: var(--laterite-gold);
}

/* Story credits hover */
.story-credits dt { transition: color 0.3s ease; }
.story-credits .cred:hover dt { color: var(--laterite-gold); }

/* ─── Responsive ──────────────────────────────────────────────── */
@media (max-width: 1024px) {
  .portfolio-head, .method-head { grid-template-columns: 1fr; }
  .plot-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .method-grid { grid-template-columns: repeat(2, 1fr); }
  .method-step:nth-child(2) { border-right: 0; }
  .method-step:nth-child(1), .method-step:nth-child(2) { border-bottom: var(--rule); }
  .story-main { grid-template-columns: 1fr; }
  .story-portrait { aspect-ratio: 4 / 3; max-width: 520px; }
  .story-credits { grid-template-columns: repeat(2, 1fr); }
  .register-grid { grid-template-columns: 1fr; }
  .footer-mark-row { grid-template-columns: 1fr; gap: 24px; }
  .footer-cta { justify-content: flex-start; }
  .footer-top { grid-template-columns: repeat(2, 1fr); }
}

/* ── The menu range ──────────────────────────────────────────────
   900, not 640, since step 9. The nav is five links now — Projects,
   About, Method, Visit, Contact — and a fifth widens the centred pill
   past the room between the brand tile and the CTA: measured, it ran
   into both from 641 up to about 880. The pill was already touching
   the tile at 768 with four links, so the band was tight before this
   and the fifth is what broke it.

   Rather than shave the pill to buy 40px and be back here at the next
   link, the menu the phone already uses takes over the whole tablet
   range. The bar there is brand + coin, the CTA moves into the panel
   with the links, and nothing overlaps anywhere. Everything below is
   the machinery for that and nothing else — the layout rules that
   really do belong to phones are in their own 640 block further
   down. */
@media (max-width: 900px) {
  /* ── The menu ───────────────────────────────────────────────────
     The nav pill has no room here, so it becomes a coin at the right
     of the bar and the links drop out of it as a panel — with the CTA
     inside, since the bar cannot carry a separate one at this width.

     Selectors are three classes deep to match `.topbar.is-condensed
     .nav-items`, which otherwise keeps the panel clamped to 0 width;
     equal specificity, and this block is later in the file. */
  .topbar .nav {
    display: inline-flex;
    position: static;
    transform: none;
    margin-left: auto;
    padding: 0;
    gap: 0;
    height: var(--coin);
    background: none;
    border: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  /* The coin carries the glass now that the pill around it is gone. */
  .topbar .nav .nav-coin {
    display: inline-flex;
    width: var(--coin);
    height: var(--coin);
    border-radius: 999px;
    background: color-mix(in oklab, var(--ground-white) 55%, transparent);
    border: 1px solid color-mix(in oklab, var(--survey-ink) 9%, transparent);
    backdrop-filter: blur(20px) saturate(1.7);
    -webkit-backdrop-filter: blur(20px) saturate(1.7);
    box-shadow:
      0 1px 0 rgba(255, 255, 255, 0.8) inset,
      0 10px 26px -22px rgba(26, 25, 22, 0.30),
      0 2px 8px -6px rgba(26, 25, 22, 0.10);
    transition: background 0.3s ease, border-color 0.3s ease, color 0.3s ease;
  }
  .topbar.on-dark .nav .nav-coin {
    background: color-mix(in oklab, var(--survey-ink) 52%, transparent);
    border-color: color-mix(in oklab, var(--ground-white) 18%, transparent);
    color: color-mix(in oklab, var(--ground-white) 82%, transparent);
    box-shadow:
      0 1px 0 color-mix(in oklab, var(--ground-white) 14%, transparent) inset,
      0 12px 30px -24px rgba(0, 0, 0, 0.75);
  }
  /* The bars become an X while the panel is open. */
  .topbar .nav.is-open .nav-coin .bar:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
  .topbar .nav.is-open .nav-coin .bar:nth-child(2) { opacity: 0; transform: scaleX(0.3); }
  .topbar .nav.is-open .nav-coin .bar:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }
  .topbar .nav .nav-coin .bar {
    width: 16px;
    transition: transform 0.42s cubic-bezier(0.2, 0.7, 0.2, 1),
                opacity 0.24s ease;
  }

  /* The panel. Kept mounted and toggled, so it animates out as well as
     in; `visibility` is what keeps it off the tab order when closed. */
  .topbar .nav .nav-items {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    width: max-content;
    min-width: 224px;
    max-width: calc(100vw - 2 * var(--gutter));
    padding: 10px;
    border-radius: 18px;
    background: color-mix(in oklab, var(--ground-white) 96%, transparent);
    border: 1px solid color-mix(in oklab, var(--survey-ink) 10%, transparent);
    backdrop-filter: blur(24px) saturate(1.6);
    -webkit-backdrop-filter: blur(24px) saturate(1.6);
    box-shadow: 0 26px 50px -24px rgba(26, 25, 22, 0.38);
    overflow: visible;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-10px) scale(0.96);
    transform-origin: top right;
    transition: opacity 0.28s ease,
                transform 0.34s cubic-bezier(0.2, 0.7, 0.2, 1),
                visibility 0s linear 0.34s;
  }
  .topbar .nav.is-open .nav-items {
    opacity: 1;
    visibility: visible;
    transform: translateY(0) scale(1);
    transition: opacity 0.28s ease,
                transform 0.42s cubic-bezier(0.2, 0.7, 0.2, 1),
                visibility 0s;
  }
  .topbar.on-dark .nav .nav-items {
    background: color-mix(in oklab, var(--survey-ink) 96%, transparent);
    border-color: color-mix(in oklab, var(--ground-white) 16%, transparent);
  }

  /* Each row rides in a beat after the panel. --i comes from the JSX. */
  .topbar .nav .nav-items > * {
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.2, 0.7, 0.2, 1);
  }
  .topbar .nav.is-open .nav-items > * {
    opacity: 1;
    transform: translateY(0);
    transition-delay: calc(90ms + var(--i, 0) * 45ms);
  }

  /* The dot is the desktop active marker and it only exists on one
     link, which indented that row against the others. The row's own
     background says the same thing here. */
  .topbar .nav .nav-items .nav-link {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 12px 14px;
    border-radius: 11px;
    font-size: var(--fs-body-s);
    transition: background 0.25s ease, color 0.25s ease;
  }
  /* The panel rows already are rounded boxes; they keep their soft
     tint rather than going solid ink, which at full row width would be
     a slab. The bar's ::after box is switched off here, and the label
     colours have to be restated or the bar's white-on-ink rule reaches
     into the panel and puts white text on a 6% tint. */
  .topbar .nav .nav-items .nav-link::after { display: none; }
  .topbar .nav .nav-items .nav-link:hover,
  .topbar .nav .nav-items .nav-link.active {
    background: color-mix(in oklab, var(--survey-ink) 6%, transparent);
    color: var(--survey-ink);
  }
  .topbar.on-dark .nav .nav-items .nav-link:hover,
  .topbar.on-dark .nav .nav-items .nav-link.active {
    background: color-mix(in oklab, var(--ground-white) 10%, transparent);
    color: var(--ground-white);
  }

  .nav-cta {
    display: block;
    margin-top: 8px;
    padding-top: 10px;
    border-top: 1px solid color-mix(in oklab, var(--survey-ink) 10%, transparent);
  }
  .topbar.on-dark .nav-cta {
    border-top-color: color-mix(in oklab, var(--ground-white) 14%, transparent);
  }
  .nav-cta .btn {
    width: 100%;
    justify-content: space-between;
    height: 46px;
  }
  /* The condensed-coin rules collapse `.cta-label` and zero the gap on
     every `.btn-compact` in the header — including this one, which left
     the menu's button as a bare arrow once the page was scrolled. Four
     classes deep so it outranks them. */
  .topbar.is-condensed .nav-cta .cta-label { max-width: none; }
  .topbar.is-condensed .nav-cta .btn-compact {
    padding: 0 8px 0 16px;
    gap: 10px;
  }

  /* The bar's own CTA is redundant once it is in the menu. */
  .topbar .topbar-right { display: none; }

  /* Tap-anywhere-else to close, and the cue that a layer is open. */
  .nav-scrim {
    position: fixed;
    inset: 0;
    z-index: 0;
    background: color-mix(in oklab, var(--survey-ink) 30%, transparent);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
  }
  .topbar.nav-open .nav-scrim { opacity: 1; pointer-events: auto; }
}

/* Above the menu range the CTA lives in the bar, never in the menu. */
@media (min-width: 901px) {
  .nav-cta { display: none; }
  .nav-scrim { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .topbar .nav .nav-items,
  .topbar .nav .nav-items > *,
  .topbar .nav .nav-coin .bar,
  .nav-scrim { transition: none !important; }
}

@media (max-width: 640px) {
  .phone-link { display: none;
  font-weight: var(--fw-strong);
}
  .topbar-right .btn { height: 40px; padding: 0 14px; font-size: var(--fs-meta); }
  .plot-cards { grid-template-columns: minmax(0, 1fr); }
  .method-grid { grid-template-columns: 1fr; }
  .method-step { border-right: 0; border-bottom: var(--rule); }
  .method-step:last-child { border-bottom: 0; }
  .story-cols { grid-template-columns: 1fr; }
  .form-row.two { grid-template-columns: 1fr; }
}
