:root {
  /* brand — the crest in assets/img/logo is gold on a deep forest field, and
     that field is where this palette comes from. It was sampled off the
     artwork rather than picked by eye: the green pixels of the badge sit at
     #042918 at the 75th percentile, and --pine-600 below is that colour. The
     --forest names stop being historical here and mean what they say again.
     (--forest is load-bearing either way: it shares a substring with the
     .section--forest class, so the name cannot change.)

     One ladder, darkest first, so every band on the page is a step on the
     same scale instead of six unrelated near-blacks. Green is carried by the
     grounds and the washes only — type, buttons and the gold are untouched,
     because a page that is green everywhere stops reading as expensive and
     starts reading as a colour scheme. */
  /* The pine scale stays — it is the crest's own green, sampled off the
     artwork — but it is an ACCENT, not the ground. Painting every band with
     it turned the whole page into one colour, and a site that is green
     everywhere stops reading as expensive and starts reading as a theme.
     Green now appears in a handful of deliberate places only: the primary
     call to action, the portfolio band, and the hairlines. Everything else
     is neutral, which is what lets the green and the gold register at all. */
  --pine-900: #03110b;
  --pine-800: #05180f;
  --pine-700: #072415;
  --pine-600: #042918;   /* sampled straight from the crest */
  --pine-500: #0b3521;

  /* Grounds: neutral near-black with only a breath of green in them, so they
     sit under the crest without competing with it. These read as black. */
  --ink: #070807;
  --ink-90: rgba(7, 8, 7, .93);
  --forest: #0d0f0e;
  --forest-2: #151816;
  --gold: #d5a83f;
  --gold-lt: #f4e0a6;
  --gold-dk: #8f6a1c;
  --cream: #0b0d0c;
  --sand: #121514;
  --paper: #0f1110;
  --char: #f5f2ec;
  --body: rgba(245, 242, 236, .72);
  --muted: rgba(245, 242, 236, .44);
  --line: rgba(255, 255, 255, .09);
  --line-dark: rgba(213, 168, 63, .22);
  /* The lettering in the logo is a polished gradient, not flat gold. Applied
     to wordmarks and key rules so type matches the mark. */
  --gold-sheen: linear-gradient(102deg, #8f6a1c 0%, #d5a83f 24%, #f6e6b4 47%, #d5a83f 70%, #96701f 100%);
  /* Success stays green on purpose — it is a status, not a brand colour, and
     the palette has no green left to borrow. */
  --ok: #2f6b4a;

  /* type */
  --f-display: "Cinzel", "Cormorant Garamond", Georgia, serif;
  --f-serif: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --f-sans: "Jost", "Segoe UI", system-ui, -apple-system, sans-serif;

  /* rhythm */
  --shell: 1240px;
  --gut: clamp(18px, 4vw, 40px);
  --sec: clamp(64px, 8vw, 120px);
  --r-sm: 4px;
  --r: 8px;
  --r-lg: 16px;

  /* effects */
  --sh-1: 0 2px 12px rgba(0, 0, 0, .45);
  --sh-2: 0 14px 40px rgba(0, 0, 0, .55);
  --sh-3: 0 30px 80px rgba(0, 0, 0, .65);
  --ease: cubic-bezier(.22, .61, .36, 1);
  /* Overshoots past 1 and settles back -- the difference between a heading
     that snaps into place and one that glides there. Used by the hero
     chapters, which are scrubbed and so have no time to glide. */
  --pop: cubic-bezier(.2, 1.5, .32, 1);
  --t: .38s var(--ease);
  /* The header is out of flow, so these three are the single source of truth
     for how much room it needs. --hdr-safe is what every first-screen section
     pads itself by; change --hdr-h or --hdr-top and the clearance follows.
     (+2px is the capsule's own top and bottom border.) */
  --hdr-h: 70px;                 /* capsule inner height, at rest */
  --hdr-top: 46px;               /* capsule offset from the top, at rest */
  --hdr-gap: 22px;               /* breathing room under the capsule */
  --hdr-safe: calc(var(--hdr-top) + var(--hdr-h) + 2px + var(--hdr-gap));
  /* Capsule inset from the viewport edge, and its own inner padding. The top
     bar borrows both so its phone number lands directly above the logo — the
     two strips are read as one piece of chrome, so they have to share an edge. */
  --hdr-gutter: clamp(18px, 2.6vw, 38px);
  --hdr-pad: clamp(20px, 2.2vw, 34px);
}

/* ---------- 2. Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
/* The browser's own [hidden] rule loses to ANY author rule that sets display,
   and plenty below do — .card is display:flex, .lb button is display:grid.
   That made el.hidden = true a no-op on the things the JS hides: the category
   filters on Coming Soon / Available Now / Projects, the lightbox arrows, the
   rotating strip. Author-level and !important so `hidden` means hidden. */
[hidden] { display: none !important; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* `clip` (unlike `hidden`) does not create a scroll container, so sticky
     positioning and smooth scrolling keep working. Guards against any
     decorative element with a negative offset causing sideways scroll. */
  overflow-x: clip;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
body {
  font-family: var(--f-sans);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.68;
  color: var(--body);
  /* The page ground is the deepest tone; --paper is now the RAISED surface a
     card sits on. Keeping them the same value would flatten every panel into
     its own background. */
  background: var(--ink);
  -webkit-font-smoothing: antialiased;
  /* `clip`, not `hidden` — `hidden` here would make <body> a scroll
     container and break `position: sticky` for the header and the film
     hero's stage. Same reasoning as the rule on <html> above. */
  overflow-x: clip;
}
body.is-locked { overflow: hidden; }
img, svg, video, iframe { display: block; max-width: 100%; }
img { height: auto; }
/* Safety net: inline icons carry a viewBox but often no width/height, which
   otherwise renders them at the SVG default of 300x150. Any component rule
   that sets an explicit size still wins on specificity. */
svg { width: 1em; height: 1em; }
p > svg, span > svg, a:not([class]) > svg { display: inline-block; vertical-align: -.14em; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; padding: 0; }
:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; border-radius: 2px; }
::selection { background: var(--gold); color: var(--ink); }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: fixed; top: 8px; left: 8px; z-index: 999;
  transform: translateY(-160%);
  background: var(--gold); color: var(--ink);
  padding: 10px 18px; font-weight: 600; border-radius: var(--r-sm);
  transition: transform .2s;
}
.skip-link:focus { transform: none; }

/* ---------- 3. Type scale ---------- */
h1, h2, h3, h4, h5 { font-family: var(--f-serif); font-weight: 600; line-height: 1.14; color: var(--char); letter-spacing: -.01em; }
h1 { font-size: clamp(2.4rem, 5.6vw, 4.35rem); }
h2 { font-size: clamp(1.95rem, 4vw, 3.05rem); }
h3 { font-size: clamp(1.35rem, 2.1vw, 1.75rem); }
h4 { font-size: clamp(1.1rem, 1.5vw, 1.28rem); }
p + p { margin-top: 1em; }
strong { font-weight: 600; color: var(--char); }

.eyebrow {
  display: inline-flex; align-items: center; gap: .7em;
  font-family: var(--f-sans); font-size: .74rem; font-weight: 500;
  letter-spacing: .3em; text-transform: uppercase; color: var(--gold-dk);
  margin-bottom: 1.1rem;
}
.eyebrow::before { content: ""; width: 34px; height: 1px; background: var(--gold); flex: none; }
.eyebrow--center { justify-content: center; }
.eyebrow--center::after { content: ""; width: 34px; height: 1px; background: var(--gold); flex: none; }
.eyebrow--light { color: var(--gold-lt); }

.lede { font-size: clamp(1.03rem, 1.35vw, 1.16rem); color: var(--body); }
.muted { color: var(--muted); }
.wordmark { font-family: var(--f-display); font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }

/* ---------- 4. Layout ---------- */
.shell { width: 100%; max-width: var(--shell); margin-inline: auto; padding-inline: var(--gut); }
.shell--wide { max-width: 1440px; }
.shell--narrow { max-width: 820px; }
.section { padding-block: var(--sec); }
.section--tight { padding-block: clamp(46px, 5.5vw, 76px); }
.section--cream { background: var(--cream); }
.section--sand { background: var(--sand); }
/* A faint warm glow off the top edge keeps the near-black bands from reading
   as dead flat, and echoes the light on the badge. */
.section--ink {
  background:
    radial-gradient(120% 78% at 50% 0%, rgba(213, 168, 63, .07), transparent 68%),
    var(--ink);
  color: rgba(255, 255, 255, .74);
}
.section--ink h1, .section--ink h2, .section--ink h3, .section--ink h4 { color: #fff; }
.section--forest {
  background:
    radial-gradient(120% 78% at 50% 0%, rgba(213, 168, 63, .06), transparent 68%),
    var(--forest);
  color: rgba(255, 255, 255, .74);
}
.section--forest h2, .section--forest h3, .section--forest h4 { color: #fff; }

.head { max-width: 720px; margin-bottom: clamp(38px, 4.5vw, 62px); }
.head--center { margin-inline: auto; text-align: center; }
.head p { margin-top: 1.1rem; }

.grid { display: grid; gap: clamp(20px, 2.6vw, 34px); }
.g-2 { grid-template-columns: repeat(2, 1fr); }
.g-3 { grid-template-columns: repeat(3, 1fr); }
.g-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1000px) { .g-4 { grid-template-columns: repeat(2, 1fr); } .g-3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 700px)  { .g-2, .g-3, .g-4 { grid-template-columns: 1fr; } }

.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(34px, 5vw, 76px); align-items: center; }
.split--media-first .split__media { order: -1; }
.split--wide { grid-template-columns: 1.55fr 1fr; }
.split--top { align-items: flex-start; }
@media (max-width: 900px) {
  .split, .split--wide { grid-template-columns: 1fr; }
  .split--media-first .split__media { order: 0; }
}

/* sticky sidebar column — released on small screens */
.sticky-col { position: sticky; top: 120px; }
@media (max-width: 900px) { .sticky-col { position: static; top: auto; } }

/* ---------- 5. Buttons ---------- */
.btn {
  /* Back to the polished gold sheen -- the same sweep as the lettering in the
     logo. A pine fill was tried here to give the CTA its own colour away from
     the gold furniture; it read as flat and heavy against the photography, so
     gold it is. Variants override --btn-bg with a plain colour. */
  --btn-bg: var(--gold-sheen); --btn-fg: var(--ink); --btn-bd: var(--gold-dk);
  --btn-lip: rgba(255, 255, 255, .5);
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: .6em;
  padding: 1.02em 2.1em; min-height: 52px;
  font-family: var(--f-sans); font-size: .8rem; font-weight: 600;
  letter-spacing: .17em; text-transform: uppercase; text-align: center;
  background: var(--btn-bg); color: var(--btn-fg);
  border: 1px solid var(--btn-bd); border-radius: 2px;
  cursor: pointer; overflow: hidden; isolation: isolate;
  transition: color var(--t), border-color var(--t), background var(--t), transform var(--t), box-shadow var(--t);
}
/* The dark face rises over the metal one on hover, the way a bevelled plate
   takes a shadow when pressed. */
.btn::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--forest); transform: translateY(101%);
  transition: transform var(--t);
}
/* hairline catch-light along the top edge, the way a bevelled metal face has
   one — fades out as the dark fill rises on hover */
