/* ==========================================================================
   Fortify Concrete — site styles
   Tokens are the source of truth (see BRAND.md). Never hardcode a hex here
   that should be a token; never dim text with opacity (use a muted token).
   ========================================================================== */

/* ---------- Fonts (self-hosted, zero external requests) ---------- */
@font-face {
  font-family: 'Archivo';
  src: url('../assets/fonts/archivo-latin-wght-normal.woff2') format('woff2-variations');
  font-weight: 100 900; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2122, U+2212;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('../assets/fonts/ibm-plex-mono-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('../assets/fonts/ibm-plex-mono-latin-500-normal.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}

/* ---------- Tokens ---------- */
:root {
  color-scheme: light;

  /* Surfaces — WARM grade. Every neutral is pulled onto the sand's hue
     (~60-70) instead of the kit's slightly cool originals, so the whole page
     sits in one warm family. Brand accents (sand, rust) are unchanged.
     Cool originals kept in comments for reference. */
  --ink:        #1A1512;   /* was #17181A */
  --ink-raised: #231D18;   /* was #1E1F21 */
  --bone:       #F4EDE1;   /* was #F1EEE6 */
  --paper:      #FDF9F1;   /* was #FFFFFF */

  /* Accents — brand, untouched */
  --sand:       #C9B896;
  --sand-soft:  #DCCDAE;
  --rust:       #A63D2F;   /* FILL ONLY on dark — 2.87:1 as text on ink */
  --rust-hover: #8E3428;
  --rust-onlight: #8E3428; /* rust as text on light surfaces */

  /* Text — warm brown-greys */
  --text:          #4A4034;  /* was #4B4B46 */
  --muted-onlight: #6B6053;  /* was #66665C. NEVER #8A8A80 (3.00:1 on bone) */
  --muted-ondark:  #A2968A;  /* was #9C9C92 */
  /* The utility bar is 13px mono, wide-tracked, on the raised ink. At
     --muted-ondark it computes 5.76:1 — technically AA, but visibly dim at
     that size. This is the same family, two steps brighter (8.11:1). */
  --util-text:     #C0B3A3;

  /* Lines */
  --border-light: rgba(26, 21, 18, .13);
  --border-dark:  rgba(244, 237, 225, .14);
  --ring:         #C9B896;

  /* Type */
  --font-display: 'Archivo', system-ui, -apple-system, sans-serif;
  --font-body:    'Archivo', system-ui, -apple-system, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace;

  /* Space */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px; --s5: 24px;
  --s6: 32px; --s7: 48px; --s8: 64px; --s9: 96px; --s10: 128px;
  --gutter: clamp(20px, 5vw, 48px);
  /* 1320 border-box (= 1224 of content at the 48px gutter). Sized so the hero
     copy column clears "POURED RIGHT." on one line at the 80px display cap. */
  --wrap: 1320px;

  /* Radius / shadow / motion */
  --r-sm: 2px; --r-md: 4px;
  --shadow-1: 0 1px 2px rgba(26,21,18,.07), 0 10px 30px rgba(26,21,18,.11);
  --dur-fast: 160ms; --dur-mid: 320ms; --dur-slow: 560ms;
  --ease: cubic-bezier(.2,.7,.2,1);
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bone);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  /* `clip`, NOT `hidden`. overflow-x:hidden forces overflow-y to `auto`, which
     makes <body> a scroll container — and on iOS Safari that breaks
     `position: sticky` descendants (the header pinned over the utility bar and
     hid the phone number). `clip` confines overflow without creating a scroll
     container. Unsupported in Safari <16, where the declaration is simply
     dropped — harmless, because the page measures 0 horizontal overflow at
     390/768/1280/1920 anyway; this is a belt, not the braces. */
  overflow-x: clip;
}
img, svg, picture, video { display: block; max-width: 100%; }
img { height: auto; }
h1, h2, h3, h4 { margin: 0; text-wrap: balance; }
p, li { text-wrap: pretty; }
p { margin: 0 0 1em; }
a { color: inherit; }
button { font: inherit; }
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--ring); outline-offset: 3px; border-radius: var(--r-sm);
}

