/* ============================================================
   BayCraft Design·Build: design system
   DNA: eleos.la (plaster/ink/brass, hairline grid, masked reveals)
   Voice: quiet-luxury craft -> serif display + mono spec labels
   ============================================================ */

/* ---------- fonts ----------
   Self-hosted: the exact latin-subset variable files Google Fonts served for
   Fraunces (opsz 9..144, wght 300..400, plus italic 300) and JetBrains Mono (wght 400..600).
   Preloaded from Seo.astro so they start with the HTML instead of after CSS -> CSS. */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 300 400;
  font-display: swap;
  src: url('/fonts/fraunces-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url('/fonts/fraunces-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/fonts/jetbrains-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* metric-matched fallbacks (measured in Chrome, qa/lighthouse/REPORT.md section 3.1):
   the swap keeps line boxes and advance widths, so the font arriving moves nothing */
@font-face {
  font-family: 'Fraunces Fallback';
  src: local('Georgia');
  size-adjust: 82.9%; ascent-override: 98%; descent-override: 26%; line-gap-override: 0%;
}
@font-face {
  font-family: 'Fraunces Fallback';
  font-style: italic;
  src: local('Georgia Italic'), local('Georgia-Italic');
  size-adjust: 74.4%; ascent-override: 98%; descent-override: 26%; line-gap-override: 0%;
}
@font-face {
  font-family: 'JetBrains Mono Fallback';
  src: local('Menlo'), local('Courier New');
  size-adjust: 100%; ascent-override: 102%; descent-override: 30%; line-gap-override: 0%;
}

/* ---------- tokens ---------- */
:root {
  /* grounds + ink (warm, not blue: wood & plaster world) */
  --plaster: #f4f2ec;
  --ink: #191613;
  --bronze: #a3865a;        /* the one accent */
  --bronze-soft: #b7a274;
  --border-light: #e2ddd0;
  --border-dark: #2e2a24;
  --text-on-light: #46413a;
  --text-on-dark: #d6d1c6;
  --grid-light: #a3865a1a;
  --grid-dark: #ffffff0d;

  /* semantic (light default) */
  --background: var(--plaster);
  --headings: var(--ink);
  --text: var(--text-on-light);
  --accent: var(--bronze);
  --accent-hover: var(--bronze-soft);
  --accent-text: #7d6540;   /* darker bronze, AA-safe for small mono text on plaster */
  --button-bg: #7d6540;     /* solid buttons: white on this reads 5.4:1; on the raw bronze it was 3.4:1 */
  --border: var(--border-light);
  --grid: var(--grid-light);

  /* type */
  --font-mono: 'JetBrains Mono', 'JetBrains Mono Fallback', Menlo, monospace;
  --font-serif: 'Fraunces', 'Fraunces Fallback', Georgia, serif;

  /* fluid scale (320 -> 1600) */
  --fs-display: clamp(2.6rem, 0.9rem + 8.5vw, 8.75rem);
  --fs-h1: clamp(2.4rem, 1.3rem + 5.5vw, 5.6rem);
  --fs-h2: clamp(1.9rem, 1.1rem + 4vw, 4.1rem);
  --fs-h3: clamp(1.35rem, 1rem + 1.75vw, 2.2rem);
  --fs-h4: clamp(1.15rem, 1rem + .75vw, 1.5rem);
  --fs-xl: clamp(1.125rem, 1.05rem + .4vw, 1.35rem);
  --fs-body: clamp(0.92rem, .88rem + .2vw, 1.02rem);
  --fs-eyebrow: clamp(0.72rem, .7rem + .11vw, 0.8rem);

  /* rhythm */
  --section-pad: clamp(4.5rem, 2.9rem + 8vw, 9rem);
  --container-max: 100rem;
  --gutter: 3.33vw;
  --nav-h: 3.5rem;
  --radius: 0.5rem;

  /* motion */
  --ease: cubic-bezier(0.625, 0.05, 0, 1);        /* eleos snap-settle */
  --ease-hover: cubic-bezier(0.165, 0.84, 0.44, 1);
  --ease-power4: cubic-bezier(0.23, 1, 0.32, 1);
}

.theme-dark {
  --background: var(--ink);
  --headings: var(--plaster);
  --text: var(--text-on-dark);
  --accent-text: var(--bronze-soft);   /* on ink, the lighter bronze is the readable one */
  --border: var(--border-dark);
  --grid: var(--grid-dark);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
html, body { height: auto; }
body {
  background: var(--background);
  color: var(--text);
  font: 400 var(--fs-body)/1.55 var(--font-mono);
  letter-spacing: -0.03em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
::selection { background: var(--headings); color: var(--background); }
/* hidden scrollbar, eleos-style */
::-webkit-scrollbar { display: none; }
html { scrollbar-width: none; }

/* ---------- layout primitives ---------- */
.container {
  width: min(100% - var(--gutter) * 2, var(--container-max));
  margin-inline: auto;
  position: relative;
  z-index: 1;
}
.section {
  position: relative;
  background: var(--background);
  color: var(--text);
  padding-block: var(--section-pad);
  overflow: clip;
}

/* signature 13-hairline drafting grid */
.bg-grid {
  position: absolute; inset: 0; z-index: 0;
  width: min(100% - var(--gutter) * 2 + 1.5em, calc(var(--container-max) + 1.5em));
  margin-inline: auto;
  display: grid; grid-template-columns: repeat(13, 1fr);
  pointer-events: none;
}
.bg-grid span { width: 1px; background: var(--grid); }
.bg-grid span:last-child { justify-self: end; }

/* ---------- typography ---------- */
h1, h2, h3, h4 { color: var(--headings); font-weight: 340; }
.t-display, .t-h1, .t-h2 {
  font-family: var(--font-serif);
  font-variation-settings: 'opsz' 144;
  letter-spacing: -0.02em;
  line-height: 1.02;
  text-wrap: balance;
}
.t-display { font-size: var(--fs-display); }
.t-h1 { font-size: var(--fs-h1); }
.t-h2 { font-size: var(--fs-h2); }
.t-h3 { font-family: var(--font-serif); font-size: var(--fs-h3); line-height: 1.12; letter-spacing: -0.01em; }
.t-h4 { font-family: var(--font-serif); font-size: var(--fs-h4); line-height: 1.2; }
.t-serif-i { font-style: italic; font-weight: 300; }
.t-xl { font-size: var(--fs-xl); line-height: 1.45; letter-spacing: -0.035em; }
.t-prose { max-width: clamp(40ch, 50vw, 68ch); }
.t-prose p + p { margin-top: 1em; }

.eyebrow {
  font: 600 var(--fs-eyebrow)/1.45 var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--headings);
  display: inline-flex; align-items: center; gap: 0.6em;
  margin-bottom: clamp(1.2em, 2vw, 2em);
}
.eyebrow::before {
  content: ''; width: 0.45em; height: 0.45em; border-radius: 50%;
  background: var(--accent); flex: none;
}
.num {
  font: 500 var(--fs-eyebrow)/1 var(--font-mono);
  color: var(--accent-text);
}

/* ---------- nav ---------- */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 998;
  height: var(--nav-h);
  display: flex; align-items: center;
  background: transparent;
  transition: background-color .25s ease, color .25s ease, transform .45s var(--ease-power4);
}
.nav.is-scrolled { background: var(--plaster); box-shadow: 0 1px 0 var(--border-light); }
.nav.is-hidden { transform: translateY(-110%); }
.nav .container { display: flex; align-items: center; justify-content: space-between; gap: 2rem; }
.nav-logo {
  font-family: var(--font-serif); font-size: 1.35rem; letter-spacing: -0.01em;
  color: var(--headings); display: flex; align-items: baseline; gap: .55em;
}
.nav-logo .tag { font: 600 0.68rem var(--font-mono); text-transform: uppercase; letter-spacing: .14em; color: var(--accent-text); }
.nav-links { display: flex; gap: clamp(1.2rem, 2.4vw, 2.6rem); list-style: none; }
.nav-links a {
  font: 600 var(--fs-eyebrow)/1.1 var(--font-mono);
  text-transform: uppercase; letter-spacing: -0.02em;
  color: var(--headings);
  position: relative; padding-block: .35em;
}
.nav-links a::before {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor;
  transform: scaleX(0) rotate(.001deg); transform-origin: right;
  transition: transform .735s var(--ease);
}
.nav-links a:hover::before, .nav-links a[aria-current]::before { transform: scaleX(1); transform-origin: left; }
.nav.on-dark:not(.is-scrolled) { --headings: var(--plaster); --text: var(--text-on-dark); }

/* services drop-down (Ram 27.9 note 14). Pure CSS: :hover for the mouse, :focus-within for the
   keyboard. padding-top bridges the gap so the pointer can travel from the link to the list. */
.nav-drop { position: relative; }
.nav-sub {
  --headings: var(--ink);
  position: absolute; top: 100%; left: -1.4rem; padding-top: 1rem;
  list-style: none; min-width: 17rem;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .25s ease, transform .35s var(--ease), visibility 0s .35s;
}
.nav-sub::before {
  content: ''; position: absolute; inset: 1rem 0 0; z-index: -1;
  background: var(--plaster); border: 1px solid var(--border-light); border-radius: var(--radius);
  box-shadow: 0 18px 40px -24px rgba(0,0,0,.35);
}
.nav-sub li:first-child { padding-top: .6rem; }
.nav-sub li:last-child { padding-bottom: .6rem; }
.nav-sub a { display: block; padding: .7em 1.4rem; white-space: nowrap; }
.nav-sub a::before { left: 1.4rem; right: 1.4rem; bottom: .45em; }
.nav-drop:hover .nav-sub, .nav-drop:focus-within .nav-sub {
  opacity: 1; visibility: visible; transform: none;
  transition: opacity .25s ease, transform .35s var(--ease), visibility 0s;
}

/* ---------- buttons ---------- */
.button {
  display: inline-flex; align-items: center; justify-content: center; gap: .5em;
  padding: .85em 1.35em; border-radius: var(--radius);
  background: var(--button-bg); color: #fff; border: 1px solid transparent;
  font: 600 0.9rem/1.3 var(--font-mono); letter-spacing: -0.03em; text-transform: uppercase;
  transition: background-color .3s var(--ease-hover), transform .3s var(--ease-hover);
  cursor: pointer;
  white-space: nowrap;
}
.button:hover { background: var(--accent); }
.button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.button.ghost {
  background: transparent; color: var(--headings); border-color: var(--border);
}
.button.ghost:hover { border-color: var(--accent); color: var(--accent); }

.link-line {
  font: 600 var(--fs-eyebrow) var(--font-mono); text-transform: uppercase;
  color: var(--headings); position: relative; padding-bottom: .25em;
}
.link-line::before {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor; transform-origin: right;
  transition: transform .735s var(--ease);
}
.link-line:hover::before { transform: scaleX(0); transform-origin: right; animation: lineswap .735s var(--ease) forwards; }
@keyframes lineswap { 0% { transform: scaleX(1); transform-origin: right; } 50% { transform: scaleX(0); transform-origin: right; } 51% { transform: scaleX(0); transform-origin: left; } 100% { transform: scaleX(1); transform-origin: left; } }

/* ---------- reveal system ---------- */
.js [data-reveal-title], .js [data-reveal-text] { visibility: visible; }
.line-mask { display: block; overflow: hidden; }
.line-mask .line-inner {
  display: block; transform: translateY(103%);
  transition: transform 1.05s var(--ease-power4);
}
.is-visible .line-mask .line-inner { transform: translateY(0); }
[data-reveal-title] .line-mask:nth-child(2) .line-inner { transition-delay: .09s; }
[data-reveal-title] .line-mask:nth-child(3) .line-inner { transition-delay: .18s; }
[data-reveal-title] .line-mask:nth-child(4) .line-inner { transition-delay: .27s; }
[data-reveal-title] .line-mask:nth-child(5) .line-inner { transition-delay: .36s; }

.js [data-reveal-text]:not(.line-split) { opacity: 0; transform: translateY(22px); transition: opacity .8s var(--ease-power4), transform .9s var(--ease-power4); }
.js [data-reveal-text].is-visible:not(.line-split) { opacity: 1; transform: none; }

.js [data-reveal-block] { opacity: 0; transition: opacity .7s ease .1s; }
.js [data-reveal-block].is-visible { opacity: 1; }

.js [data-stagger] > * { opacity: 0; transform: translateY(26px); }
.js [data-stagger].is-visible > * {
  opacity: 1; transform: none;
  transition: opacity .7s var(--ease-power4), transform .85s var(--ease-power4);
}
.js [data-stagger].is-visible > *:nth-child(1) { transition-delay: .05s; }
.js [data-stagger].is-visible > *:nth-child(2) { transition-delay: .15s; }
.js [data-stagger].is-visible > *:nth-child(3) { transition-delay: .25s; }
.js [data-stagger].is-visible > *:nth-child(4) { transition-delay: .35s; }
.js [data-stagger].is-visible > *:nth-child(5) { transition-delay: .45s; }
.js [data-stagger].is-visible > *:nth-child(6) { transition-delay: .55s; }

/* column-wipe image reveal */
.frame { position: relative; overflow: hidden; border-radius: var(--radius); }
.frame img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.frame .wipe { position: absolute; inset: 0; z-index: 2; display: flex; }
.frame .wipe i { flex: 1; background: var(--background); transition: transform .8s var(--ease); }
.frame.is-visible .wipe i { transform: translateY(-101%); }
.frame.is-visible .wipe i:nth-child(2) { transition-delay: .06s; }
.frame.is-visible .wipe i:nth-child(3) { transition-delay: .12s; }
.frame.is-visible .wipe i:nth-child(4) { transition-delay: .18s; }
.frame.is-visible .wipe i:nth-child(5) { transition-delay: .24s; }
.frame.is-visible .wipe i:nth-child(6) { transition-delay: .30s; }
.frame.is-visible .wipe i:nth-child(7) { transition-delay: .36s; }
[data-parallax] img { will-change: transform; transform: scale(1.12); }

/* scramble labels */
[data-scramble] { min-height: 1.45em; display: inline-block; }

/* ---------- intro overlay ---------- */
.intro {
  position: fixed; inset: 0; z-index: 9999;
  background: transparent;
  display: flex; align-items: center; justify-content: center;
  flex-direction: column; gap: 2.2rem;
}
.intro .bg-grid span { background: var(--grid-light); }
.intro-art { width: min(46vw, 300px); color: var(--ink); position: relative; z-index: 1; }
.intro-art svg { width: 100%; height: auto; display: block; }
.intro-art path, .intro-art line, .intro-art rect, .intro-art circle, .intro-art polyline {
  fill: none; stroke: currentColor; stroke-width: 1.2; stroke-linecap: round; stroke-linejoin: round;
}
.intro-word {
  font: 600 var(--fs-eyebrow) var(--font-mono); text-transform: uppercase;
  letter-spacing: .05em; color: var(--text-on-light); z-index: 1;
}
.intro-cols { position: absolute; inset: 0; z-index: -1; display: flex; pointer-events: none; }
.intro-cols i { flex: 1; background: var(--plaster); transform: translateY(0); transition: transform .9s var(--ease); }
.intro.is-done { pointer-events: none; }
.intro.is-done .intro-art, .intro.is-done .intro-word, .intro.is-done .bg-grid { opacity: 0; transition: opacity .35s ease; }
.intro.is-done .intro-cols i { transform: translateY(-101%); }
.intro.is-done .intro-cols i:nth-child(2) { transition-delay: .06s; }
.intro.is-done .intro-cols i:nth-child(3) { transition-delay: .12s; }
.intro.is-done .intro-cols i:nth-child(4) { transition-delay: .18s; }
.intro.is-done .intro-cols i:nth-child(5) { transition-delay: .24s; }
.intro.is-done .intro-cols i:nth-child(6) { transition-delay: .30s; }
.intro.is-done .intro-cols i:nth-child(7) { transition-delay: .36s; }

/* ---------- hero ---------- */
.hero {
  min-height: 100svh;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding-block: calc(var(--nav-h) + 2rem) clamp(2rem, 4vw, 3.5rem);
}
.hero .container { display: flex; flex-direction: column; min-height: calc(100svh - var(--nav-h) - 5rem); }
.hero-media { position: absolute; inset: 0; z-index: 0; }
.hero-media .frame { position: absolute; inset: 0; border-radius: 0; }
.hero-video {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%; object-fit: cover;
  /* the first frame is the still, so the crossfade reads as the photo starting to move */
  opacity: 0; transition: opacity 1.4s var(--ease);
}
.hero-video.is-playing { opacity: 1; }
.hero-media::after {
  content: ''; position: absolute; inset: 0; z-index: 3;
  /* two passes: a vertical one that seats the masthead and the title block, and a
     diagonal one weighted to the lower left so the kitchen keeps its daylight on the
     right instead of sitting under an even grey sheet */
  background:
    linear-gradient(180deg, #19161385 0%, #19161326 34%, #19161318 52%, #191613e0 100%),
    linear-gradient(115deg, #191613a6 0%, #19161340 42%, #19161300 68%);
}
.hero-wordmark {
  font-family: var(--font-serif); font-weight: 340;
  font-size: clamp(3.4rem, 15.8vw, 15.5rem);
  line-height: .92; letter-spacing: -0.035em;
  color: var(--plaster);
  filter: blur(5px);
  transition: filter 1.1s cubic-bezier(0.37, 0, 0.63, 1) .15s;
}
.hero-wordmark.is-visible { filter: blur(0px); }

/* gooey morph stage (hero wordmark variant) */
.gooey { position: relative; }
.gooey-defs { position: absolute; width: 0; height: 0; }
.gooey-stage { display: block; position: relative; height: 1.02em; white-space: nowrap; }
.gooey-stage .g1, .gooey-stage .g2 {
  position: absolute; left: 0; top: 0; display: inline-block; user-select: none;
}
.gooey-sizer { visibility: hidden; display: block; height: 0; overflow: hidden; white-space: nowrap; }
/* Ram, 19.9: the gooey morph runs on phones and tablets too, not just desktop.
   It used to fall back to a compositor-only crossfade here, for two reasons that
   no longer hold. The visual one was that a crossfade left two display-size serif
   words near half opacity at the midpoint, legibly stacked; that was a property of
   the crossfade, not of touch, and the threshold filter this uses instead hard
   clips anything under ~55% alpha, so one word is ever on screen. The cost one was
   the filter re-rasterizing display-size text every frame: the wordmark is 74px on
   a phone against 227px on a desktop, about a ninth of the area, so a phone is
   doing strictly less of that work than the desktop which has always run it.
   Measured over two morph cycles at 390x844, the main thread went from 627ms busy
   to 703ms in 8s, under 9% either way. What does NOT come back is the blur-in
   entrance on the wordmark itself: a filter on the parent, even blur(0px), keeps
   the whole word in an offscreen buffer that re-rasterizes on every child swap,
   and that one does compound with the morph. Touch keeps the opacity-and-rise
   entrance below, which costs nothing and reads the same. */
@media (max-width: 860px), (pointer: coarse) {
  .hero-wordmark {
    filter: none;
    opacity: 0; transform: translateY(0.18em);
    transition: opacity .9s var(--ease) .15s, transform .9s var(--ease) .15s;
  }
  .hero-wordmark.is-visible { filter: none; opacity: 1; transform: none; }
}

/* ---------- premium motion layer ---------- */
/* Lenis smooth scroll */
html.lenis, html.lenis body { height: auto; }
html.lenis { scroll-behavior: auto; }  /* Lenis owns smoothing; CSS smooth would double-animate anchors */
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

/* cross-page view transitions removed: throttled rendering surfaces (embedded
   browser panes, backgrounded tabs) freeze the snapshot layer mid-animation and
   the stale frame sits on top of the live page. Reveals + Lenis carry the feel. */

/* hover micro-interactions */
.button { will-change: transform; }
.button:hover { transform: translateY(-2px); }
.button:active { transform: translateY(0); }
.project .t-h4 { transition: color .35s var(--ease-hover); }
.project:hover .t-h4 { color: var(--accent); }
.project .frame { transition: box-shadow .5s var(--ease-hover); }
.project:hover .frame { box-shadow: 0 24px 60px -28px #19161355; }
.card { will-change: transform; transition: background-color .3s var(--ease-hover), border-color .3s var(--ease-hover), transform .45s var(--ease-hover); }
.card:hover { transform: translateY(-4px); }
.faq-item summary { transition: color .3s var(--ease-hover), padding-left .35s var(--ease-hover); }
.faq-item summary:hover { padding-left: .5rem; }
.footer-word { will-change: transform; }
.hero-wordmark .t-serif-i { color: var(--bronze-soft); }
/* hero masthead + title block (see the comment in index.astro) */
.hero-eyebrow { margin: 0 0 1.1rem; color: var(--plaster); }
.hero-rule {
  border: 0; border-top: 1px solid #f4f2ec4d; margin: 0;
  transform: scaleX(0); transform-origin: left;
  transition: transform 1.15s var(--ease);
}
.hero-rule.is-visible { transform: none; }
.hero-wordmark { margin-top: clamp(1.2rem, 2.4vw, 2.4rem); }
.hero-lede {
  font-family: var(--font-serif); font-weight: 340;
  font-size: clamp(1.45rem, 3.1vw, 2.9rem);
  line-height: 1.12; letter-spacing: -0.015em;
  color: var(--plaster);
  margin: clamp(1rem, 1.8vw, 1.6rem) 0 0; max-width: 32ch;
  text-wrap: balance;   /* without it "& ADUs" orphans onto its own line at both widths */
}
.hero-lede .t-serif-i { color: var(--bronze-soft); }

.hero-block {
  margin: auto 0 0; padding-top: clamp(2rem, 4vw, 3.2rem);
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: 0 clamp(1.2rem, 2.6vw, 3rem);
  border-top: 1px solid #f4f2ec4d;
}
/* the dl stays a real dl (axe rejects a non dt/dd child), so the button sits beside it */
.hero-block-fields {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0 clamp(1.2rem, 2.6vw, 3rem); margin: 0;
}
.hero-block-fields > div { padding-top: 1.1rem; }
.hero-block-fields > div + div,
.hero-block > .hero-block-cta { border-left: 1px solid #f4f2ec26; padding-left: clamp(1.2rem, 2.6vw, 3rem); }
.hero-block dt {
  font: 600 var(--fs-eyebrow)/1.2 var(--font-mono);
  text-transform: uppercase; letter-spacing: .12em;
  color: var(--bronze-soft); margin-bottom: .7em;
}
.hero-block dd {
  margin: 0; color: var(--plaster);
  font: 500 .95rem/1.35 var(--font-mono); letter-spacing: -0.02em;
}
.hero-block dd a { color: inherit; border-bottom: 1px solid var(--bronze-soft); padding-bottom: .1em; }
.hero-block dd a:hover { color: var(--bronze-soft); }
.hero-block-cta { display: flex; align-items: center; }
.hero-block-cta .button { padding: 1.05em 1.7em; font-size: 1rem; }

@media (max-width: 860px) {
  .hero-block { grid-template-columns: 1fr; gap: 0; }
  .hero-block-fields { grid-template-columns: 1fr 1fr; gap: 0; }
  .hero-block-fields > div { padding-top: 1.2rem; }
  .hero-block-fields > div + div { border-left: 0; padding-left: 0; }
  .hero-block-fields > div:nth-child(2) { border-left: 1px solid #f4f2ec26; padding-left: 1.2rem; }
  .hero-block-fields > div:nth-child(3) { grid-column: 1 / -1; border-top: 1px solid #f4f2ec26; margin-top: 1.2rem; }
  .hero-block > .hero-block-cta { border-left: 0; padding-left: 0; margin-top: 1.4rem; }
  .hero-block-cta .button { width: 100%; }
  .hero-lede { max-width: none; }
}

/* ---------- generic composition helpers ---------- */
.split { display: grid; grid-template-columns: repeat(12, 1fr); gap: 20px; align-items: start; }
.col-4 { grid-column: span 4; } .col-5 { grid-column: span 5; } .col-6 { grid-column: span 6; }
.col-7 { grid-column: span 7; } .col-8 { grid-column: span 8; } .col-12 { grid-column: span 12; }
.offset-1 { grid-column-start: 2; } .offset-5 { grid-column-start: 6; }
@media (max-width: 860px) {
  .split { grid-template-columns: 1fr; }
  .split > * { grid-column: auto !important; }
}

.rule { border: 0; border-top: 1px solid var(--border); }

/* stat blocks */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 20px; }
.stat { border-top: 1px solid var(--border); padding-top: 1.1rem; }
.stat b { font: 340 var(--fs-h2)/1 var(--font-serif); color: var(--headings); display: block; }
.stat span { font: 600 var(--fs-eyebrow) var(--font-mono); text-transform: uppercase; }

/* service / process lists */
.index-list { list-style: none; counter-reset: row; }
.index-list > li {
  border-top: 1px solid var(--border);
  padding: clamp(1.4rem, 2.6vw, 2.4rem) 0;
  display: grid; grid-template-columns: 3.5rem 1fr; gap: 1.5rem; align-items: baseline;
  counter-increment: row;
  transition: background-color .3s var(--ease-hover), padding-left .3s var(--ease-hover);
}
.index-list > li::before {
  content: counter(row, decimal-leading-zero);
  font: 500 var(--fs-eyebrow) var(--font-mono); color: var(--accent);
}
.index-list > li:last-child { border-bottom: 1px solid var(--border); }
.index-list h3 { margin-bottom: .35em; }
/* Ram 27.9 notes 3-4: a real button, under the service instead of beside it */
.index-list .index-cta { margin-top: 1.1rem; padding: .7em 1.15em; font-size: .8rem; }
.index-list li:hover { padding-left: .6rem; }

/* cards */
.card {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: clamp(1.2rem, 2vw, 1.8rem);
  background: transparent;
  transition: background-color .3s var(--ease-hover), border-color .3s var(--ease-hover);
}
.card:hover { border-color: var(--accent); }
.split > .card { align-self: stretch; } /* equal-height card rows despite .split's align-items:start */
/* a .card that is itself the link (section 04b sub-page cards): the whole box is the hit area,
   so the inner "Read more" is decoration and must not be a second nested link */
a.svc-child { display: block; text-decoration: none; color: inherit; }
a.svc-child:hover .link-line { color: var(--accent); }

/* project grid */
.projects { display: grid; grid-template-columns: repeat(12, 1fr); gap: clamp(20px, 2.5vw, 42px); }
.project { grid-column: span 6; }
.project.wide { grid-column: 6 / span 7; }
.project .frame { aspect-ratio: 4.3/3.4; margin-bottom: 1rem; }
.project .meta { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
@media (max-width: 860px) { .project, .project.wide { grid-column: 1 / -1 !important; } }

/* marquee strip */
.strip { display: flex; gap: 1vw; width: max-content; animation: strip 42s linear infinite; }
.strip .frame { width: clamp(220px, 21vw, 380px); aspect-ratio: 2/1.6; flex: none; }
@keyframes strip { to { transform: translateX(-50%); } }
html.static .strip { animation: none; }

/* ---------- FAQ accordion ---------- */
.faq-item { border-top: 1px solid var(--border); }
.faq-item:last-child { border-bottom: 1px solid var(--border); }
.faq-item summary {
  list-style: none; cursor: pointer;
  display: flex; justify-content: space-between; align-items: baseline; gap: 1.5rem;
  padding: clamp(1.1rem, 2vw, 1.6rem) 0;
  font-family: var(--font-serif); font-size: var(--fs-h4); color: var(--headings);
  transition: color .3s var(--ease-hover);
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: '+'; font: 400 1.2em var(--font-mono); color: var(--accent);
  transition: transform .45s var(--ease); flex: none;
}
.faq-item[open] summary::after { transform: rotate(45deg); }
.faq-item summary:hover { color: var(--accent); }
.faq-item p { padding: 0 0 1.6rem; max-width: 62ch; }

/* ---------- footer ---------- */
.footer { position: relative; border-top: 1px solid var(--border); padding-top: var(--section-pad); overflow: clip; }
.footer-grid { display: flex; flex-wrap: wrap; gap: 3rem 6vw; justify-content: space-between; margin-bottom: clamp(3rem, 6vw, 5rem); }
.footer h2, .footer h4 { font: 600 var(--fs-eyebrow) var(--font-mono); text-transform: uppercase; margin-bottom: 1.1em; color: var(--headings); }
.footer ul { list-style: none; display: grid; gap: .55em; }
.footer ul a { position: relative; display: inline-block; transition: color .3s var(--ease-hover); }
/* hover dot lives in the left gutter (absolute), so link text stays flush with the column heading */
.footer ul a::before {
  content: ''; position: absolute; left: -0.95em; top: 50%; margin-top: -.2em;
  width: .4em; height: .4em; border-radius: 50%; background: var(--accent);
  opacity: 0; transition: opacity .3s;
}
.footer ul a:hover { color: var(--headings); }
.footer ul a:hover::before { opacity: 1; }
.footer-word {
  font-family: var(--font-serif); font-weight: 340;
  font-size: clamp(4rem, 14.5vw, 15rem); line-height: .9; letter-spacing: -0.03em;
  color: var(--headings); text-align: center;
  transform: translateY(12%);
}
.footer-bar {
  background: var(--ink); color: var(--text-on-dark);
  font-size: .78rem; padding: .8em 0; margin-top: -2px;
}
.footer-bar .container { display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }

/* ---------- mobile nav ---------- */
.nav-burger { display: none; }
@media (max-width: 860px) {
  .nav-links {
    position: fixed; inset: 0; z-index: -1;
    background: var(--plaster);
    flex-direction: column; justify-content: center; align-items: center; gap: 2rem;
    transform: translateY(-60%); opacity: 0; pointer-events: none;
    transition: transform .5s cubic-bezier(0.83, 0, 0.17, 1), opacity .3s cubic-bezier(0.65, 0, 0.35, 1);
  }
  .menu-open .nav-links { transform: none; opacity: 1; pointer-events: auto;
    transition: transform 1s cubic-bezier(0.83, 0, 0.17, 1), opacity .5s cubic-bezier(0.65, 0, 0.35, 1) .1s; }
  .menu-open .nav { background: var(--plaster); }
  .menu-open .nav-links a { font-size: 1.4rem; color: var(--ink); }
  .nav-links { overflow-y: auto; }
  .nav-drop { display: flex; flex-direction: column; align-items: center; }
  .nav-sub {
    position: static; min-width: 0; padding: 0; margin-top: 1rem;
    display: flex; flex-direction: column; align-items: center; gap: .9rem;
    opacity: 1; visibility: visible; transform: none; transition: none;
  }
  .nav-sub::before { display: none; }
  .nav-sub li:first-child, .nav-sub li:last-child { padding: 0; }
  .nav-sub a { padding: .2em 0; }
  .nav-sub a::before { left: 0; right: 0; bottom: 0; }
  .menu-open .nav-links .nav-sub a { font-size: .95rem; color: var(--text); }
  .nav-cta { display: none; }
  .nav-logo .tag { display: none; }
  .nav-burger {
    display: grid; gap: 5px; background: none; border: 0; padding: .6em .2em; cursor: pointer;
  }
  .nav-burger span { width: 26px; height: 1.5px; background: var(--headings); transition: transform .4s var(--ease), opacity .3s; }
  .menu-open .nav-burger span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
  .menu-open .nav-burger span:nth-child(2) { opacity: 0; }
  .menu-open .nav-burger span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }
}

/* ---------- page hero (inner pages) ---------- */
.page-hero { padding-top: calc(var(--nav-h) + var(--section-pad)); }
.page-hero .t-h1 { max-width: 14ch; }

/* ---------- static mode (?static=1 kill switch) ---------- */
html.static { scroll-behavior: auto; }
html.static .line-mask .line-inner, html.static.js [data-reveal-text], html.static.js [data-reveal-block],
html.static.js [data-stagger] > *, html.static .frame .wipe i { transition: none !important; }
html.static [data-parallax] img { transform: none !important; }

/* ---------- lead form (.ct-form / .ct-field) ----------
   Moved verbatim from contact-us.astro: LeadForm.astro renders on more than one page now. */
.ct-form {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(1.2rem, 2.2vw, 1.7rem) 20px;
  margin-top: clamp(1.8rem, 3vw, 2.6rem);
}
.ct-span2 { grid-column: 1 / -1; }
.ct-field { display: grid; gap: .6em; align-content: start; }
.ct-field label {
  font: 600 var(--fs-eyebrow)/1.2 var(--font-mono);
  text-transform: uppercase; letter-spacing: .05em;
  color: var(--headings);
}
.ct-field :is(input, select, textarea) {
  width: 100%;
  font: 400 .95rem/1.4 var(--font-mono); letter-spacing: -0.02em;
  color: var(--ink);
  background: #fbfaf6;
  border: 1px solid #d3ccba;
  border-radius: var(--radius);
  padding: .9em 1em;
  appearance: none;
  transition: border-color .3s var(--ease-hover), box-shadow .3s var(--ease-hover), background-color .3s var(--ease-hover);
}
.ct-field :is(input, select, textarea)::placeholder { color: #8f8878; }
.ct-field :is(input, select, textarea):focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px #a3865a40;
  background: #fff;
}
.ct-field select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%2346413a' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1em center;
  background-size: .7em;
  padding-right: 2.8em;
  cursor: pointer;
}
.ct-field textarea { min-height: 10em; resize: vertical; }
.ct-actions {
  grid-column: 1 / -1;
  display: flex; align-items: center; gap: 1.2rem 1.8rem; flex-wrap: wrap;
  margin-top: .4rem;
}
.ct-note {
  font: 500 var(--fs-eyebrow)/1.6 var(--font-mono);
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--text);
}
.ct-note a {
  color: var(--headings);
  border-bottom: 1px solid var(--accent);
  padding-bottom: .12em;
  transition: color .3s var(--ease-hover);
}
.ct-note a:hover { color: var(--accent); }
/* label state on focus (color is instant-safe; nudge lives behind the media query) */
.ct-field:focus-within label { color: var(--accent-text); }
.ct-btn-label { display: inline-block; }
@media all {
  .ct-field label { transition: color .3s var(--ease-hover), transform .45s var(--ease); }
  .ct-field:focus-within label { transform: translateX(.3em); }
  .ct-btn-label { transition: opacity .22s var(--ease-hover), transform .22s var(--ease-hover); }
  .ct-busy .ct-btn-label { opacity: 0; transform: translateY(4px); }
}
@media (max-width: 860px) {
  .ct-form { grid-template-columns: 1fr; }
}

/* ---------- lead form states: honeypot, status line, success, error (js/lead-form.js) ---------- */
.lead-form [hidden] { display: none !important; }  /* .ct-form and .eyebrow set display, so [hidden] needs the override */
.ct-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.button:disabled { opacity: .6; cursor: default; transform: none; }
.ct-status {
  font: 500 var(--fs-eyebrow)/1.6 var(--font-mono);
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--text);
  margin-top: 1.4rem; max-width: 64ch;
}
.ct-status:empty { display: none; }
.ct-status a { color: var(--headings); border-bottom: 1px solid var(--accent); padding-bottom: .12em; }
.ct-status.is-error { color: #a8471f; }              /* burnt clay, AA on plaster */
.theme-dark .ct-status.is-error { color: #e0855f; }  /* lighter on ink */
.ct-field [aria-invalid="true"] { border-color: #a8471f; }
.ct-done { margin-top: clamp(1.8rem, 3vw, 2.6rem); }  /* success eyebrow sits where the form began */
.lead-form.is-done .ct-status {
  font: 340 var(--fs-h3)/1.15 var(--font-serif);
  text-transform: none; letter-spacing: -0.01em;
  color: var(--headings); margin-top: 0; max-width: 24ch;
}

/* ============================================================
   service pages (/services/<slug>) + /faq  (.svc-)
   Same plaster / ink / bronze system as the rest of the site.
   The one new device is the drawing-sheet title block that sits
   in the bottom-right corner of the hero photo, like the boxed
   corner of a construction sheet: service, area, approach.
   ============================================================ */

/* hero: geography + service H1 needs more room than the 14ch inner-page cap */
.svc-hero .t-h1 { max-width: 20ch; }
.svc-hero-lead { grid-column: span 6; }
.svc-hero-cta { grid-column: 9 / span 4; align-self: end; }
.svc-hero-media { position: relative; margin-top: clamp(3rem, 6vw, 5rem); }
.svc-hero-media .frame { aspect-ratio: 21/9; }

/* trust strip (areas pages): licence on the left, plain text only. Service pages use ListingLogos. */
.svc-trust {
  list-style: none;
  display: flex; flex-wrap: wrap; align-items: center;
  gap: .8em clamp(1.4rem, 2.6vw, 2.6rem);
  padding: 1.15rem 0;
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
.svc-trust .eyebrow { margin: 0; }
.svc-trust .num { margin-left: auto; }
.svc-trust a { border-bottom: 1px solid var(--accent); padding-bottom: .12em; transition: color .3s var(--ease-hover); }
.svc-trust a:hover { color: var(--accent-text); }

/* scope block: photo + prose + two cards, then the "why" paragraph + dot-ruled points
   (the services overview language). Photo stays first in the DOM so it leads on mobile;
   grid-row pins both columns to one row whichever side the photo sits on. */
.svc-scope > * { grid-row: 1; }
.svc-scope > .frame { align-self: center; }
.svc-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: clamp(2rem, 3.5vw, 3rem); }
/* .stack is the cards-in-the-frame's-column variant used when a scope block has no photo.
   Class-on-class out-ranks the bare .svc-cards rule above it, deliberately. */
.svc-cards.stack { grid-template-columns: 1fr; margin-top: 0; }
.svc-points { list-style: none; }
.svc-points li { border-top: 1px solid var(--border); padding: 1em 0; display: flex; gap: 1em; align-items: flex-start; }
.svc-points li::before { content: ''; width: .45em; height: .45em; border-radius: 50%; background: var(--accent); flex: none; margin-top: .5em; }
.svc-points li:last-child { border-bottom: 1px solid var(--border); }

/* areas: ruled mono list. Each name links to its page under /areas/. */
.svc-areas {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0 20px; margin-top: clamp(2.2rem, 4vw, 3.4rem);
}
.svc-areas span {
  border-top: 1px solid var(--border); padding: .9em 0;
  font: 600 var(--fs-eyebrow)/1.4 var(--font-mono);
  text-transform: uppercase; letter-spacing: .05em; color: var(--text);
  display: flex; align-items: center; gap: .6em;
}
.svc-areas span::before { content: ''; width: .4em; height: .4em; border-radius: 50%; background: var(--accent); flex: none; }
.js .svc-areas[data-stagger].is-visible > span { transition-delay: calc(.05s + var(--i, 0) * .03s); }
.svc-areas a { transition: color .3s var(--ease-hover); }
.svc-areas a:hover { color: var(--headings); }

/* faq accordions longer than the engine's six stagger slots */
.js .svc-faq[data-stagger].is-visible > *:nth-child(n+7) { transition-delay: .65s; }

@media (max-width: 860px) {
  .svc-hero-media .frame { aspect-ratio: 4/3; }
  .svc-trust .num { margin-left: 0; flex-basis: 100%; margin-top: .3em; }
  .svc-cards { grid-template-columns: 1fr; }
  /* stacked under the prose on phones, so it needs the gap the desktop column did not */
  .svc-cards.stack { margin-top: clamp(2rem, 3.5vw, 3rem); }
  .svc-scope > * { grid-row: auto; }
  .svc-frame { aspect-ratio: 4/3 !important; }
}
@media (max-width: 560px) {
  .svc-areas { grid-template-columns: repeat(2, 1fr); }
}

/* ---------- QA sweep 1.9: markdown lists inside prose had no indent, so their numbers hung into the gutter ---------- */
.t-prose ol, .t-prose ul { padding-left: 1.4em; }
.t-prose li + li { margin-top: .4em; }

/* ---------- QA sweep 1.9: keyboard and screen-reader basics ---------- */
.menu-open { overflow: hidden; }                       /* the open mobile menu must not scroll the page under it */
.skip-link {
  position: absolute; left: 1rem; top: -4rem; z-index: 2000;
  padding: .7em 1em; border-radius: var(--radius);
  background: var(--ink); color: var(--plaster);
  font: 600 var(--fs-eyebrow) var(--font-mono); text-transform: uppercase; letter-spacing: .04em;
  transition: top .2s var(--ease-hover);
}
.skip-link:focus { top: 1rem; outline: 2px solid var(--accent); outline-offset: 2px; }
:is(a, button, summary, input, select, textarea):focus-visible { outline: 2px solid var(--accent-text); outline-offset: 3px; }

/* ---------- Mobile QA 6.9: the hero headline was unreadable on a phone ----------
   The scrim above is tuned for the desktop crop, where the daylight sits to the
   right of the type. The art-directed mobile file (granby-kitchen-01-m.webp)
   puts a near-white wall directly behind the headline instead: sampled at
   rgb(210,208,206), which left the bronze italic at 1.08:1 and the plaster words
   barely better. The scrim waist there is only 0.09 alpha, so it did nothing.
   Phones get a deeper, single vertical pass. Measured after the change: bronze
   clears 3:1 and plaster clears 7:1. Desktop is untouched. */
@media (max-width: 860px) {
  .hero-media::after {
    background: linear-gradient(180deg, #191613cc 0%, #191613b8 30%, #191613b8 66%, #191613f2 100%);
  }
}

/* ---------- Mobile QA 6.9: vertical rhythm ----------
   --section-pad floors at 4.5rem, so every section boundary on a phone stacked
   76px + 76px plus element margins, about 218px of empty band. On an 812px
   screen that is a quarter of the viewport twice over, and at a light/dark
   boundary it reads as a gap rather than as breathing room. Phones only. */
@media (max-width: 560px) {
  :root { --section-pad: clamp(3.25rem, 1.5rem + 7vw, 6rem); }
}

/* ---------- Ram, 17.9: "on the phone it is a bit too much" ----------
   The body face is monospace, so every character takes the same 0.6em whatever
   it is. At 14.9px in a 357px column that is 39 characters a line, where a
   proportional face of the same size would fit nearer 58, and a 376-character
   paragraph became ten lines deep. The face is the brand and it stays; it is
   set a little smaller and a little shorter in the leading here, which buys
   about six more characters a line and takes a fifth off the height of every
   block of copy. Tracking is left alone: body already carries -0.03em, and an
   override here only ever made the line wider.
   The lead face rides down with it: --fs-xl was 18.4px here, which is only 35
   characters to a line, tighter than the body it is meant to introduce.
   Phones only: nothing above 860px moves. */
@media (max-width: 860px) {
  :root { --fs-body: 0.87rem; --fs-xl: 1.02rem; }
  body { line-height: 1.5; }
  /* .t-prose floors its measure at 40ch, which is a desktop guard against a
     over-long line. On a 390px phone the container is already narrower than
     that, so the cap only held the column 30px short of the gutter, and
     because ch scales with the font it gave the smaller size straight back.
     The gutter is the measure here. */
  .t-prose { max-width: none; }
}

/* ---------- Ram, 18.9: "the jump down here, or it looks like a bug" ----------
   The footer wordmark bleeds under the black bar on purpose: at 15rem on a
   desktop, half a word running off the bottom edge reads as typography. At the
   64px floor on a phone it is just a word cut in half, and the scroll parallax
   that pushes it down is re-measured against innerHeight, which iOS changes
   mid-scroll as it collapses its URL bar, so it visibly jumped as well. On a
   phone the word sits whole above the bar and holds still. The parallax itself
   is switched off in js/main.js, since an inline transform would win here. */
@media (max-width: 860px) {
  .footer-word { transform: none; margin-bottom: .35em; }
}