.btn::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 1px;
  background: var(--btn-lip); opacity: 1; transition: opacity var(--t);
}
.btn:hover { color: #fff; border-color: var(--gold); transform: translateY(-2px); box-shadow: var(--sh-2); }
.btn:hover::after { transform: none; }
.btn:hover::before { opacity: 0; }
.btn:active { transform: none; }
.btn svg { width: 16px; height: 16px; flex: none; }

/* the catch-light belongs only to the metal face */
.btn--ghost, .btn--light, .btn--solid-dark { --btn-lip: transparent; }
/* On ink, an outline button has to be drawn in light — the old dark face and
   near-black border were chosen against paper and simply vanish here. */
.btn--ghost { --btn-bg: transparent; --btn-fg: var(--char); --btn-bd: rgba(255, 255, 255, .28); }
.btn--ghost:hover { border-color: var(--gold); }
.btn--light { --btn-bg: transparent; --btn-fg: #fff; --btn-bd: rgba(255, 255, 255, .4); }
.btn--light::after { background: var(--gold); }
.btn--light:hover { color: var(--ink); border-color: var(--gold); }
/* Its whole point was to be the dark button on a pale band. With no pale band
   left it becomes the raised-surface button, edged in gold so it still reads
   as a distinct object rather than a hole in the page. */
.btn--solid-dark { --btn-bg: var(--forest-2); --btn-fg: var(--char); --btn-bd: rgba(213, 168, 63, .34); }
.btn--solid-dark::after { background: var(--gold); }
.btn--solid-dark:hover { color: var(--ink); border-color: var(--gold); }
.btn--sm { padding: .8em 1.5em; min-height: 44px; font-size: .72rem; }
.btn--block { width: 100%; }

.btn-row { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 2.1rem; }
.btn-row--center { justify-content: center; }

.txtlink {
  display: inline-flex; align-items: center; gap: .55em;
  font-size: .78rem; font-weight: 600; letter-spacing: .18em; text-transform: uppercase;
  color: var(--gold-dk); padding-bottom: 4px;
  border-bottom: 1px solid var(--line-dark); transition: color var(--t), border-color var(--t), gap var(--t);
}
.txtlink svg { width: 14px; height: 14px; flex: none; }
.txtlink:hover { color: var(--char); border-color: var(--gold); gap: 1em; }
.txtlink--light { color: var(--gold-lt); border-color: rgba(246, 230, 180, .3); }
.txtlink--light:hover { color: #fff; border-color: #fff; }

/* ---------- 6. Top bar ---------- */
.topbar {
  background: var(--ink); color: rgba(255, 255, 255, .68);
  font-size: .79rem; border-bottom: 1px solid rgba(255, 255, 255, .07);
}
/* 38px, not 44: the capsule below had to sit low enough to clear this strip,
   and every pixel here was a pixel the header started further down the page. */
.topbar__in {
  /* Not capped, and padded to the capsule's content edge rather than .shell's
     gutter: capped at 1440px on a 1920px screen this strip stopped 240px short
     of where the capsule below it ended, and the two misaligned edges were the
     most visible thing in the header. */
  max-width: none;
  padding-inline: calc(var(--hdr-gutter) + var(--hdr-pad));
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; min-height: 38px;
}
.topbar__set { display: flex; align-items: center; gap: 26px; }
.topbar a { display: inline-flex; align-items: center; gap: .55em; transition: color var(--t); }
.topbar a:hover { color: var(--gold-lt); }
.topbar svg { width: 14px; height: 14px; color: var(--gold); flex: none; }
.topbar__socials { display: flex; gap: 8px; }
.topbar__socials a {
  width: 30px; height: 30px; display: grid; place-items: center;
  border: 1px solid rgba(255, 255, 255, .16); border-radius: 50%;
  transition: background var(--t), border-color var(--t), color var(--t);
}
.topbar__socials a:hover { background: var(--gold); border-color: var(--gold); color: var(--ink); }
.topbar__socials svg { width: 13px; height: 13px; color: currentColor; }
@media (max-width: 980px) { .topbar { display: none; } }

/* ---------- 7. Header / nav ---------- */
.hdr {
  position: sticky; top: 0; z-index: 120;
  background: var(--ink);
  transition: box-shadow var(--t), background var(--t);
}
/* a gold hairline that fades at both ends, rather than a flat grey rule */
.hdr::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(213, 168, 63, .5) 22%, rgba(246, 230, 180, .7) 50%, rgba(213, 168, 63, .5) 78%, transparent);
}
/* ---------- the two scrolled states ----------
   Flush at the top of the page the bar is flat ink with the hairline resting.
   `is-stuck` lifts it off the page: a deeper fill, a shadow, and the hairline
   brightening. `is-tight` then condenses it — the contact strip retracts and
   the bar pulls in around a smaller mark, handing the height back to the
   content. Both are transitions on the same element, so the two read as one
   continuous move rather than a jump between layouts. */
/* ==========================================================================
   The header — one bar that narrows
   --------------------------------------------------------------------------
   A single object in a single design: an ink capsule, blurred, edged in gold.
   Scrolling does not swap it for something else — it only takes width away.

     at rest   nearly the full window, sitting just inside the margins
     scrolled  drawn in to a centred 1120px and lifted toward the top

   Because only width, offset and depth change, the two states are the same
   element transitioning — no morph between different layouts, and nothing
   entering or leaving the screen.

   It is FIXED rather than sticky. #site-header is lifted out of the flow so
   the opening photograph starts at y=0 and runs full-bleed behind the bar;
   an element inside an out-of-flow parent has no scroll context to stick to,
   so sticky would simply never fire.

   No `overflow` here: the drop panels are positioned children and clipping
   them to the capsule would cut every submenu off.
   ========================================================================== */
#site-header {
  position: absolute; top: 0; left: 0; right: 0;
  z-index: 120;
}

/* The contact strip stays on the photograph unfilled, so the capsule below is
   the only object carrying a fill and reads as the single piece of chrome. */
.topbar {
  background: transparent;
  border-bottom: 1px solid rgba(255, 255, 255, .1);
  margin-inline: 0;
}

.hdr {
  position: fixed;
  /* clears the contact strip at rest, then rises as that strip retracts */
  top: var(--hdr-top);
  left: 50%;
  transform: translateX(-50%);
  width: calc(100% - var(--hdr-gutter) * 2);
  margin: 0;
  border-radius: 999px;
  border: 1px solid rgba(213, 168, 63, .2);
  /* #072918 across the whole capsule — the crest's own field colour, so the
     bar and the mark on it are the same green. Kept slightly translucent
     rather than flat so the backdrop-filter below still has something to do:
     the bar picks up a little of whatever it is passing over, which is what
     makes it read as glass on the photograph instead of a printed strip.
     White nav on this is far past AA, so nothing is traded for it.

     Stepped down from the sampled #072918 to rgb(4 24 14). The crest colour
     was picked to read on a small badge; spread across a full bar the same
     value reads mid, not deep -- a large area of any colour looks lighter
     than a small one. This is the same hue held at a lower value, so it still
     matches the mark while the bar itself sits back. */
  background: rgba(4, 24, 14, .93);
  backdrop-filter: blur(20px) saturate(1.3);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  box-shadow: 0 14px 40px rgba(0, 0, 0, .42);
  transition: width .55s var(--ease), top .55s var(--ease),
              background .45s var(--ease), border-color .45s var(--ease),
              box-shadow .45s var(--ease);
}
/* The bar has its own edge now, so the old full-bleed hairline would hang off
   both ends of it. The gold lives in the border instead. */
.hdr::after { display: none; }

/* is-stuck only deepens it — the shape is the same object either way. */
/* Deepens on scroll — same green, less of the page showing through, because
   once it is over content rather than over the hero it has to hold its own
   edge. */
.hdr.is-stuck {
  background: rgba(4, 24, 14, .97);
  border-color: rgba(213, 168, 63, .27);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .55);
}

/* ---------- narrowed ---------- */
.hdr.is-tight {
  width: min(1120px, calc(100% - 26px));
  top: clamp(9px, 1.1vw, 15px);
}
.hdr.is-tight .hdr__in { min-height: 60px; padding-inline: clamp(18px, 2vw, 28px); }
.hdr.is-tight .brand { padding-block: 3px; }
.hdr.is-tight .brand__mark { height: 44px; }
.hdr.is-tight .nav__link { padding-block: 8px; }
.hdr.is-tight .hdr__cta .btn { padding-block: 7px; min-height: 40px; }

/* The row inside is capped separately from the capsule so the content keeps
   its measure while the shell around it moves. */
.hdr__in { padding-inline: var(--hdr-pad); }
/* A capsule with a square-cornered button inside it fights its own shape. */
.hdr__cta .btn { border-radius: 999px; }
/* The panels hang off a curved edge, so they gain clearance and lose the seam
   that assumed a straight one. */
.nav__sub { top: calc(100% + 10px); }
.nav__sub::before { display: none; }

/* Sizes transition; OPACITY DELIBERATELY DOES NOT.
   The opening timeline animates .brand and .hdr__cta with GSAP, which writes
   an inline opacity every frame. A CSS transition on the same property treats
   each of those frames as a fresh transition to chase, so the two fight and
   the element never arrives — which is exactly how the logo and the CTA came
   to render as ghosts. */
.brand__mark, .hdr__in, .brand, .nav__link, .hdr__cta .btn {
  transition: height .45s var(--ease), min-height .45s var(--ease),
              padding .45s var(--ease), margin .45s var(--ease);
}

/* ---------- room for the overlay ----------
   With the chrome out of flow, an interior banner would start beneath it and
   put its breadcrumbs under the navigation — which is exactly what it was
   doing. The two rules that used to live here set `padding-top` on .banner and
   .hero__in, but BOTH elements set `padding-block` again further down this
   file. Equal specificity, later wins, so the whole allowance was quietly
   discarded and the breadcrumbs sat 6px behind the capsule.

   The clearance now lives on the same declarations that set the padding (see
   .hero__in and .banner below), as `max(own padding, --hdr-safe)` — so it
   cannot be overwritten by a later padding-block, and a section never loses
   its own generous spacing just to satisfy the header. */

@media (max-width: 980px) {
  /* No contact strip below 980px, so the bar starts high — and --hdr-safe
     shrinks with it, since it is derived from --hdr-top. */
  :root { --hdr-top: clamp(9px, 1.1vw, 15px); }
}
@media (max-width: 700px) {
  :root { --hdr-top: 8px; }
  .hdr, .hdr.is-tight {
    width: calc(100% - 16px); border-radius: 18px;
  }
  .hdr .hdr__in, .hdr.is-tight .hdr__in { padding-inline: 14px; }
}



/* The contact strip retracts rather than disappearing — it slides up under
   the bar and gives its height back, which is what makes the whole header
   feel like one mechanism instead of two stacked bars. */
.topbar {
  overflow: hidden;
  transition: max-height .5s var(--ease), opacity .35s var(--ease),
              transform .5s var(--ease);
  max-height: 60px;
}
.topbar.is-away {
  max-height: 0; opacity: 0; transform: translateY(-100%);
  pointer-events: none;
}
/* max-width:none, and it has to be set HERE. The rule further up already said
   `max-width: none` for exactly this reason, but this declaration came later
   with the same specificity and quietly put the 1440px cap back — which is why
   a capsule drawn 1844px wide on a 1920px screen carried its logo and its CTA
   200px in from its own ends, with visible dead space at both. The capsule is
   the thing that decides the width; the row inside it just fills. */
.hdr__in { max-width: none; display: flex; align-items: center; justify-content: space-between; gap: 14px; min-height: var(--hdr-h); }
/* The gap stays at 14px at every width: the row is capped at 1440px, and with
   eight nav items plus the CTA there is nothing spare to give it. */