/* ---------- Layout primitives ---------- */
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }
.section { position: relative; padding-block: clamp(56px, 8vw, 104px); overflow: hidden; }
.section > .wrap { position: relative; z-index: 1; }
.section--bone  { background: var(--bone); }
.section--paper { background: var(--paper); }

/* Dark surfaces carry ONE marker class. Every dark override targets .on-dark. */
.on-dark { background: var(--ink); color: var(--bone); }
.on-dark h1, .on-dark h2, .on-dark h3, .on-dark h4 { color: var(--bone); }
.on-dark p, .on-dark li { color: var(--muted-ondark); }
.on-dark a:not(.btn):not(.nav__link) { color: var(--sand); }
.on-dark .eyebrow { color: var(--sand); }
.on-dark .rule::before { background: var(--sand); }
.on-dark .rule::after  { background: var(--border-dark); }

/* --- Background photography on dark bands -------------------------------
   The photos are pre-blurred, pre-graded and pre-darkened at build time
   (640x360, ~2.5 KB each) — no runtime `filter: blur()`, and no visible
   softness from upscaling a 383px source, because they are already abstract.
   The scrim is 0.84 ink. Verified numerically against each image's BRIGHTEST
   pixel: worst-case effective background is #221B15, on which the tightest
   text token (--muted-ondark) still measures 5.88:1. Do not lower the scrim
   below 0.82 — that is where body text starts approaching 4.5:1. */
.on-dark { background-color: var(--ink); }
.on-dark.has-bg {
  background-image:
    linear-gradient(rgba(26, 21, 18, .84), rgba(26, 21, 18, .88)),
    var(--bg-photo);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
.bg--steps    { --bg-photo: url('../assets/img/bg-steps.webp'); }
.bg--backyard { --bg-photo: url('../assets/img/bg-backyard.webp'); }
.bg--team     { --bg-photo: url('../assets/img/bg-team.webp'); }

/* Atmosphere: drafting grid + a low sand/rust glow, drawn as pseudo-elements.
   Data-URI SVG = zero extra requests. Grid is dialled back where a photo
   sits behind it so the two textures don't fight. */
.on-dark::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cg fill='none' stroke='%23C9B896' stroke-width='1' opacity='.09'%3E%3Cpath d='M0 .5h120M.5 0v120'/%3E%3C/g%3E%3Cg fill='none' stroke='%23C9B896' stroke-width='1' opacity='.045'%3E%3Cpath d='M0 30.5h120M0 60.5h120M0 90.5h120M30.5 0v120M60.5 0v120M90.5 0v120'/%3E%3C/g%3E%3C/svg%3E");
}
.on-dark.has-bg::before { opacity: .55; }
.on-dark::after {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(60% 70% at 12% 0%,   rgba(201,184,150,.15), transparent 65%),
    radial-gradient(55% 60% at 92% 100%, rgba(166,61,47,.17),   transparent 62%);
}

/* --- Page grain ----------------------------------------------------------
   A warm concrete tooth over the whole page. Fixed, non-interactive, 3.4%.
   Tiny tiled SVG = zero extra requests and no layout cost. */
body::after {
  content: ''; position: fixed; inset: 0; z-index: 9999; pointer-events: none;
  opacity: .034;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)'/%3E%3C/svg%3E");
}

/* ---------- Type roles ---------- */
.eyebrow {
  font-family: var(--font-mono); font-size: .75rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: .22em; color: var(--rust-onlight);
  margin: 0 0 var(--s4);
}
.h-display {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: -.015em; line-height: .92; color: var(--ink);
  font-size: clamp(2.6rem, 6.6vw, 5.4rem);
}
.h-section {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: -.01em; line-height: .98; color: var(--ink);
  font-size: clamp(1.9rem, 4.2vw, 3.2rem);
}
.h-card {
  font-family: var(--font-display); font-weight: 700; text-transform: uppercase;
  letter-spacing: .01em; line-height: 1.15; font-size: 1.1875rem; color: var(--ink);
}
.lede { font-size: clamp(1.0625rem, 1.4vw, 1.1875rem); line-height: 1.65; max-width: 56ch; }
.meta { font-family: var(--font-mono); font-size: .8125rem; letter-spacing: .02em; }

/* SIGNATURE: the drafting rule — a plumb tick over a level line, lifted from
   the logo's set-square artwork. Sits under every section heading. */
.rule { position: relative; height: 18px; margin: var(--s5) 0 var(--s6); }
.rule::before {
  content: ''; position: absolute; left: 0; top: 0; width: 2px; height: 18px;
  background: var(--rust-onlight);
}
.rule::after {
  content: ''; position: absolute; left: 0; top: 8px; width: 84px; height: 2px;
  background: var(--border-light);
}
.rule--center { margin-inline: auto; width: 84px; }
.rule--center::before { left: 41px; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .6em;
  padding: 15px 26px; min-height: 48px;
  font-family: var(--font-display); font-size: .875rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .14em; text-decoration: none;
  border: 2px solid transparent; border-radius: var(--r-sm); cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.btn:active { transform: translateY(1px); }
/* rust fill + white text = 6.31:1. Never rust as text on ink (2.82:1). */
.btn--primary { background: var(--rust); border-color: var(--rust); color: #fff; }
.btn--primary:hover { background: var(--rust-hover); border-color: var(--rust-hover); }
.btn--ghost { background: transparent; border-color: var(--sand); color: var(--sand); }
.btn--ghost:hover { background: var(--sand); color: var(--ink); }
.btn--line { background: transparent; border-color: var(--ink); color: var(--ink); }
.btn--line:hover { background: var(--ink); color: var(--bone); }

/* ---------- Utility bar ---------- */
.util {
  background: var(--ink-raised); color: var(--util-text);
  font-family: var(--font-mono); font-size: .8125rem; font-weight: 500;
  letter-spacing: .04em;
  border-bottom: 1px solid var(--border-dark);
}
.util .wrap { display: flex; flex-wrap: wrap; gap: 0 var(--s6); align-items: center; padding-block: 2px; }
.util .wrap > * { padding-block: 12px; }
.util a { color: var(--sand); text-decoration: none; display: inline-block; padding-block: 12px; }
.util a:hover { text-decoration: underline; }
.util__spacer { margin-left: auto; }

/* ---------- Header ---------- */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: var(--ink); border-bottom: 1px solid var(--border-dark);
}
.site-header .wrap { display: flex; align-items: center; gap: var(--s5); padding-block: 14px; }
.brand { display: inline-flex; align-items: center; text-decoration: none; flex: none; }
/* Logo art is near-black on transparent — knock it out for the ink header.
   The lockup is STACKED (mark over wordmark, aspect 1.35), so it is sized by
   HEIGHT: a width-based size makes the header ~140px tall. See BRAND.md. */
.brand img { height: 72px; width: auto; filter: brightness(0) invert(1); }

.nav { margin-left: auto; display: flex; align-items: center; gap: clamp(14px, 2vw, 30px); }
.nav__link {
  font-family: var(--font-display); font-size: .8125rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .14em; color: var(--bone);
  text-decoration: none; padding: 12px 0; position: relative;
}
.nav__link::after {
  content: ''; position: absolute; left: 0; right: 100%; bottom: 6px; height: 2px;
  background: var(--sand); transition: right var(--dur-mid) var(--ease);
}
.nav__link:hover::after { right: 0; }
.nav .btn { padding: 12px 20px; min-height: 44px; }

/* Mobile tap-to-call — lives in the sticky header so it survives scrolling.
   Sand on ink = 8.55:1; the border makes the tap target explicit. */
.call-btn {
  display: none; align-items: center; gap: 9px;
  margin-left: auto; padding: 10px 14px; min-height: 44px;
  border: 1px solid var(--sand); border-radius: var(--r-sm);
  color: var(--sand); text-decoration: none;
  font-family: var(--font-mono); font-size: .8125rem; font-weight: 500;
  letter-spacing: .02em; white-space: nowrap;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.call-btn svg { width: 15px; height: 15px; flex: none; }
.call-btn:hover { background: var(--sand); color: var(--ink); }

.nav-toggle {
  display: none; margin-left: var(--s3); width: 48px; height: 44px; flex: none;
  background: transparent; border: 1px solid var(--border-dark); border-radius: var(--r-sm);
  color: var(--bone); cursor: pointer; align-items: center; justify-content: center;
}
.nav-toggle span, .nav-toggle span::before, .nav-toggle span::after {
  display: block; width: 20px; height: 2px; background: currentColor; content: '';
  transition: transform var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.nav-toggle span { position: relative; }
.nav-toggle span::before { position: absolute; top: -6px; }
.nav-toggle span::after  { position: absolute; top: 6px; }
.nav-toggle[aria-expanded='true'] span { background: transparent; }
.nav-toggle[aria-expanded='true'] span::before { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded='true'] span::after  { transform: translateY(-6px) rotate(-45deg); }

/* ---------- Hero ---------- */
.hero { position: relative; background: var(--ink); color: var(--bone); overflow: hidden; }
.hero .wrap {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(32px, 5vw, 72px); align-items: center;
  padding-block: clamp(56px, 8vw, 104px);
}
/* No max-width on the copy column: a ch-cap resolved against the 17px body
   size squeezed the 79px H1 into four short lines. The <br> sets the break.
   container-type makes this column the sizing reference for the headline. */
.hero__copy { min-width: 0; container-type: inline-size; }

/* Sized in `cqi` (this column's width), NOT `vw`. The column is the viewport
   MINUS a photo column that is itself clamped, so its width does not track the
   viewport linearly — a vw-derived size fitted at 390/768/1280/1920 and still
   broke to 4 lines across ~880-1050px, where the two-column layout has just
   started but the column is at its narrowest. 11cqi keeps the longest segment
   ("POURED RIGHT." ≈ 8.5x the font size) inside the column at every width.
   `balance` is wrong here: with an explicit <br> it split segment one in two. */
.hero h1 {
  color: var(--bone);
  font-size: clamp(2rem, 11cqi, 5rem);
  text-wrap: normal;
}
.hero h1 em { font-style: normal; color: var(--sand); }
.hero__lede { color: var(--muted-ondark); max-width: 46ch; margin-top: var(--s5); }
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--s4); margin-top: var(--s7); }
.hero__license {
  margin-top: var(--s6); padding-top: var(--s5); border-top: 1px solid var(--border-dark);
  font-family: var(--font-mono); font-size: .75rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--sand);
}