.brand { display: flex; align-items: center; gap: 12px; min-width: 0; padding-block: 5px; }
/* The badge art carries its own round edge on a transparent ground, so it is
   NOT masked or ringed here. A border-radius:50% circle over art that is a
   331x305 ellipse never lines up — that mismatch, plus a 1px gold ring sitting
   on the badge's own painted edge, was reading as a soft double outline.
   60px with 5px padding-block fills --hdr-h (70px) exactly, so the mark is as
   large as it can be without the header changing height. Keep the two in step:
   the mark is what sets the bar's height, so growing it here silently undoes
   the clearance every first-screen section is padded by. */
.brand__mark {
  height: 60px; width: auto; flex: none; object-fit: contain;
}
.brand__txt { display: flex; flex-direction: column; line-height: 1; min-width: 0; }
.brand__name {
  font-family: var(--f-display); font-size: 1rem; font-weight: 700;
  letter-spacing: .07em; color: #fff; text-transform: uppercase; white-space: nowrap;
}
.brand__sub {
  font-size: .56rem; font-weight: 500; letter-spacing: .25em; text-transform: uppercase;
  color: var(--gold); margin-top: 6px; white-space: nowrap;
}
/* roomier viewports can afford the fuller lockup */
/* The tight band: the desktop nav appears at 1340px, but between there and
   about 1520px the eight nav items plus the CTA leave the brand almost no
   room. The mark steps back to roughly its old size so the wordmark and the
   first nav item keep a real gap instead of touching. */
@media (min-width: 1340px) and (max-width: 1519px) {
  .brand { gap: 10px; }
  .brand__mark { height: 58px; }
  .brand__name { font-size: .93rem; letter-spacing: .05em; }
  .brand__sub { font-size: .52rem; letter-spacing: .18em; margin-top: 5px; }
}

/* There is deliberately NO wide-viewport enlargement of the brand.
   .hdr__in is capped at 1440px, so beyond that width the header gains no
   space whatsoever — the old rules here grew the wordmark and the flex gap on
   wide screens, which was affordable beside a 54px mark and is not beside a
   72px one. The mark is the thing that should read at a glance, so it keeps
   the width and the lettering stays at its base size. */
/* Phones: stack the wordmark over two lines and drop the descriptor so the
   lockup plus the burger always fit inside the viewport. */
@media (max-width: 600px) {
  .brand__mark { height: 60px; }
  .brand__name { display: flex; flex-direction: column; gap: 5px; font-size: .95rem; letter-spacing: .09em; }
  .brand__name > span:last-child { font-size: .68rem; letter-spacing: .2em; color: var(--gold); font-weight: 600; }
  .brand__sub { display: none; }
}
@media (max-width: 380px) {
  .brand { gap: 10px; }
  .brand__mark { height: 52px; }
  .brand__name { font-size: .86rem; letter-spacing: .06em; }
  .brand__name > span:last-child { font-size: .62rem; letter-spacing: .16em; }
}

.nav { display: flex; align-items: center; flex: none; }
.nav > ul { display: flex; align-items: center; }
.nav__item { position: relative; }
.nav__link {
  display: inline-flex; align-items: center; gap: .4em;
  padding: 12px 9px; font-size: .74rem; font-weight: 500;
  letter-spacing: .05em; text-transform: uppercase;
  color: rgba(255, 255, 255, .82); white-space: nowrap;
  transition: color var(--t);
}
/* No wide-viewport bump for the nav links either. The old rule here added 4px
   of padding per side plus a larger size and looser tracking, which across
   eight items came to roughly 110px of extra width — inside a row that is
   capped at 1440px and therefore never gains any. That was the last of the
   three wide-screen enlargements pushing the wordmark into "Home". */
.nav__link:hover, .nav__item:focus-within > .nav__link { color: var(--gold-lt); }
.nav__link .caret { width: 9px; height: 9px; transition: transform var(--t); opacity: .7; }
.nav__item:hover .caret, .nav__item:focus-within .caret { transform: rotate(180deg); }
.nav__link.is-active { color: var(--gold); }

/* One rule for the rule under every item, drawn from the centre out.
   It used to exist only on the active link, appearing fully formed; giving
   every link the same hairline and scaling it from the middle is what turns
   a hover from a colour change into a piece of craft. The active item simply
   starts at full width and stays there. */
.nav__link::after {
  content: ""; position: absolute; left: 9px; right: 9px; bottom: 4px; height: 1px;
  background: var(--gold-sheen);
  transform: scaleX(0); transform-origin: 50% 50%;
  transition: transform .42s var(--ease);
}
.nav__link:hover::after,
.nav__item:focus-within > .nav__link::after,
.nav__link.is-active::after { transform: scaleX(1); }

/* ---------- the drop panel ----------
   It used to be a sheet of light paper falling out of a black bar, which was
   the single most jarring thing in the header. Now it is the same material as
   the bar itself — ink, blurred, edged in gold — so it reads as the header
   extending downward rather than as a different component appearing. */
.nav__sub {
  position: absolute; top: calc(100% + 4px); left: -6px; min-width: 268px;
  padding: 7px;
  /* Matched to the bar, a shade deeper. These hang off the capsule, so a
     neutral panel under a green bar read as two unrelated objects; a step
     down in the same green reads as the bar opening. */
  background: rgba(3, 17, 10, .98);
  backdrop-filter: blur(16px) saturate(1.2);
  -webkit-backdrop-filter: blur(16px) saturate(1.2);
  border: 1px solid rgba(213, 168, 63, .16);
  box-shadow: 0 26px 64px rgba(8, 9, 8, .6);
  opacity: 0; visibility: hidden; transform: translateY(10px);
  transition: opacity .28s var(--ease), transform .38s var(--ease), visibility .28s;
}
/* the gold seam where the panel meets the bar */
.nav__sub::before {
  content: ""; position: absolute; left: -1px; right: -1px; top: -1px; height: 1px;
  background: var(--gold-sheen);
}
.nav__item:hover > .nav__sub,
.nav__item:focus-within > .nav__sub { opacity: 1; visibility: visible; transform: none; }

.nav__sub a {
  position: relative; display: block;
  padding: 11px 15px 11px 17px;
  font-size: .82rem; letter-spacing: .03em;
  color: rgba(255, 255, 255, .76);
  /* The stagger is carried by TRANSFORM ALONE, deliberately.
     Hiding each item with opacity:0 and restoring it on the parent's :hover
     makes the whole menu depend on that one rule matching — and the failure
     mode is a panel that opens empty, which is far worse than a missing
     flourish. A 7px offset that never resolves is invisible; an invisible
     navigation is not. The panel's own opacity/visibility already keeps the
     items out of sight while it is closed. */
  transform: translateX(-7px);
  transition: transform .3s var(--ease),
              color var(--t), background var(--t), padding-left var(--t);
}
/* Delays live on the hover state only, so the items arrive one after another
   but leave together instead of unwinding in slow motion. */
.nav__item:hover > .nav__sub a,
.nav__item:focus-within > .nav__sub a { transform: none; }
.nav__item:hover > .nav__sub li:nth-child(1) a { transition-delay: .04s; }
.nav__item:hover > .nav__sub li:nth-child(2) a { transition-delay: .09s; }
.nav__item:hover > .nav__sub li:nth-child(3) a { transition-delay: .14s; }

/* a gold tick that grows out of the left edge on hover */
.nav__sub a::before {
  content: ""; position: absolute; left: 6px; top: 50%; margin-top: -.5px;
  width: 0; height: 1px; background: var(--gold);
  transition: width .3s var(--ease);
}
.nav__sub a:hover {
  color: var(--gold-lt);
  background: rgba(213, 168, 63, .07);
  padding-left: 26px;
}
.nav__sub a:hover::before { width: 12px; }
.nav__sub a.is-active { color: var(--gold); }
.nav__sub a.is-active::before { width: 12px; }
@media (max-width: 1339px) { .nav { display: none; } }

.hdr__cta { display: flex; align-items: center; gap: 10px; flex: none; }
@media (max-width: 1339px) { .hdr__cta .btn { display: none; } }

.burger {
  display: none; width: 46px; height: 46px; flex: none;
  border: 1px solid rgba(255, 255, 255, .22); border-radius: 2px;
  padding: 0 12px; place-items: center;
}
.burger span { display: block; width: 100%; height: 1.5px; background: #fff; transition: transform var(--t), opacity var(--t); }
.burger span + span { margin-top: 5px; }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }
@media (max-width: 1339px) { .burger { display: grid; } }

/* mobile drawer
   The host is exactly viewport-sized and clips its children, so the off-canvas
   panel can never widen the document's scroll width while it is closed. */
.drawer-host {
  position: fixed; inset: 0; z-index: 190;
  overflow: hidden; pointer-events: none;
}
.drawer-host.is-open { pointer-events: auto; }
.drawer {
  position: absolute; inset: 0 0 0 auto; z-index: 2;
  /* The drawer IS the header on a phone -- it is what the burger opens -- so it
     carries the same green rather than the page ink. */
  width: min(400px, 88vw); background: #04180e; color: #fff;
  display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform .42s var(--ease);
  overflow-y: auto; overscroll-behavior: contain;
}
.drawer.is-open { transform: none; }
.drawer__top { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 18px 22px; border-bottom: 1px solid rgba(255, 255, 255, .1); }
/* the drawer heading is a tighter band than the header, so the mark is held
   back from the 56px the phone breakpoint would otherwise give it */
.drawer__top .brand__mark { height: 54px; }
.drawer__close { width: 40px; height: 40px; display: grid; place-items: center; border: 1px solid rgba(255, 255, 255, .22); color: #fff; }
.drawer__close svg { width: 16px; height: 16px; }
.drawer__nav { padding: 12px 22px 22px; flex: 1; }
.drawer__nav > li { border-bottom: 1px solid rgba(255, 255, 255, .08); }
.drawer__nav a, .drawer__toggle {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%;
  padding: 16px 2px; font-size: .93rem; font-weight: 500; letter-spacing: .06em;
  text-transform: uppercase; color: rgba(255, 255, 255, .86); text-align: left;
}
.drawer__nav a.is-active, .drawer__toggle.is-active { color: var(--gold); }
.drawer__toggle svg { width: 12px; height: 12px; color: var(--gold); transition: transform var(--t); }
.drawer__toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.drawer__panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .34s var(--ease); }
.drawer__panel > div { overflow: hidden; }
.drawer__toggle[aria-expanded="true"] + .drawer__panel { grid-template-rows: 1fr; }
.drawer__panel a {
  padding: 12px 0 12px 18px; font-size: .84rem; text-transform: none;
  letter-spacing: .02em; color: rgba(255, 255, 255, .66); border-left: 1px solid rgba(213, 168, 63, .3);
}
.drawer__panel a:last-child { margin-bottom: 12px; }
.drawer__foot { padding: 22px; border-top: 1px solid rgba(255, 255, 255, .1); display: grid; gap: 12px; }
.drawer__foot a.contact-line { display: flex; align-items: center; gap: .7em; font-size: .88rem; color: rgba(255, 255, 255, .78); }
.drawer__foot svg { width: 15px; height: 15px; color: var(--gold); flex: none; }

.scrim {
  position: absolute; inset: 0; z-index: 1; background: rgba(8, 9, 8, .6);
  backdrop-filter: blur(2px); opacity: 0; visibility: hidden; transition: opacity var(--t), visibility var(--t);
}
.scrim.is-open { opacity: 1; visibility: visible; }