/* Photo pair — sized so neither image is ever upscaled past ~1.05x native
   (source photos are 383x510; that ceiling is why there is no full-bleed photo). */
.hero__media { position: relative; flex: none; width: clamp(280px, 34vw, 400px); }
.frame {
  position: relative; overflow: hidden; border-radius: var(--r-sm);
  background: var(--ink-raised); box-shadow: var(--shadow-1);
  outline: 1px solid var(--border-dark); outline-offset: 0;
}
.frame img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 383 / 510; }
.hero__frame { aspect-ratio: 383 / 510; }
.hero__frame img { position: absolute; inset: 0; opacity: 0; transition: opacity 480ms var(--ease); }
.hero__frame img.is-active { opacity: 1; }
.hero__inset {
  position: absolute; left: -14%; bottom: -8%; width: 52%;
  border: 5px solid var(--ink); border-radius: var(--r-sm); overflow: hidden;
  box-shadow: var(--shadow-1);
}
.hero__inset img { aspect-ratio: 383 / 510; object-fit: cover; width: 100%; }
.hero__dots { position: absolute; right: 4px; bottom: 4px; display: flex; z-index: 2; }
.hero__dots button {
  width: 44px; height: 44px; padding: 0; border: 0; background: transparent;
  cursor: pointer; display: grid; place-items: center;
}
.hero__dots button::before {
  content: ''; width: 8px; height: 8px; border-radius: 50%;
  background: var(--muted-ondark); transition: background var(--dur-fast) var(--ease);
}
.hero__dots button[aria-current='true']::before { background: var(--sand); }

/* ---------- Spec strip (sand band — INK TEXT ONLY, white is 1.95:1) ---------- */
.spec { background: var(--sand); color: var(--ink); }
.spec .wrap { padding-block: 18px; }
/* The <ul> is the flex row itself. `display:contents` on a list can strip its
   semantics in some AT/browser pairs — not worth it for one row. */
.spec ul {
  margin: 0; padding: 0; list-style: none;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--s3) clamp(20px, 4vw, 52px);
}
.spec li {
  font-family: var(--font-mono); font-size: .8125rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: .12em; color: var(--ink);
  display: flex; align-items: center; gap: 10px;
}
.spec li::before { content: ''; width: 6px; height: 6px; background: var(--ink); flex: none; }

/* ---------- Section heading blocks ---------- */
.sec-head { max-width: 62ch; margin-bottom: var(--s7); }
.sec-head--center { text-align: center; margin-inline: auto; }
.sec-head--center .eyebrow { }
.sec-head p { color: var(--muted-onlight); margin-bottom: 0; }
.on-dark .sec-head p { color: var(--muted-ondark); }

/* ---------- Service cards (icon cards — matches the reference's icon grid) ---------- */
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; background: var(--border-light); border: 1px solid var(--border-light); }
.svc {
  background: var(--bone); padding: clamp(24px, 3vw, 38px);
  display: grid; grid-template-rows: subgrid; grid-row: span 4; gap: var(--s4);
  transition: background var(--dur-mid) var(--ease);
}
.section--paper .grid-3 .svc { background: var(--paper); }
.svc:hover { background: var(--paper); }
.section--paper .grid-3 .svc:hover { background: var(--bone); }
.svc__top { display: flex; align-items: center; justify-content: space-between; gap: var(--s4); }
.svc__num {
  font-family: var(--font-mono); font-size: .75rem; font-weight: 500;
  letter-spacing: .16em; color: var(--muted-onlight);
}
.svc__icon { width: 40px; height: 40px; color: var(--rust-onlight); flex: none; }
.svc__icon svg { width: 100%; height: 100%; }
.svc p { color: var(--muted-onlight); font-size: .9375rem; margin: 0; }
.svc__more {
  font-family: var(--font-mono); font-size: .75rem; font-weight: 500; letter-spacing: .14em;
  text-transform: uppercase; color: var(--rust-onlight); text-decoration: none;
  align-self: end; display: inline-flex; align-items: center; gap: 8px;
  padding: 12px 0; min-height: 44px;
}
.svc__more::after { content: '→'; transition: transform var(--dur-fast) var(--ease); }
.svc__more:hover::after { transform: translateX(4px); }

/* ---------- Project cards ---------- */
.projects { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(18px, 2.4vw, 30px); }
.project { position: relative; }
.project .frame { border-radius: var(--r-sm); }
.project img {
  transition: transform var(--dur-slow) var(--ease), filter var(--dur-slow) var(--ease);
  filter: saturate(.92) contrast(1.04);
}
.project:hover img { transform: scale(1.04); filter: saturate(1) contrast(1.06); }
.project__cat {
  font-family: var(--font-mono); font-size: .6875rem; font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase; color: var(--sand);
  margin: var(--s5) 0 8px;
}
.project__title {
  font-family: var(--font-display); font-weight: 700; text-transform: uppercase;
  font-size: 1.0625rem; letter-spacing: .01em; color: var(--bone); line-height: 1.25;
}
.project__scrim {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top, rgba(26,21,18,.62), transparent 48%);
}