/* ---------- 8. Hero slider ----------
   Every moving part in here reads one shared number: --sc, which site.js
   writes on the section as you scroll (0 while the hero fills the screen,
   1 once it has scrolled out of the way). Because the slide stack, the copy
   and the chrome all key off that one variable, the hero drifts as a single
   piece instead of three things animating separately. It stays at 0 when the
   script never runs or reduced motion is asked for. */
.hero {
  --sc: 0;
  /* Held as variables so the film variant's sticky stage can paint the same
     two layers without restating them. */
  --veil:
    /* The copy column is seated on its own pool of colour rather than relying
       on the diagonal alone. The lede used to run across a brightly lit
       building and sat right on the edge of legible; type this size should
       never have to be squinted at, and holding the darkness longer across
       the left half costs the photograph nothing — the subject is on the
       right.

       The green here is --pine-600, rgb(4 41 24) — the crest's own field
       colour, sampled off the artwork. An earlier pass lifted it to a lighter
       green on the theory that a wash needs to be light to read as a colour;
       it read as washed out instead. The badge green is dark, and the hero is
       the one screen that has to look like the badge, so it uses the badge
       colour and carries its weight through alpha rather than lightness. */

  /* NO GREEN HERE, and that is a decision rather than an oversight. The green
     is the site's ground colour and it earns its keep on flat panels, but the
     hero is the one surface with a photograph under it — and this shot flies
     from a dusk elevation into a great room with cream walls and a window
     wall, so it ends far brighter than it starts. A tinted scrim over that
     range does two things badly at once: it colours the interior a sickly
     shade, and it has to be heavy enough for the bright end, which buries the
     dark end. Neutral ink does the legibility job invisibly and lets the room
     keep its own warm light. The brand green resumes the moment the hero ends.

     Centred, because the copy is: a pool under the type, falling away to the
     edges so the room still reads around it. */
    radial-gradient(86% 104% at 50% 42%, rgba(6, 8, 9, .78), rgba(6, 8, 9, .42) 58%, transparent 78%),
    /* Top and bottom bands. The top one keeps the header capsule legible over
       a pale ceiling; the bottom one hands off to the marquee below. */
    linear-gradient(180deg, rgba(6, 8, 9, .72) 0%, rgba(6, 8, 9, .30) 30%, rgba(6, 8, 9, .30) 62%, rgba(6, 8, 9, .82) 100%),
    linear-gradient(to top, rgba(6, 8, 9, .88), transparent 46%);
  --vignette:
    radial-gradient(120% 92% at 50% 44%, transparent 44%, rgba(6, 8, 9, .62) 100%),
    radial-gradient(52% 58% at 88% 16%, rgba(213, 168, 63, .16), transparent 72%);
  position: relative; min-height: min(94vh, 920px);
  display: grid; isolation: isolate; overflow: hidden;
}
/* Grown 9% taller than the frame in both directions so the drift never
   exposes an edge. */
.hero__slides {
  position: absolute; inset: -9% 0; z-index: -2;
  transform: translate3d(0, calc(var(--sc) * 7%), 0);
  will-change: transform;
}
.hero__slide { position: absolute; inset: 0; opacity: 0; transition: opacity 1.5s var(--ease); }
.hero__slide.is-active { opacity: 1; }
.hero__slide img { width: 100%; height: 100%; object-fit: cover; object-position: center; transform: scale(1.06); }
.hero__slide.is-active img { animation: kenburns 12s var(--ease) forwards; }
.hero__slide:nth-child(even).is-active img { animation-name: kenburns-alt; }
/* The residual scale at the end of the pan is what keeps the translate from
   pulling the photo off its own edge — do not take it below 1.04. */
@keyframes kenburns     { from { transform: scale(1.14) translate3d( 1.4%, 0, 0); } to { transform: scale(1.04) translate3d(-1.2%, 0, 0); } }
@keyframes kenburns-alt { from { transform: scale(1.14) translate3d(-1.4%, 0, 0); } to { transform: scale(1.04) translate3d( 1.2%, 0, 0); } }
.hero::before { content: ""; position: absolute; inset: 0; z-index: -1; background: var(--veil); }
/* Vignette plus a warm wash in the top-right dead space, so the photograph
   reads as lit rather than flat. */
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  pointer-events: none; background: var(--vignette);
}
/* ---------- the hero's framing ----------
   The copy sat in the top-left of a very large photograph with nothing
   holding it there, and the lower half of the frame carried no structure at
   all. Two hairlines fix that without adding a single new element or any more
   movement to a section that already has plenty:

     ::before  a vertical rule in the gutter, so the copy block is anchored to
               something rather than floating on the picture
     ::after   ticks at the four corners — the same drafting language as the
               preloader's mat, so the sheet the visitor arrived on and the
               building it became are visibly the same drawing

   BOTH ARE position:absolute, and that is load-bearing: .hero__in is a flex
   container, so a static pseudo-element would become a flex ITEM and sit in
   the row beside the copy. */
/* The vertical rule used to sit in the left gutter, anchoring a left-aligned
   copy column to the edge of the page. With the copy centred there is no edge
   for it to anchor to — parked at the left it just floats, and moved to the
   middle it would run straight through the headline. Removed rather than
   relocated: the centred block is symmetrical enough to hold itself. */
.hero__in::before { content: none; }
/* Corner ticks were tried here and removed. .hero__in is the shell, so they
   landed on the shell's corners rather than the frame's — an inset rectangle
   floating inside the picture, which read as an accident. The single rule
   above does the anchoring job on its own. */
@media (max-width: 900px) {
  /* The gutter is too narrow to hold a rule beside the copy at this width. */
  .hero__in::before { display: none; }
}

.hero__in {
  position: relative;
  display: flex; align-items: center; padding-block: clamp(78px, 10vw, 140px);
  /* Must come after padding-block, and must be max() rather than a plain
     override: on a wide screen the hero's own 140px is already the larger of
     the two, and the header clearance should never be allowed to shrink it. */
  padding-top: max(clamp(78px, 10vw, 140px), var(--hdr-safe));
  opacity: calc(1 - var(--sc) * 1.3);
  transform: translate3d(0, calc(var(--sc) * -48px), 0);
}
/* ---------- centred hero ----------
   The copy block is centred in the stage rather than run up the left gutter.
   Everything inside it is a flex row or a max-width block, so centring the
   column alone would leave the kicker, buttons and pills still packed left
   inside a centred box — each one has to be told separately. */
.hero__copy {
  max-width: 730px; color: rgba(255, 255, 255, .8);
  margin-inline: auto; text-align: center;
}
.hero__in { justify-content: center; }
.hero__copy .hero__kicker,
.hero__copy .btn-row,
.hero__copy .hero__pills { justify-content: center; }
.hero__copy .hero__lede { margin-inline: auto; }
/* The kicker's growing rule was a lead-in from the left margin. Centred, a
   single dash on one side reads as a stray mark, so it grows on both. */
.hero__kicker::after {
  content: ""; height: 1px; width: 0; flex: none; background: var(--gold);
  animation: ruleGrow .9s var(--ease) .45s both;
}
.hero h1 { color: #fff; margin-bottom: 1.15rem; }
.hero h1 em { font-style: normal; color: var(--gold); }
.hero__kicker {
  display: flex; align-items: center; gap: .95em;
  font-family: var(--f-sans); font-size: clamp(.82rem, 1.2vw, .95rem);
  font-weight: 500; letter-spacing: .3em; text-transform: uppercase; color: var(--gold);
  margin-bottom: 1.3rem;
}
.hero__kicker::before {
  content: ""; height: 1px; width: 0; flex: none; background: var(--gold);
  animation: ruleGrow .9s var(--ease) .45s both;
}
.hero__lede { font-size: clamp(1.02rem, 1.4vw, 1.18rem); max-width: 58ch; }
.hero__pills { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 2.2rem; }
.hero__pills li {
  font-size: .71rem; font-weight: 500; letter-spacing: .15em; text-transform: uppercase;
  padding: .55em 1.1em; border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 100px; color: rgba(255, 255, 255, .8);
  background: rgba(255, 255, 255, .05); backdrop-filter: blur(4px);
  transition: border-color var(--t), color var(--t), background var(--t);
}
.hero__pills li:hover { border-color: var(--gold); color: #fff; background: rgba(213, 168, 63, .16); }

/* copy entrance — replays on every slide change because the inactive copy
   blocks carry `hidden`, and leaving display:none restarts an animation.
   The film variant cross-fades its chapters on scroll instead, so it opts
   out of the per-slide entrance. */
.hero:not(.hero--film) [data-hero-copy] > * { animation: heroRise 1s var(--ease) both; }
.hero:not(.hero--film) [data-hero-copy] > *:nth-child(1) { animation-delay: .08s; }
.hero:not(.hero--film) [data-hero-copy] > *:nth-child(2) { animation-delay: .22s; }
.hero:not(.hero--film) [data-hero-copy] > *:nth-child(3) { animation-delay: .36s; }
.hero .btn-row { animation: heroRise 1s var(--ease) .5s both; }
.hero__pills   { animation: heroRise 1s var(--ease) .62s both; }
@keyframes heroRise { from { opacity: 0; transform: translate3d(0, 30px, 0); } }
@keyframes ruleGrow { to { width: clamp(30px, 5vw, 58px); } }


/* No rule across the top. The hairline was there to separate the chapter
   readout from the picture, and with the readout and the scroll cue both gone
   it was drawing a line under nothing — a border with no content above it
   reads as the bottom edge of the photograph rather than as a divider, which
   is exactly the seam it was meant to avoid. The gradient alone is enough to
   seat the dots and the arrows. */
.hero__ui {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  background: linear-gradient(to top, rgba(8, 9, 8, .58), transparent);
  opacity: calc(1 - var(--sc) * 1.7);
}
.hero__ui-in { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding-block: 16px; }
.hero__dots { display: flex; gap: 10px; }
/* The active dot doubles as the autoplay timer — its gold fill runs for
   exactly --hero-delay (set by site.js) and pauses with the slider. */
.hero__dots button {
  position: relative; overflow: hidden;
  width: 34px; height: 3px; background: rgba(255, 255, 255, .3); border-radius: 2px;
  transition: background var(--t), width var(--t);
}
.hero__dots button:hover { background: rgba(255, 255, 255, .55); }
.hero__dots button::after {
  content: ""; position: absolute; inset: 0; background: var(--gold);
  transform: scaleX(0); transform-origin: left;
}
.hero__dots button.is-active { width: 60px; background: rgba(255, 255, 255, .2); }
.hero__dots button.is-active::after { animation: dotFill var(--hero-delay, 6200ms) linear forwards; }
.hero.is-paused .hero__dots button.is-active::after { animation-play-state: paused; }
@keyframes dotFill { to { transform: scaleX(1); } }
.hero__arrows { display: flex; gap: 8px; }
.hero__arrows button {
  width: 44px; height: 44px; display: grid; place-items: center; color: #fff;
  border: 1px solid rgba(255, 255, 255, .28); border-radius: 50%;
  transition: background var(--t), border-color var(--t), color var(--t);
}
.hero__arrows button:hover { background: var(--gold); border-color: var(--gold); color: var(--ink); }
.hero__arrows svg { width: 15px; height: 15px; }

/* ---------- 8b. Film hero ----------
   A frame sequence from assets/film scrubbed by the scroll position. The
   section is a tall runway; everything the visitor sees lives in a sticky
   100vh stage inside it, so scrolling "through" the hero plays the shot
   instead of moving the page. site.js writes the frame, the chapter classes
   and --sc; if it never runs, .hero__poster is a perfectly good static hero
   and the runway collapses to one screen (see .hero--film:not(.is-live)). */
.hero--film {
  min-height: 0; height: var(--runway, 360vh);
  display: block; overflow: visible;
}
.hero--film::before, .hero--film::after { content: none; }
.hero__stage {
  position: sticky; top: 0; min-height: 540px;
  height: 100vh;
  /* svh, not dvh: the small-viewport unit does not change when a mobile
     address bar hides, so the sticky stage and its canvas are not resized
     mid-scroll. */
  height: 100svh;
  display: grid; isolation: isolate; overflow: hidden;
}
.hero__stage::before { content: ""; position: absolute; inset: 0; z-index: -1; background: var(--veil); }

/* ---------- the scrim only exists to serve the copy ----------
   While the camera is still outside, there is no copy to protect — so there
   is no reason to put a scrim over the photography either. A darkening layer
   sitting on an empty frame is not atmosphere, it is just a worse picture:
   the elevation is the product, and the opening shot should show it at full
   strength rather than through a filter.

   Both layers therefore ride the lead-in. They come up as the first chapter
   pops, which reads as the room dimming for the words rather than as a
   gradient switching on, and they stay up for the rest of the shot because
   from there on there is always copy on screen.

   Scoped to .is-live: without the film running there is no lead-in state to
   leave, and the hero needs its scrim from the first frame. */
/* --sc runs 0 to 1 across the stretch after COPY_END, and site.js already
   uses it to fade the copy out. Hanging the scrim on the same variable means
   the two leave together: the moment the last headline is gone the room is
   unobstructed, and the final quarter of the shot plays as a clean walk into
   the great room. One driver, so they can never disagree. */
.hero--film.is-live .hero__stage::before,
.hero--film.is-live .hero__stage::after {
  opacity: calc(1 - var(--sc, 0));
  transition: opacity .55s var(--ease);
}
/* Nothing over the approach: ::after is the vignette and it stays down while
   the camera is outside. The crest used to fade in here; it now belongs at
   the other end of the shot, after the copy has finished. */
.hero--film.is-live.is-lead .hero__stage::after { opacity: 0; }

/* The one exception, and it is not decoration. The contact strip carries no
   fill of its own — it was drawn to sit on the veil — and this shot opens on
   a bright overcast sky. Drop the scrim entirely and the phone number and
   email vanish into the cloud. So during the lead-in the full veil is
   replaced by a band that covers the chrome and nothing else: roughly the top
   120px, gone by a fifth of the way down. The building, which is the whole
   point of the opening frame, is completely unfiltered. */
.hero--film.is-live.is-lead .hero__stage::before {
  opacity: 1;
  background: linear-gradient(180deg,
              rgba(6, 8, 9, .82) 0%,
              rgba(6, 8, 9, .40) 9%,
              transparent 19%);
}

.hero__stage::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  pointer-events: none; background: var(--vignette);
}
/* ---------- the lead-in ----------
   site.js writes .is-lead while the camera is still outside, before the first
   chapter stop. The house gets the screen to itself: no headline, no buttons,
   no pills — only the scroll cue, which is the one thing that should be on
   screen when the whole instruction is "scroll".

   The copy is moved down and faded rather than displayed none, so when the
   door opens it rises into place instead of appearing. Scoped to .is-live so
   a visitor without the film (reduced motion, no canvas, metered connection)
   still gets a perfectly ordinary hero with its headline showing. */
.hero--film.is-live.is-lead .hero__copies,
.hero--film.is-live.is-lead .btn-row,
.hero--film.is-live.is-lead .hero__pills {
  opacity: 0; visibility: hidden;
  transform: translate3d(0, 26px, 0);
}
.hero--film.is-live .hero__copies,
.hero--film.is-live .btn-row,
.hero--film.is-live .hero__pills {
  transition: opacity .7s var(--ease), visibility .7s var(--ease),
              transform .7s var(--ease);
}

/* Until the first frame is painted the poster carries the stage; the canvas
   then fades over the top of it, so there is never an empty frame. */
.hero__film { position: absolute; inset: 0; z-index: -2; background: var(--ink); }
.hero__film canvas,
.hero__poster {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}
.hero__film canvas { opacity: 0; transition: opacity .7s var(--ease); }
.hero--film.is-ready .hero__film canvas { opacity: 1; }

/* chapters are stacked and cross-faded, so the block never changes height
   between them and the copy below it cannot jump */
.hero--film .hero__copies { display: grid; }
/* Each chapter arrives by coming toward you out of the depth of the shot,
   not by sliding up into it. The camera is pushing forward through the house
   the whole time, so copy that scales up from small is travelling with the
   camera — it reads as the words emerging from the doorway the lens just went
   through. Copy that merely slides reads as a caption laid over a video.

   The origin sits above centre because that is roughly where the doorway and
   then the hallway vanish to in this footage; scaling out of that point is
   what sells it as depth rather than as a zoom effect.

   Deliberately no blur on the way in. Softening the type would sell the depth
   harder, and it is exactly what made the headings unreadable last time — a
   heading has one job and being legible is it. Scale and fade carry it.

   It POPS rather than drifts. The long ease this used to run on was a
   cinematic glide, which is the wrong instinct here: the copy is scrubbed by
   the wheel, so a slow transition is still catching up while the reader has
   already moved on, and the arrival never lands. --pop overshoots slightly
   past 1 and settles back, which is what makes it read as a snap instead of
   a zoom. Opacity is faster than the transform on purpose — the words are
   fully solid a beat before they finish seating, so nothing is ever read
   through a fade. */
.hero--film [data-hero-copy] {
  grid-area: 1 / 1;
  opacity: 0; visibility: hidden;
  transform: scale(.9) translate3d(0, 10px, 0);
  transform-origin: 50% 42%;
  transition: opacity .22s var(--ease),
              transform .42s var(--pop),
              visibility .22s;
}
/* --cp is the progress through the active chapter, written by site.js. Riding
   a few percent of scale on it means the copy keeps drifting toward the
   viewer for the whole chapter instead of arriving and then sitting still
   while the camera carries on without it. */
.hero--film [data-hero-copy].is-on {
  opacity: 1; visibility: visible;
  transform: scale(calc(1 + var(--cp, 0) * .045));
}
/* Leaving is the reverse — pushed back into the house rather than pulled
   forward — so consecutive chapters read as one continuous move inward. */
/* Quicker than it arrives, and no overshoot on the way out. A chapter that
   lingers is still on screen while the next one is popping, and two headlines
   overlapping is the one thing that makes the whole sequence look broken. */
.hero--film [data-hero-copy].was-on {
  transform: scale(1.08) translate3d(0, -8px, 0);
  transition: opacity .16s var(--ease),
              transform .3s var(--ease),
              visibility .16s;
}

/* the active chapter marker doubles as a scrubber for that chapter */
.hero--film .hero__dots button.is-active::after { animation: none; transform: scaleX(var(--cp, 0)); }

/* The stage clips to 100vh, so on a short viewport the copy has to give
   something up rather than get cut off. */
@media (max-height: 720px) {
  /* This outranks the .hero__in clearance above, so it has to carry it too —
     a short viewport is a reason to give up hero padding, never a reason to
     let the copy slide under the header. */
  .hero--film .hero__in { padding-block: 56px; padding-top: max(56px, var(--hdr-safe)); }
  .hero--film .hero__pills { display: none; }
  .hero--film .hero__lede { font-size: 1rem; }
}

/* No script, reduced motion or a data saver: one screen, poster only. */
.hero--film:not(.is-live) { height: min(94vh, 920px); }
.hero--film:not(.is-live) .hero__stage { position: relative; height: 100%; }
.hero--film:not(.is-live) [data-hero-copy] { opacity: 1; visibility: visible; transform: none; }
.hero--film:not(.is-live) [data-hero-copy] ~ [data-hero-copy] { display: none; }
.hero--film:not(.is-live) .hero__ui { display: none; }

/* ---------- 9. Marquee ---------- */
/* Read as a band of brushed metal rather than a flat gold stripe. */
.marquee {
  background: linear-gradient(90deg, #b3862a, var(--gold) 18%, #f2dda0 50%, var(--gold) 82%, #b3862a);
  color: var(--ink); overflow: hidden; padding-block: 15px;
}
.marquee__track { display: flex; width: max-content; animation: slide 34s linear infinite; }
.marquee:hover .marquee__track { animation-play-state: paused; }
@keyframes slide { to { transform: translateX(-50%); } }
.marquee__set { display: flex; align-items: center; flex: none; }
.marquee__set span {
  display: inline-flex; align-items: center; gap: 1.6rem;
  padding-inline: 1.6rem; font-family: var(--f-display); font-size: .84rem;
  font-weight: 700; letter-spacing: .22em; text-transform: uppercase; white-space: nowrap;
}
.marquee__set span::after { content: ""; width: 5px; height: 5px; background: var(--ink); border-radius: 50%; opacity: .55; }

/* ---------- 10. Page banner ---------- */
.banner { position: relative; isolation: isolate; padding-block: clamp(74px, 9vw, 132px); color: rgba(255, 255, 255, .78); overflow: hidden; }
/* Same reasoning as .hero__in: this has to follow padding-block, or the
   breadcrumbs go back under the capsule. */
.banner { padding-top: max(clamp(74px, 9vw, 132px), var(--hdr-safe)); }
/* Oversized top and bottom so the scroll drift (--par, written by site.js)
   can never pull the photograph off the band. */
.banner__bg {
  position: absolute; inset: -10% 0; z-index: -2;
  transform: translate3d(0, var(--par, 0px), 0);
}
.banner__bg img { width: 100%; height: 100%; object-fit: cover; }
.banner::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(95deg, rgba(8, 9, 8, .93), rgba(8, 9, 8, .6) 70%, rgba(8, 9, 8, .78));
}
.banner h1 { color: #fff; max-width: 20ch; }
.banner p { max-width: 62ch; margin-top: 1.2rem; font-size: clamp(1rem, 1.3vw, 1.1rem); }
.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: .55em; font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; margin-bottom: 1.5rem; color: rgba(255, 255, 255, .58); }
.crumbs a { transition: color var(--t); }
.crumbs a:hover { color: var(--gold); }
.crumbs svg { width: 11px; height: 11px; opacity: .5; }
.crumbs [aria-current] { color: var(--gold); }

/* ---------- 11. Cards ---------- */
.card {
  position: relative; display: flex; flex-direction: column;
  background: var(--paper); border: 1px solid var(--line);
  transition: transform var(--t), box-shadow var(--t), border-color var(--t);
}
.card:hover { transform: translateY(-5px); box-shadow: var(--sh-2); border-color: rgba(213, 168, 63, .45); }
.card__media { position: relative; overflow: hidden; aspect-ratio: 4 / 3; background: var(--sand); }
/* Hover zoom and scroll drift share one transform, so the zoom rides a
   custom property instead of overwriting --par. The 1.05 resting scale is
   the headroom the drift needs. */
.card__media img {
  width: 100%; height: 100%; object-fit: cover;
  transform: translate3d(0, var(--par, 0px), 0) scale(var(--cz, 1.07));
  transition: transform .7s var(--ease);
}
.card:hover .card__media img { --cz: 1.14; }
.card__tag {
  position: absolute; top: 14px; left: 14px; z-index: 2;
  font-size: .66rem; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  padding: .5em 1em; background: var(--ink); color: var(--gold);
}
.card__tag--gold { background: var(--gold); color: var(--ink); }
/* Sold reads as a closed sale, not an offer, so it deliberately does NOT take
   the gold reserved for "Available Now" -- a buyer scanning the grid should be
   able to tell the two apart at a glance, from the colour alone. */
.card__tag--sold {
  background: #7d2b28; color: #fff; border-color: #7d2b28;
}
.card__body { padding: clamp(22px, 2.4vw, 30px); display: flex; flex-direction: column; flex: 1; gap: .8rem; }
.card__body h3 a { transition: color var(--t); }
.card__body h3 a:hover { color: var(--gold-dk); }
.card__meta { display: flex; flex-wrap: wrap; gap: .5em 1.2em; font-size: .78rem; color: var(--muted); letter-spacing: .04em; }
.card__meta li { display: inline-flex; align-items: center; gap: .45em; }
.card__meta svg { width: 14px; height: 14px; color: var(--gold-dk); flex: none; }
.card__price { font-family: var(--f-serif); font-size: 1.22rem; font-weight: 600; color: var(--gold-dk); }
.card__body > .txtlink { margin-top: auto; align-self: flex-start; }

/* icon feature card */
.icard {
  padding: clamp(28px, 3vw, 40px); background: var(--paper);
  border: 1px solid var(--line); position: relative; overflow: hidden;
  transition: transform var(--t), box-shadow var(--t), border-color var(--t);
}
.icard::before {
  content: ""; position: absolute; inset: auto 0 0 0; height: 2px;
  background: var(--gold); transform: scaleX(0); transform-origin: left;
  transition: transform .5s var(--ease);
}
.icard:hover { transform: translateY(-5px); box-shadow: var(--sh-2); }
.icard:hover::before { transform: none; }
.icard__ico {
  width: 58px; height: 58px; display: grid; place-items: center; margin-bottom: 1.4rem;
  color: var(--gold-dk); background: var(--cream); border: 1px solid var(--line);
  border-radius: 50%; transition: background var(--t), color var(--t), border-color var(--t);
}
.icard:hover .icard__ico { background: var(--gold); color: var(--ink); border-color: var(--gold); }
.icard__ico svg { width: 26px; height: 26px; }
.icard h3 { margin-bottom: .6rem; }
.icard--dark { background: rgba(255, 255, 255, .035); border-color: rgba(255, 255, 255, .1); }
.icard--dark .icard__ico { background: rgba(213, 168, 63, .12); border-color: var(--line-dark); color: var(--gold); }
.icard--num::after {
  content: attr(data-num); position: absolute; top: 8px; right: 18px;
  font-family: var(--f-display); font-size: 4.4rem; font-weight: 700;
  color: rgba(18, 17, 16, .05); line-height: 1; pointer-events: none;
}
.icard--dark.icard--num::after { color: rgba(255, 255, 255, .055); }

/* pillar (trust / quality / commitment) */
.pillar { text-align: center; padding: clamp(30px, 3vw, 44px) clamp(20px, 2.4vw, 30px); border: 1px solid var(--line-dark); background: rgba(255, 255, 255, .03); }
.pillar__ico { width: 72px; height: 72px; margin: 0 auto 1.4rem; display: grid; place-items: center; border: 1px solid var(--gold); border-radius: 50%; color: var(--gold); }
.pillar__ico svg { width: 32px; height: 32px; }
.pillar h3 { font-family: var(--f-display); font-size: 1.05rem; letter-spacing: .2em; text-transform: uppercase; color: #fff; margin-bottom: .8rem; }

/* ---------- 12. Media frames ---------- */
.frame { position: relative; }
/* A default shape rather than whatever ratio the source file happens to be —
   the photo library mixes 2.4:1 panoramas with near-square aerials, and a
   framed slot has to hold its place in the split regardless. The modifiers
   below override it. */
.frame img { width: 100%; aspect-ratio: 16 / 11; object-fit: cover; }
.frame--tall img { aspect-ratio: 4 / 5; }
.frame--wide img { aspect-ratio: 16 / 11; }
.frame--edge { isolation: isolate; }
.frame--edge::after {
  content: ""; position: absolute; inset: 18px -18px -18px 18px; z-index: -1;
  border: 1px solid var(--gold); pointer-events: none;
}
@media (max-width: 700px) { .frame--edge::after { display: none; } }
.frame__badge {
  position: absolute; right: -14px; bottom: -14px; z-index: 2;
  background: var(--ink); color: #fff; padding: 22px 26px; max-width: 240px;
  border-left: 3px solid var(--gold);
}
.frame__badge b { display: block; font-family: var(--f-display); font-size: 2.1rem; color: var(--gold); line-height: 1; }
.frame__badge span { display: block; font-size: .74rem; letter-spacing: .16em; text-transform: uppercase; margin-top: .5rem; color: rgba(255, 255, 255, .7); }
@media (max-width: 520px) { .frame__badge { position: static; margin-top: 16px; max-width: none; } .frame--edge::after { display: none; } }

.duo { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: end; }
.duo img { aspect-ratio: 3 / 4; }
.duo > :first-child { padding-top: 34px; }

/* ---------- 13. Ticked lists ---------- */
.ticks { display: grid; gap: .9rem; margin-top: 1.7rem; }
.ticks li { display: flex; gap: .9em; align-items: flex-start; font-size: .97rem; }
.ticks svg { width: 20px; height: 20px; flex: none; color: var(--gold-dk); margin-top: 3px; }
.ticks--light svg { color: var(--gold); }
.ticks--2 { grid-template-columns: repeat(2, 1fr); gap: .9rem 2rem; }
@media (max-width: 620px) { .ticks--2 { grid-template-columns: 1fr; } }

.deflist { display: grid; gap: 0; margin-top: 1.8rem; border-top: 1px solid var(--line); }
.deflist > div { display: grid; grid-template-columns: 190px 1fr; gap: 12px 26px; padding: 16px 0; border-bottom: 1px solid var(--line); }
.deflist dt { font-size: .78rem; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--gold-dk); }
.deflist dd { margin: 0; }
@media (max-width: 620px) { .deflist > div { grid-template-columns: 1fr; gap: 4px; } }

/* ---------- 14. Stats ---------- */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line-dark); }
.stat { padding: clamp(28px, 3.4vw, 46px) clamp(16px, 2vw, 26px); text-align: center; background: var(--ink); }
.stat__n { font-family: var(--f-display); font-size: clamp(2.2rem, 4.4vw, 3.3rem); font-weight: 700; color: var(--gold); line-height: 1; display: block; font-variant-numeric: tabular-nums; }
.stat__l { display: block; margin-top: .8rem; font-size: .74rem; font-weight: 500; letter-spacing: .18em; text-transform: uppercase; color: rgba(255, 255, 255, .66); }
@media (max-width: 760px) { .stats { grid-template-columns: repeat(2, 1fr); } }