/* ---------- Why / accordion ---------- */
.split { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: clamp(32px, 5vw, 72px); align-items: start; }
.acc { border-top: 1px solid var(--border-light); }
.acc details { border-bottom: 1px solid var(--border-light); }
.acc summary {
  list-style: none; cursor: pointer; padding: 20px 40px 20px 0; position: relative;
  font-family: var(--font-display); font-weight: 700; font-size: 1.0625rem;
  color: var(--ink); line-height: 1.35;
}
.acc summary::-webkit-details-marker { display: none; }
.acc summary::after {
  content: ''; position: absolute; right: 4px; top: 50%; width: 14px; height: 2px;
  background: var(--rust-onlight); transform: translateY(-50%);
}
.acc summary::before {
  content: ''; position: absolute; right: 10px; top: 50%; width: 2px; height: 14px;
  background: var(--rust-onlight); transform: translateY(-50%);
  transition: transform var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.acc details[open] summary::before { transform: translateY(-50%) rotate(90deg); opacity: 0; }
.acc details p { color: var(--muted-onlight); font-size: .9375rem; padding-bottom: 20px; margin: 0; max-width: 60ch; }
.why__media { position: relative; }
.why__media .frame { max-width: 400px; margin-inline: auto; }
.why__stamp {
  position: absolute; right: max(0px, calc(50% - 200px - 22px)); bottom: -18px;
  background: var(--ink); color: var(--sand); padding: 14px 18px; border-radius: var(--r-sm);
  font-family: var(--font-mono); font-size: .6875rem; letter-spacing: .16em;
  text-transform: uppercase; line-height: 1.5; box-shadow: var(--shadow-1);
}
.why__stamp b { display: block; color: var(--bone); font-weight: 500; font-size: .8125rem; }

/* ---------- Process ---------- */
.steps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(20px, 3vw, 40px); }
.step { position: relative; padding-top: var(--s5); border-top: 2px solid var(--ink); }
/* Sand is 1.95:1 on white — the step numerals sit on a light band, so they
   take rust-onlight (7.4:1). Sand numerals only ever appear on .on-dark. */
.step__n {
  font-family: var(--font-display); font-weight: 900; font-size: clamp(2rem, 3.4vw, 2.75rem);
  letter-spacing: -.02em; line-height: 1; color: var(--rust-onlight); display: block; margin-bottom: var(--s3);
}
.step h3 { font-family: var(--font-display); font-weight: 700; text-transform: uppercase; font-size: 1rem; letter-spacing: .04em; color: var(--ink); margin-bottom: 8px; }
.step p { color: var(--muted-onlight); font-size: .9375rem; margin: 0; }

/* ---------- Credentials band ---------- */
.creds { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px; background: var(--border-dark); border: 1px solid var(--border-dark); }
.cred { background: var(--ink-raised); padding: clamp(22px, 2.6vw, 32px); }
.cred__k {
  font-family: var(--font-mono); font-size: .6875rem; font-weight: 500; letter-spacing: .2em;
  text-transform: uppercase; color: var(--sand); margin-bottom: 10px;
}
.cred__v {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  font-size: clamp(1.125rem, 1.9vw, 1.5rem); line-height: 1.1; letter-spacing: -.01em; color: var(--bone);
}
.cred p { font-size: .875rem; margin: 10px 0 0; color: var(--muted-ondark); }