/* ---------- 15. Process timeline ---------- */
.steps { position: relative; display: grid; gap: clamp(22px, 2.6vw, 30px); grid-template-columns: repeat(4, 1fr); counter-reset: s; }
@media (max-width: 1000px) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .steps { grid-template-columns: 1fr; } }
.step { position: relative; padding-top: 46px; isolation: isolate; }
.step::before {
  counter-increment: s; content: "0" counter(s);
  position: absolute; top: 0; left: 0;
  font-family: var(--f-display); font-size: .96rem; font-weight: 700; letter-spacing: .1em;
  color: var(--ink); background: var(--gold); padding: .45em .85em;
}
.step::after { content: ""; position: absolute; top: 16px; left: 0; right: 0; height: 1px; background: var(--line); z-index: -1; }
.step h3 { margin-bottom: .7rem; }
.section--ink .step::after, .section--forest .step::after { background: rgba(255, 255, 255, .12); }

/* ---------- 16. Filters + gallery ---------- */
.filters { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: clamp(28px, 3vw, 42px); }
.filters button {
  padding: .72em 1.5em; font-size: .74rem; font-weight: 600; letter-spacing: .15em; text-transform: uppercase;
  border: 1px solid var(--line); color: var(--muted); background: var(--paper);
  transition: color var(--t), border-color var(--t), background var(--t);
}
.filters button:hover { color: var(--char); border-color: var(--gold); }
.filters button[aria-pressed="true"] { background: var(--forest-2); border-color: var(--gold); color: #fff; }

.gal { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
@media (max-width: 900px) { .gal { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px) { .gal { grid-template-columns: repeat(2, 1fr); } }
.gal__item { position: relative; overflow: hidden; aspect-ratio: 1; background: var(--sand); cursor: zoom-in; }
.gal__item:nth-child(1), .gal__item:nth-child(8) { grid-column: span 2; grid-row: span 2; }
@media (max-width: 620px) { .gal__item:nth-child(1), .gal__item:nth-child(8) { grid-column: span 2; grid-row: span 1; aspect-ratio: 3/2; } }
/* flat variant — uniform tiles, used for per-project photo sets */
.gal--3 { grid-template-columns: repeat(3, 1fr); }
.gal--flat > .gal__item:nth-child(1), .gal--flat > .gal__item:nth-child(8) {
  grid-column: auto; grid-row: auto; aspect-ratio: 1;
}
@media (max-width: 480px) { .gal--3 { grid-template-columns: repeat(2, 1fr); } }
.gal__item img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease); }
.gal__item:hover img { transform: scale(1.07); }
.gal__item::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(8, 9, 8, .6), transparent 55%);
  opacity: 0; transition: opacity var(--t);
}
.gal__item:hover::after { opacity: 1; }
.gal__cap {
  position: absolute; inset: auto 0 0 0; z-index: 2; padding: 16px 18px;
  font-size: .78rem; font-weight: 500; letter-spacing: .1em; text-transform: uppercase; color: #fff;
  transform: translateY(8px); opacity: 0; transition: transform var(--t), opacity var(--t);
}
.gal__item:hover .gal__cap { transform: none; opacity: 1; }

/* lightbox */
.lb {
  position: fixed; inset: 0; z-index: 300; display: none;
  background: rgba(5, 6, 5, .96); place-items: center; padding: clamp(14px, 4vw, 48px);
}
.lb.is-open { display: grid; }
.lb__stage { position: relative; max-width: 1180px; width: 100%; }
.lb__img { width: 100%; max-height: 78vh; object-fit: contain; margin-inline: auto; }
.lb__cap { text-align: center; margin-top: 16px; color: rgba(255, 255, 255, .7); font-size: .87rem; letter-spacing: .06em; }
.lb__cap b { color: var(--gold); font-weight: 600; }
.lb button {
  position: absolute; width: 50px; height: 50px; display: grid; place-items: center;
  color: #fff; border: 1px solid rgba(255, 255, 255, .28); border-radius: 50%; background: rgba(0, 0, 0, .35);
  transition: background var(--t), border-color var(--t), color var(--t);
}
.lb button:hover { background: var(--gold); border-color: var(--gold); color: var(--ink); }
.lb button svg { width: 17px; height: 17px; }
.lb__close { top: -62px; right: 0; }
.lb__prev { left: -66px; top: 50%; margin-top: -25px; }
.lb__next { right: -66px; top: 50%; margin-top: -25px; }
@media (max-width: 1340px) {
  .lb__close { top: -58px; }
  .lb__prev { left: 6px; }
  .lb__next { right: 6px; }
}

/* ---------- 17. Testimonials ---------- */
.quotes { position: relative; overflow: hidden; }
.quotes__view { display: flex; transition: transform .55s var(--ease); }
.quotes__slide { flex: 0 0 100%; padding-inline: 4px; }
.quote { background: rgba(255, 255, 255, .04); border: 1px solid var(--line-dark); padding: clamp(30px, 4vw, 54px); text-align: center; }
.quote__stars { display: flex; justify-content: center; gap: 5px; color: var(--gold); margin-bottom: 1.6rem; }
.quote__stars svg { width: 17px; height: 17px; }
.quote blockquote { font-family: var(--f-serif); font-size: clamp(1.16rem, 2.1vw, 1.6rem); line-height: 1.5; color: #fff; font-style: italic; }
.quote blockquote::before { content: "\201C"; color: var(--gold); }
.quote blockquote::after { content: "\201D"; color: var(--gold); }
.quote figcaption { margin-top: 1.8rem; }
.quote figcaption b { display: block; font-family: var(--f-display); font-size: .94rem; letter-spacing: .16em; text-transform: uppercase; color: var(--gold); }
.quote figcaption span { display: block; margin-top: .4rem; font-size: .82rem; color: rgba(255, 255, 255, .58); }
.quotes__ui { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 2.4rem; }
.quotes__ui button {
  width: 46px; height: 46px; display: grid; place-items: center; color: #fff;
  border: 1px solid rgba(255, 255, 255, .26); border-radius: 50%;
  transition: background var(--t), border-color var(--t), color var(--t);
}
.quotes__ui button:hover { background: var(--gold); border-color: var(--gold); color: var(--ink); }
.quotes__ui svg { width: 15px; height: 15px; }
.quotes__dots { display: flex; gap: 8px; }
.quotes__dots button { width: 9px; height: 9px; padding: 0; border-radius: 50%; background: rgba(255, 255, 255, .26); border: 0; }
.quotes__dots button.is-active { background: var(--gold); }

/* light variant for testimonials page */
.quote--light { background: var(--paper); border-color: var(--line); }
.quote--light blockquote { color: var(--char); }
.quote--light figcaption b { color: var(--gold-dk); }
.quote--light figcaption span { color: var(--muted); }

/* ---------- 18. Accordion ---------- */
.acc { border-top: 1px solid var(--line); }
.acc__item { border-bottom: 1px solid var(--line); }
.acc__btn {
  display: flex; align-items: center; justify-content: space-between; gap: 20px; width: 100%;
  padding: clamp(19px, 2.2vw, 26px) 0; text-align: left;
  font-family: var(--f-serif); font-size: clamp(1.04rem, 1.6vw, 1.22rem); font-weight: 600;
  color: var(--char); transition: color var(--t);
}
.acc__btn:hover { color: var(--gold-dk); }
.acc__btn .ico { width: 32px; height: 32px; flex: none; display: grid; place-items: center; border: 1px solid var(--line); border-radius: 50%; color: var(--gold-dk); transition: background var(--t), color var(--t), border-color var(--t), transform var(--t); }
.acc__btn[aria-expanded="true"] .ico { background: var(--gold); border-color: var(--gold); color: var(--ink); transform: rotate(180deg); }
.acc__btn .ico svg { width: 13px; height: 13px; }
.acc__panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .36s var(--ease); }
.acc__panel > div { overflow: hidden; }
.acc__item.is-open .acc__panel { grid-template-rows: 1fr; }
.acc__panel p { padding-bottom: clamp(19px, 2.2vw, 26px); max-width: 78ch; }