/* ---------- Estimate form ---------- */
.estimate { display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); gap: clamp(32px, 5vw, 72px); align-items: start; }
.estimate__intro { color: var(--muted-onlight); }
.contact-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s5); }
.contact-list dd { margin: 0; }
.contact-list dt, .contact-list .k {
  font-family: var(--font-mono); font-size: .6875rem; font-weight: 500; letter-spacing: .2em;
  text-transform: uppercase; color: var(--rust-onlight); margin-bottom: 6px;
}
.contact-list .v { font-family: var(--font-display); font-weight: 700; font-size: 1.0625rem; color: var(--ink); text-decoration: none; }
.contact-list a.v { display: inline-flex; align-items: center; min-height: 44px; font-size: 1.375rem; }
.contact-list a.v:hover { color: var(--rust-onlight); }

.form { background: var(--paper); border: 1px solid var(--border-light); padding: clamp(22px, 3vw, 38px); }
.form__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); }
.field { display: flex; flex-direction: column; gap: 7px; }
.field--full { grid-column: 1 / -1; }
.field label {
  font-family: var(--font-mono); font-size: .6875rem; font-weight: 500; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted-onlight);
}
.field input, .field select, .field textarea {
  font-family: var(--font-body); font-size: 1rem; color: var(--ink);
  background: var(--bone); border: 1px solid var(--border-light); border-radius: var(--r-sm);
  padding: 13px 14px; min-height: 48px; width: 100%;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.field textarea { min-height: 128px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus { background: var(--paper); border-color: var(--ink); }
.form .btn { width: 100%; margin-top: var(--s2); }
.form__note { font-family: var(--font-mono); font-size: .75rem; color: var(--muted-onlight); margin: var(--s4) auto 0; text-align: center; max-width: 46ch; }

/* ---------- Footer ---------- */
.site-footer { background: var(--ink); color: var(--muted-ondark); padding-block: clamp(48px, 6vw, 80px) 0; position: relative; overflow: hidden; }
.footer-grid { display: grid; grid-template-columns: minmax(0, 1.3fr) repeat(2, minmax(0, 1fr)); gap: clamp(28px, 4vw, 56px); position: relative; z-index: 1; }
.site-footer .brand img { height: 132px; width: auto; }
.footer__blurb { margin-top: var(--s5); max-width: 38ch; }
/* .on-dark p (0,1,1) outranks a bare class (0,1,0) — scope it to win. */
.site-footer .footer__license { color: var(--sand); }
.footer__cta { margin-top: var(--s5); }
.site-footer .footer__h {
  font-family: var(--font-mono); font-size: .6875rem; font-weight: 500; letter-spacing: .2em;
  text-transform: uppercase; color: var(--sand); margin-bottom: var(--s5);
}
.site-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.site-footer li { min-height: 40px; display: flex; align-items: center; }
.site-footer a:not(.btn) { color: var(--muted-ondark); text-decoration: none; display: inline-flex; align-items: center; min-height: 40px; }
.site-footer a:hover { color: var(--sand); }
.footer-bar {
  margin-top: clamp(36px, 5vw, 64px); border-top: 1px solid var(--border-dark);
  padding-block: 20px; display: flex; flex-wrap: wrap; gap: var(--s3) var(--s6);
  font-family: var(--font-mono); font-size: .75rem; letter-spacing: .04em;
  position: relative; z-index: 1;
}
.footer-bar span:last-child { margin-left: auto; }

/* ---------- Scroll reveal ------------------------------------------------
   FAILS OPEN. The hidden state is gated on .reveal-armed, which site.js adds
   ONLY after an IntersectionObserver is successfully constructed, and which a
   2.5s failsafe tears down. No JS, old browser, observer that never fires,
   reduced motion → content is simply visible. Never let copy depend on JS. */
.reveal-armed .reveal { opacity: 0; transform: translateY(18px); }
.reveal-armed .reveal.is-in { opacity: 1; transform: none; transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease); }
.reveal-armed .reveal:nth-child(2) { transition-delay: 70ms; }
.reveal-armed .reveal:nth-child(3) { transition-delay: 140ms; }
.reveal-armed .reveal:nth-child(4) { transition-delay: 210ms; }

/* ==========================================================================
   Responsive — collapse points chosen so 768 never shows a cramped 3-col
   ========================================================================== */
@media (max-width: 1080px) {
  .estimate { grid-template-columns: 1fr; }
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 960px) {
  .grid-3, .projects, .creds { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .svc { grid-row: auto; grid-template-rows: none; }
  .split { grid-template-columns: 1fr; }
  .why__media { order: -1; }
  .why__stamp { right: max(0px, calc(50% - 200px + 8px)); }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .site-footer .brand { grid-column: 1 / -1; }
}
@media (max-width: 880px) {
  .hero .wrap { grid-template-columns: 1fr; }
  .hero__media { width: min(400px, 78%); margin-inline: auto; }
  .hero__inset { left: -10%; width: 46%; }
  .hero__copy { max-width: none; }

  .brand img { height: 52px; }
  /* Tighter gap: at 375 the logo + full phone number + 48px toggle need every
     pixel, and the toggle must never shrink below its tap target. */
  .site-header .wrap { gap: var(--s3); }
  .call-btn { display: inline-flex; }
  .nav-toggle { display: inline-flex; }
  /* Anchored to the header itself (which is sticky, so it is a containing
     block) — NOT `fixed` at a JS-measured offset. The measured version drifted
     whenever the header's height changed without a resize/scroll event firing,
     leaving a visible gap between the bar and the panel. `top: 100%` cannot
     drift. */
  .nav {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--ink); border-bottom: 1px solid var(--border-dark);
    padding: var(--s4) var(--gutter) var(--s6);
    transform: translateY(-130%);
    max-height: 78dvh; overflow-y: auto; margin-left: 0;
    /* visibility (not z-index:-1) hides the closed panel: a negative-z child
       paints ABOVE its stacking context's own background, so the panel's
       bottom hairline would streak across the header. visibility also keeps
       the closed links out of the tab order. Delayed to the end of the slide
       on close, instant on open. */
    visibility: hidden;
    transition: transform var(--dur-mid) var(--ease),
                visibility 0s linear var(--dur-mid);
  }
  .nav.is-open {
    transform: none; visibility: visible;
    transition: transform var(--dur-mid) var(--ease), visibility 0s;
  }
  .nav__link { padding: 15px 0; border-bottom: 1px solid var(--border-dark); }
  .nav__link::after { display: none; }
  .nav .btn { margin-top: var(--s5); width: 100%; }
}
/* iPhone SE / older small Androids: logo + full phone number + a 48px tap
   target do not fit a 320px row at the default sizes (measured 21px of
   overflow). Tighten the logo and the call pill rather than dropping the
   number — the number being visible is the whole point of the component. */
@media (max-width: 400px) {
  .site-header .wrap { gap: var(--s2); padding-inline: 14px; }
  .brand img { height: 44px; }
  .call-btn { padding: 8px 10px; gap: 6px; font-size: .75rem; letter-spacing: 0; }
  .call-btn svg { width: 14px; height: 14px; }
  .nav-toggle { margin-left: var(--s2); width: 44px; }
}

@media (max-width: 620px) {
  .grid-3, .projects, .creds, .steps, .form__grid, .footer-grid { grid-template-columns: 1fr; }
  .site-footer .brand { grid-column: auto; }
  .hero__inset { display: none; }
  .hero__media { width: min(360px, 92%); }
  /* The utility bar wrapped to three rows and ate 101px of a 390px viewport,
     and its only mobile-relevant item — the phone — is now in the sticky
     header, where it survives scrolling. Hours and license both still appear
     in the hero and the footer. */
  .util { display: none; }
  .footer-bar span:last-child { margin-left: 0; }
  .why__stamp { position: static; display: inline-block; margin-top: var(--s5); }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  /* Finite entrances snap to end state; the hero cross-fade is JS-gated off. */
  .reveal-armed .reveal { opacity: 1; transform: none; }
  .hero__frame img { transition: none; }
  .project:hover img { transform: none; }
}