/* ---------- 19. Forms ---------- */
.form { display: grid; gap: 18px; }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 620px) { .form__row { grid-template-columns: 1fr; } }
.field { display: grid; gap: 7px; }
.field > label { font-size: .77rem; font-weight: 600; letter-spacing: .13em; text-transform: uppercase; color: var(--char); }
.field .req { color: var(--gold-dk); }
.field input, .field select, .field textarea {
  width: 100%; padding: 14px 16px; background: var(--paper);
  border: 1px solid var(--line); border-radius: 2px; color: var(--char);
  transition: border-color var(--t), box-shadow var(--t);
}
.field textarea { min-height: 148px; resize: vertical; }
.field select { appearance: none; cursor: pointer; padding-right: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238f6a1c' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 15px center; background-size: 15px;
}
.field input::placeholder, .field textarea::placeholder { color: #a49d92; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: 0; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(213, 168, 63, .16);
}
.field .err { font-size: .8rem; color: #b4432f; display: none; }
.field.has-error input, .field.has-error select, .field.has-error textarea { border-color: #d08d7e; background: #fdf7f5; }
.field.has-error .err { display: block; }
.check { display: flex; gap: .8em; align-items: flex-start; font-size: .88rem; }
.check input { width: 18px; height: 18px; margin-top: 3px; flex: none; accent-color: var(--gold-dk); }
.form__note { font-size: .82rem; color: var(--muted); }
.form__alert {
  display: none; gap: .8em; align-items: flex-start; padding: 15px 18px;
  border-left: 3px solid var(--ok); background: rgba(47, 107, 74, .14); font-size: .9rem; color: #a9d9be;
}
.form__alert.is-shown { display: flex; }
.form__alert svg { width: 19px; height: 19px; flex: none; color: var(--ok); margin-top: 2px; }
.form__alert--warn { border-color: var(--gold-dk); background: rgba(213, 168, 63, .12); color: #ecd5a4; }
.form__alert--warn svg { color: var(--gold-dk); }

.form-panel { background: var(--paper); border: 1px solid var(--line); padding: clamp(26px, 3.4vw, 46px); box-shadow: var(--sh-1); }

/* multi-step */
.stepbar { display: flex; gap: 4px; margin-bottom: clamp(26px, 3vw, 38px); }
.stepbar__i { flex: 1; text-align: center; padding-top: 12px; border-top: 3px solid var(--line); font-size: .72rem; font-weight: 600; letter-spacing: .13em; text-transform: uppercase; color: var(--muted); }
.stepbar__i.is-done { border-color: var(--gold-dk); color: var(--gold-dk); }
.stepbar__i.is-now { border-color: var(--gold); color: var(--gold-dk); }
.fset { display: none; }
.fset.is-now { display: grid; gap: 18px; }
.fnav { display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between; margin-top: 8px; }

/* ---------- 20. Contact info blocks ---------- */
.infoblock { display: flex; gap: 18px; padding: clamp(22px, 2.4vw, 30px); border: 1px solid var(--line); background: var(--paper); transition: border-color var(--t), box-shadow var(--t); }
.infoblock:hover { border-color: rgba(213, 168, 63, .5); box-shadow: var(--sh-1); }
.infoblock__ico { width: 46px; height: 46px; flex: none; display: grid; place-items: center; background: var(--cream); border-radius: 50%; color: var(--gold-dk); }
.infoblock__ico svg { width: 20px; height: 20px; }
.infoblock h4 { font-family: var(--f-sans); font-size: .76rem; font-weight: 600; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); margin-bottom: .45rem; }
.infoblock a, .infoblock p { font-size: 1.01rem; color: var(--char); font-weight: 500; }
.infoblock a { transition: color var(--t); }
.infoblock a:hover { color: var(--gold-dk); }
.infoblock p.is-long { overflow-wrap: anywhere; }
/* Contact tiles: four across is tight for a 28-character email address, so
   this row gets an uneven split plus trimmed chrome to buy back width. */
@media (min-width: 1001px) {
  .grid--contact { grid-template-columns: .82fr 1.36fr .87fr .95fr; }
  .grid--contact .infoblock { gap: 14px; padding: 22px 20px; }
  .grid--contact .infoblock__ico { width: 40px; height: 40px; }
  .grid--contact .infoblock__ico svg { width: 18px; height: 18px; }
  .grid--contact .infoblock p, .grid--contact .infoblock a { font-size: .95rem; }
  .grid--contact .infoblock p.is-long { font-size: .86rem; line-height: 1.55; }
}

/* The published office address, sat above the map. Centred to match the
   .head--center block it follows, and normal-weight because an <address>
   element defaults to italic in every browser. */
.addr {
  font-style: normal; text-align: center; line-height: 1.75;
  margin: 0 0 clamp(18px, 2.4vw, 30px); color: var(--ink-90);
}
.addr b { display: block; font-family: var(--f-display); font-size: 1.05rem; letter-spacing: .02em; }
.addr a { color: var(--gold-dk); text-decoration: none; border-bottom: 1px solid transparent; }
.addr a:hover, .addr a:focus-visible { border-bottom-color: currentColor; }

.mapwrap { position: relative; border: 1px solid var(--line); background: var(--sand); }
.mapwrap iframe { width: 100%; height: clamp(320px, 46vw, 480px); border: 0; filter: grayscale(.3) contrast(1.05); }

/* ---------- 21. CTA band ---------- */
.cta { position: relative; isolation: isolate; overflow: hidden; text-align: center; padding-block: clamp(66px, 8vw, 116px); color: rgba(255, 255, 255, .78); }
.cta__bg {
  position: absolute; inset: -10% 0; z-index: -2;
  transform: translate3d(0, var(--par, 0px), 0);
}
.cta__bg img { width: 100%; height: 100%; object-fit: cover; }
.cta::before { content: ""; position: absolute; inset: 0; z-index: -1; background: rgba(8, 9, 8, .9); }
.cta h2 { color: #fff; max-width: 22ch; margin-inline: auto; }
.cta p { max-width: 60ch; margin: 1.2rem auto 0; }

/* ---------- 22. Footer ---------- */
.ftr { background: var(--ink); color: rgba(255, 255, 255, .62); font-size: .92rem; }
.ftr__main { padding-block: clamp(50px, 6vw, 80px); display: grid; grid-template-columns: 1.5fr 1fr 1fr 1.2fr; gap: clamp(28px, 4vw, 54px); }
@media (max-width: 1000px) { .ftr__main { grid-template-columns: 1fr 1fr; } }
@media (max-width: 620px)  { .ftr__main { grid-template-columns: 1fr; } }
.ftr__brand { display: flex; align-items: center; gap: 13px; margin-bottom: 1.5rem; }
/* Sized from the width, not the height. This is the horizontal lockup — crest,
   wordmark and the strapline under it — at roughly 2.4:1, so pinning a height
   the way the old square crest needed would either overflow the footer column
   or shrink the strapline to a grey smear. Letting it take the column up to
   300px keeps all three parts legible and lets it step down on a phone. */
.ftr__brand img {
  width: 100%; max-width: 300px; height: auto;
  object-fit: contain;
}
.ftr h4 { font-family: var(--f-sans); font-size: .8rem; font-weight: 600; letter-spacing: .2em; text-transform: uppercase; color: #fff; margin-bottom: 1.5rem; position: relative; padding-bottom: .9rem; }
.ftr h4::after { content: ""; position: absolute; left: 0; bottom: 0; width: 30px; height: 1px; background: var(--gold); }
.ftr__links { display: grid; gap: .82rem; }
.ftr__links a { display: inline-flex; align-items: center; gap: .6em; transition: color var(--t), gap var(--t); }
.ftr__links a::before { content: ""; width: 5px; height: 1px; background: var(--gold); flex: none; transition: width var(--t); }
.ftr__links a:hover { color: var(--gold-lt); gap: .9em; }
.ftr__links a:hover::before { width: 11px; }
.ftr__contact { display: grid; gap: 1.1rem; }
.ftr__contact li { display: flex; gap: .85em; align-items: flex-start; }
.ftr__contact svg { width: 16px; height: 16px; color: var(--gold); flex: none; margin-top: 4px; }
.ftr__contact a:hover { color: var(--gold-lt); }
.ftr__socials { display: flex; gap: 9px; margin-top: 1.6rem; }
.ftr__socials a { width: 38px; height: 38px; display: grid; place-items: center; border: 1px solid rgba(255, 255, 255, .16); border-radius: 50%; transition: background var(--t), border-color var(--t), color var(--t); }
.ftr__socials a:hover { background: var(--gold); border-color: var(--gold); color: var(--ink); }
.ftr__socials svg { width: 15px; height: 15px; }
.ftr__pillars { display: flex; flex-wrap: wrap; gap: .8em 1.4em; margin-top: 1.4rem; }
.ftr__pillars li { display: inline-flex; align-items: center; gap: .5em; font-size: .74rem; font-weight: 500; letter-spacing: .17em; text-transform: uppercase; color: var(--gold); }
.ftr__pillars svg { width: 15px; height: 15px; }
.ftr__bar { border-top: 1px solid rgba(255, 255, 255, .09); padding-block: 22px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 14px; font-size: .84rem; }
.ftr__bar nav { display: flex; flex-wrap: wrap; gap: 8px 22px; }
.ftr__bar a:hover { color: var(--gold-lt); }

/* ---------- 23. Utilities ---------- */
.totop {
  position: fixed; right: 20px; bottom: 20px; z-index: 110;
  width: 48px; height: 48px; display: grid; place-items: center;
  background: var(--forest); color: var(--gold); border: 1px solid var(--gold);
  border-radius: 50%; box-shadow: var(--sh-2);
  opacity: 0; visibility: hidden; transform: translateY(14px);
  transition: opacity var(--t), visibility var(--t), transform var(--t), background var(--t), color var(--t);
}
.totop.is-shown { opacity: 1; visibility: visible; transform: none; }
.totop:hover { background: var(--gold); color: var(--ink); }
.totop svg { width: 17px; height: 17px; }

.wfab {
  position: fixed; left: 20px; bottom: 20px; z-index: 110;
  display: inline-flex; align-items: center; gap: .7em;
  padding: 13px 20px 13px 16px; background: var(--ink); color: #fff;
  border: 1px solid var(--line-dark); border-radius: 100px; box-shadow: var(--sh-2);
  font-size: .8rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  transition: background var(--t), color var(--t), transform var(--t);
}
.wfab:hover { background: var(--gold); color: var(--ink); transform: translateY(-2px); }
.wfab svg { width: 18px; height: 18px; color: var(--gold); flex: none; transition: color var(--t); }
.wfab:hover svg { color: var(--ink); }
@media (max-width: 560px) { .wfab span { display: none; } .wfab { padding: 14px; border-radius: 50%; } }

.rule { height: 1px; background: var(--line); border: 0; margin-block: clamp(38px, 5vw, 64px); }
.section--ink .rule, .section--forest .rule { background: rgba(255, 255, 255, .1); }

/* legal / prose pages */
.prose { max-width: 78ch; }
.prose h2 { font-size: clamp(1.5rem, 2.4vw, 2rem); margin-top: 2.6rem; margin-bottom: .9rem; }
.prose h3 { margin-top: 1.9rem; margin-bottom: .6rem; }
.prose > :first-child { margin-top: 0; }
.prose ul { display: grid; gap: .7rem; margin-top: 1rem; }
.prose ul li { display: flex; gap: .8em; }
.prose ul li::before { content: ""; width: 5px; height: 5px; margin-top: .68em; background: var(--gold); border-radius: 50%; flex: none; }
.prose a { color: var(--gold-dk); border-bottom: 1px solid var(--line-dark); }
.prose a:hover { color: var(--char); border-color: var(--gold); }

/* tables */
.tablewrap { overflow-x: auto; border: 1px solid var(--line); background: var(--paper); }
.table { width: 100%; min-width: 620px; border-collapse: collapse; font-size: .94rem; }
.table caption { text-align: left; padding: 16px 20px; font-size: .78rem; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--gold-dk); border-bottom: 1px solid var(--line); }
.table th, .table td { padding: 15px 20px; text-align: left; border-bottom: 1px solid var(--line); vertical-align: top; }
.table thead th { background: var(--forest); color: #fff; font-family: var(--f-sans); font-size: .74rem; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; border-bottom: 0; }
.table tbody tr:last-child th, .table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:nth-child(even) { background: rgba(250, 247, 240, .6); }
.table tbody th { font-family: var(--f-serif); font-size: 1.05rem; font-weight: 600; color: var(--char); white-space: nowrap; }

.callout { display: flex; gap: 16px; padding: clamp(20px, 2.4vw, 28px); background: var(--cream); border-left: 3px solid var(--gold); font-size: .92rem; }
.callout svg { width: 20px; height: 20px; flex: none; color: var(--gold-dk); margin-top: 3px; }
.section--ink .callout, .section--forest .callout { background: rgba(255, 255, 255, .05); color: rgba(255, 255, 255, .74); }

/* empty state */
.empty { padding: clamp(40px, 6vw, 74px); text-align: center; border: 1px dashed var(--line); background: var(--cream); }
.empty svg { width: 42px; height: 42px; color: var(--gold-dk); margin: 0 auto 1.2rem; }

/* ---------- 24. Reveal on scroll ----------
   Scoped to `.js`, which site.js adds to <html> on load. If scripting is
   unavailable or the bundle fails, nothing is ever hidden. */
.js [data-reveal] {
  opacity: 0; transform: translateY(30px);
  transition: opacity .9s var(--ease), transform .9s var(--ease), clip-path .9s var(--ease);
}
.js [data-reveal="fade"]  { transform: none; }
.js [data-reveal="left"]  { transform: translateX(-34px); }
.js [data-reveal="right"] { transform: translateX(34px); }
.js [data-reveal="zoom"]  { transform: scale(.94); }
/* wipes an image up from its own bottom edge — no layout shift, no overflow */
.js [data-reveal="mask"]  { opacity: 1; transform: none; clip-path: inset(0 0 100% 0); }
.js [data-reveal].is-in   { opacity: 1; transform: none; clip-path: inset(0); }
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] { opacity: 1 !important; transform: none !important; clip-path: none !important; }
}

/* ---------- 24b. Scroll engine ----------
   The reading-progress hairline and the scroll-linked drift. site.js writes
   --p on the bar and --par on anything carrying [data-par], both from a
   single rAF loop; neither is set at all under reduced motion, so the
   fallback values below are what the page keeps. */
.progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 130;
  pointer-events: none; background: rgba(255, 255, 255, .1);
}
.progress i {
  display: block; height: 100%;
  background: linear-gradient(90deg, var(--gold-dk), var(--gold) 55%, var(--gold-lt));
  transform: scaleX(var(--p, 0)); transform-origin: left;
}
[data-par] { will-change: transform; }

/* ==========================================================================
   25. Magnetic cursor
   A gold dot that trails the pointer and changes shape by context. Enabled
   by site.js only on precise-pointer devices without a reduced-motion
   preference — the `has-cursor` class is what hides the native arrow, so if
   the script never runs the normal cursor is untouched.
   ========================================================================== */
@media (hover: hover) and (pointer: fine) {
  html.has-cursor,
  html.has-cursor *,
  html.has-cursor *::before,
  html.has-cursor *::after { cursor: none !important; }
}

.cursor {
  position: fixed; top: 0; left: 0; z-index: 400;
  pointer-events: none; contain: layout style size;
  will-change: transform;
  opacity: 0; transition: opacity .28s;
}
.cursor.-visible { opacity: 1; }

.cursor__dot {
  position: absolute; top: -24px; left: -24px;
  width: 48px; height: 48px; box-sizing: border-box; border-radius: 50%;
  background: linear-gradient(135deg, var(--gold-lt), var(--gold) 52%, var(--gold-dk));
  border: 0 solid var(--gold);
  transform: scale(.2);
  transition: transform .3s var(--ease), background .3s, border-width .3s,
              width .2s var(--ease), height .2s var(--ease),
              top .2s var(--ease), left .2s var(--ease), border-radius .2s;
}
.cursor__label {
  position: absolute; top: -24px; left: -24px;
  width: 48px; height: 48px; display: grid; place-items: center;
  font-family: var(--f-sans); font-size: .6rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; text-align: center;
  color: var(--ink); white-space: nowrap;
  opacity: 0; transform: scale(0) rotate(8deg);
  transition: opacity .3s, transform .3s var(--ease);
}

/* pressed */
.cursor.-active .cursor__dot { transform: scale(.3); transition-duration: .18s; }

/* over anything clickable — becomes a ring, so the affordance survives
   hiding the native pointer */
.cursor.-pointer .cursor__dot { transform: scale(.9); background: transparent; border-width: 2px; }
.cursor.-pointer.-active .cursor__dot { transform: scale(.78); }

/* over text inputs — a caret bar */
.cursor.-field .cursor__dot {
  top: -13px; left: -1px; width: 2px; height: 26px;
  border-radius: 1px; border-width: 0; transform: none;
  background: var(--gold);
}

/* data-cursor="-opaque" — solid gold disc */
.cursor.-opaque .cursor__dot { transform: scale(1.35); background: rgba(213, 168, 63, .92); border-width: 0; }
.cursor.-opaque.-active .cursor__dot { transform: scale(1.2); }

/* data-cursor="-lg" / "-hidden" */
.cursor.-lg .cursor__dot { transform: scale(2); }
.cursor.-hidden .cursor__dot, .cursor.-hidden .cursor__label { transform: scale(0); opacity: 0; }

/* data-cursor-text="…" — labelled disc. Declared last so it wins when an
   element carries both a state and a label. */
/* Gold disc with dark text rather than the reference's near-black disc, which
   disappears against dark sections and dark photography. */
.cursor.-label .cursor__dot {
  top: -24px; left: -24px; width: 48px; height: 48px; border-radius: 50%;
  transform: scale(1.78);
  background: linear-gradient(135deg, var(--gold-lt), var(--gold) 55%, var(--gold-dk));
  border: 1px solid rgba(8, 9, 8, .22);
}
.cursor.-label .cursor__label { opacity: 1; transform: none; }
.cursor.-label.-active .cursor__dot { transform: scale(1.62); }

/* ---------- 26. Print ---------- */
@media print {
  .topbar, .hdr, .ftr, .totop, .wfab, .hero__ui, .drawer, .drawer-host, .scrim, .lb, .cursor { display: none !important; }
  body { color: #000; }
  .section { padding-block: 20px; }
}

/* ---------- 27. Crest panels ----------
   The brand mark is a 190x210 badge, not a photograph. Dropped into a .frame
   it would be stretched to the full column width — around 600px on a desktop
   split — which is a three-times upscale of artwork that only has 190px to
   give, and a crisp badge rendered soft reads as a cheap logo rather than a
   considered one. So the frame keeps its size and the crest sits centred on
   the dark ground at its own scale, with the panel supplying the ink the
   inline background used to. */
.frame--crest {
  display: grid; place-items: center;
  background: var(--ink);
  padding: clamp(30px, 5vw, 64px);
  min-height: clamp(200px, 22vw, 300px);
}
.frame--crest img {
  width: auto; height: auto;
  /* The full crest is 800x624. Capped at 400 wide, which is inside the panel's
     content box on a desktop split and still only half the source — so it is
     never upscaled, at any breakpoint. */
  max-width: 400px; max-height: 312px;
  /* Both of these have to be reset, not just the width. `.frame img` above
     forces every framed image into a 16/11 box and crops it to fill — correct
     for a photograph, wrong for a badge: it was squashing the crest and
     cutting the crown off the top. */
  aspect-ratio: auto;
  object-fit: contain;
}

