@charset "UTF-8";
/* ==========================================================================
   TWO TREES CONSTRUCTION GROUP LLC — Design System
   Single stylesheet for the entire site. No build step, no frameworks,
   no external fonts, no CDN. System font stack only.

   TABLE OF CONTENTS
   01. Tokens (:root custom properties)
   02. Reset / normalize
   03. Base elements & fluid typography
   04. Accessibility helpers (skip link, .visually-hidden, focus)
   05. Layout primitives (.container, .section, .split, .stack)
   06. Section rhythm (.eyebrow, .section-head, .lede, .rule)
   07. Buttons
   08. Site header + nav (mobile hamburger, sticky/.is-scrolled)
   09. Hero (full-bleed dark)
   10. Cards & card grid
   11. Service detail blocks + check lists
   12. Process / numbered steps
   13. Callout, panel, CTA band
   14. Service-area town list
   15. FAQ (details/summary accordion)
   16. Gallery grid + lightbox overlay
   17. Forms
   18. Contact / info blocks
   19. Site footer (NJ license line)
   20. Reveal-on-scroll utility (JS-gated, degrades visible)
   21. Small utilities
   22. prefers-reduced-motion
   23. Print styles
   ========================================================================== */


/* ==========================================================================
   01. TOKENS
   ========================================================================== */

:root {
  /* --- Brand color ------------------------------------------------------
     The logo is stark black on transparent with a classical serif wordmark.
     The palette mirrors that: a deep warm near-black, a bone off-white, and
     ONE muted natural accent (moss/olive) used sparingly. Warm tan is a
     secondary tint only — never a button color. */

  --c-ink:          #16170F;  /* deep warm near-black — primary dark ground */
  --c-ink-soft:     #24261B;  /* raised dark surface (cards on dark) */
  --c-ink-line:     #363929;  /* hairlines on dark */

  --c-bone:         #F6F3EC;  /* page background — warm off-white */
  --c-bone-deep:    #EDE8DE;  /* alternating / tinted section ground */
  --c-paper:        #FFFFFF;  /* card & input surface on light */

  --c-moss:         #5E6B45;  /* the one accent — muted olive */
  --c-moss-deep:    #48532F;  /* accent hover / pressed */
  --c-moss-soft:    #E4E7D8;  /* accent wash for tags & icon plates */
  --c-tan:          #B8A382;  /* warm tan — hairlines and accents on DARK only */
  --c-tan-text:     #7A6646;  /* same tan, dark enough to be TEXT on light
                                 grounds — 4.97:1 on bone (WCAG AA) */

  --c-text:         #1B1C13;  /* body text on light */
  --c-text-muted:   #55584A;  /* secondary text on light */
  --c-text-faint:   #676A5C;  /* captions, meta, placeholders — WCAG AA (5.0:1 on bone) */
  --c-on-dark:      #F6F3EC;  /* body text on dark */
  --c-on-dark-mute: #B7B9A8;  /* secondary text on dark */

  --c-line:         #DCD6C8;  /* hairline on light */
  --c-line-strong:  #C4BCA9;  /* stronger decorative hairline (not a control edge) */
  /* Form controls need a 3:1 edge against their background (WCAG 1.4.11),
     which the decorative hairline above does not meet. Controls use this. */
  --c-input-border: #928464;  /* 3.68:1 on paper, 3.32:1 on bone, 3.01:1 on bone-deep */

  --c-error:        #8E2C22;
  --c-error-soft:   #FBEDEB;
  --c-success:      #3F6340;
  --c-success-soft: #E8F0E6;

  --c-focus:        #2F6DBF;  /* high-contrast focus ring, brand-neutral */

  /* --- Type -------------------------------------------------------------
     Serif display (system): Georgia -> Iroquois -> Times New Roman.
     Sans body: native UI stack. */
  --font-display: Georgia, "Iroquois", "Times New Roman", "Times", serif;
  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
               "Liberation Mono", monospace;

  /* Fluid type scale — clamp(min, preferred, max). Viewport 360px → 1440px. */
  --fs-xs:    clamp(0.75rem, 0.72rem + 0.12vw, 0.8125rem);   /* 12 → 13 */
  --fs-sm:    clamp(0.8125rem, 0.78rem + 0.16vw, 0.875rem);  /* 13 → 14 */
  --fs-base:  clamp(1rem, 0.96rem + 0.18vw, 1.0625rem);      /* 16 → 17 */
  --fs-md:    clamp(1.0625rem, 1rem + 0.28vw, 1.1875rem);    /* 17 → 19 */
  --fs-lg:    clamp(1.1875rem, 1.09rem + 0.42vw, 1.375rem);  /* 19 → 22 */
  --fs-xl:    clamp(1.375rem, 1.22rem + 0.68vw, 1.75rem);    /* 22 → 28 */
  --fs-2xl:   clamp(1.625rem, 1.36rem + 1.16vw, 2.375rem);   /* 26 → 38 */
  --fs-3xl:   clamp(2rem, 1.55rem + 2vw, 3.125rem);          /* 32 → 50 */
  --fs-4xl:   clamp(2.375rem, 1.66rem + 3.18vw, 4.125rem);   /* 38 → 66 */

  --lh-tight:  1.08;
  --lh-snug:   1.22;
  --lh-normal: 1.45;
  --lh-loose:  1.65;

  --ls-tight:  -0.015em;
  --ls-normal: 0;
  --ls-wide:   0.06em;
  --ls-wider:  0.16em;   /* eyebrows, the "Construction Group" feel */

  /* --- Space scale (4px base, fluid at the top end) ---------------------- */
  --sp-3xs: 0.25rem;   /*  4 */
  --sp-2xs: 0.5rem;    /*  8 */
  --sp-xs:  0.75rem;   /* 12 */
  --sp-sm:  1rem;      /* 16 */
  --sp-md:  1.5rem;    /* 24 */
  --sp-lg:  2rem;      /* 32 */
  --sp-xl:  3rem;      /* 48 */
  --sp-2xl: 4rem;      /* 64 */
  --sp-3xl: 6rem;      /* 96 */

  /* Vertical rhythm for full sections — fluid */
  --sp-section:       clamp(3.5rem, 2.4rem + 4.8vw, 7rem);
  --sp-section-tight: clamp(2.5rem, 1.9rem + 2.6vw, 4.5rem);
  --gutter:           clamp(1.25rem, 0.9rem + 1.6vw, 2.5rem);

  /* --- Containers -------------------------------------------------------- */
  --w-page:   1240px;  /* default container */
  --w-wide:   1440px;  /* wide container (gallery, full grids) */
  --w-narrow: 940px;   /* narrow container (forms, FAQ) */
  --w-prose:  66ch;    /* measure for running text */

  /* --- Radii -------------------------------------------------------------
     Restrained. Near-square edges read as craftsman, not franchise. */
  --r-xs:   2px;
  --r-sm:   3px;
  --r-md:   5px;
  --r-lg:   8px;
  --r-pill: 999px;

  /* --- Shadows (low, warm, never glossy) --------------------------------- */
  --sh-xs: 0 1px 2px rgba(22, 23, 15, 0.05);
  --sh-sm: 0 1px 2px rgba(22, 23, 15, 0.05), 0 2px 6px rgba(22, 23, 15, 0.05);
  --sh-md: 0 2px 4px rgba(22, 23, 15, 0.05), 0 8px 20px rgba(22, 23, 15, 0.07);
  --sh-lg: 0 4px 8px rgba(22, 23, 15, 0.06), 0 20px 48px rgba(22, 23, 15, 0.12);
  --sh-header: 0 1px 0 rgba(22, 23, 15, 0.08), 0 6px 20px rgba(22, 23, 15, 0.06);

  /* --- Motion ------------------------------------------------------------ */
  --t-fast:   120ms;
  --t-base:   220ms;
  --t-slow:   420ms;
  --t-reveal: 700ms;
  --ease:      cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out:  cubic-bezier(0.16, 1, 0.3, 1);

  /* --- Chrome ------------------------------------------------------------ */
  --header-h: 76px;         /* overridden at small widths below */
  --z-header: 100;
  --z-navpanel: 95;
  --z-lightbox: 200;
  --z-skiplink: 300;

  color-scheme: light;
  accent-color: var(--c-moss);
}

@media (max-width: 900px) {
  :root { --header-h: 64px; }
}


/* ==========================================================================
   02. RESET / NORMALIZE
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1.5rem);
  -moz-tab-size: 4;
  tab-size: 4;
}

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd, ol, ul, fieldset, legend {
  margin: 0;
  padding: 0;
}

ul[class], ol[class] { list-style: none; }

img, svg, video, canvas, picture, iframe {
  display: block;
  max-width: 100%;
}
img, video { height: auto; }

svg { fill: currentColor; }

input, button, textarea, select {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}

button { background: none; border: 0; }

textarea { resize: vertical; }

table { border-collapse: collapse; border-spacing: 0; }

hr {
  border: 0;
  border-top: 1px solid var(--c-line);
  margin: var(--sp-lg) 0;
}

[hidden] { display: none !important; }

/* No page should ever scroll sideways. */
html, body { overflow-x: clip; max-width: 100%; }


/* ==========================================================================
   03. BASE ELEMENTS & TYPOGRAPHY
   ========================================================================== */

body {
  font-family: var(--font-body);
  font-size: var(--fs-base);
  line-height: var(--lh-loose);
  color: var(--c-text);
  background-color: var(--c-bone);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Sticky footer. 100vh is the fallback; mobile browsers count the collapsing
     URL bar and overshoot, so dvh corrects it where supported. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

/* Page authors: <main id="main"> is the flex child that grows. */
main { flex: 1 0 auto; display: block; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  color: var(--c-ink);
  text-wrap: balance;
}
h5, h6 {
  font-family: var(--font-body);
  font-weight: 600;
  line-height: var(--lh-snug);
  color: var(--c-ink);
}

h1 { font-size: var(--fs-3xl); line-height: var(--lh-tight); }
h2 { font-size: var(--fs-2xl); }
h3 { font-size: var(--fs-xl); }
h4 { font-size: var(--fs-lg); }
h5 { font-size: var(--fs-md); }
h6 { font-size: var(--fs-sm); letter-spacing: var(--ls-wide); text-transform: uppercase; }

p { text-wrap: pretty; }

/* Default vertical rhythm between flow siblings inside content areas. */
p + p,
p + ul, p + ol,
ul + p, ol + p,
p + h2, p + h3, ul + h3, ol + h3, p + h4 {
  margin-top: var(--sp-sm);
}
p + h2, ul + h2, ol + h2 { margin-top: var(--sp-xl); }
p + h3, ul + h3, ol + h3 { margin-top: var(--sp-lg); }

a {
  color: var(--c-moss-deep);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: color-mix(in srgb, var(--c-moss-deep) 40%, transparent);
  transition: color var(--t-fast) var(--ease),
              text-decoration-color var(--t-fast) var(--ease);
}
a:hover { color: var(--c-ink); text-decoration-color: currentColor; }

strong, b { font-weight: 600; color: var(--c-ink); }

small { font-size: var(--fs-sm); }

::selection { background: var(--c-moss); color: var(--c-bone); }

/* Default list styling inside prose */
.prose ul, .prose ol { padding-left: 1.25em; }
.prose li + li { margin-top: var(--sp-2xs); }
.prose { max-width: var(--w-prose); }
.prose > * + * { margin-top: var(--sp-sm); }


/* ==========================================================================
   04. ACCESSIBILITY HELPERS
   ========================================================================== */

/* Skip link — page authors put this as the FIRST child of <body>:
   <a class="skip-link" href="#main">Skip to content</a>            */
.skip-link {
  position: fixed;
  top: var(--sp-2xs);
  left: var(--sp-2xs);
  z-index: var(--z-skiplink);
  transform: translateY(-160%);
  display: inline-block;
  padding: 0.75rem 1.25rem;
  background: var(--c-ink);
  color: var(--c-bone);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  text-decoration: none;
  border-radius: var(--r-sm);
  box-shadow: var(--sh-md);
  transition: transform var(--t-base) var(--ease-out);
}
.skip-link:focus-visible,
.skip-link:focus { transform: translateY(0); }

.visually-hidden:not(:focus):not(:active) {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Global focus treatment. Visible on every interactive element. */
:focus { outline: none; }
:focus-visible {
  outline: 3px solid var(--c-focus);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}
/* On dark grounds the ring gets a bone halo so it never disappears. */
.is-dark :focus-visible,
.site-footer :focus-visible,
.hero :focus-visible,
.cta-band :focus-visible {
  outline-color: #FFFFFF;
  box-shadow: 0 0 0 6px rgba(47, 109, 191, 0.65);
}

main:focus { outline: none; }


/* ==========================================================================
   05. LAYOUT PRIMITIVES
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--w-page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--wide   { max-width: var(--w-wide); }
.container--narrow { max-width: var(--w-narrow); }

/* Full-width horizontal band. Pair with a .container inside. */
.section {
  padding-block: var(--sp-section);
  position: relative;
}
.section--tight { padding-block: var(--sp-section-tight); }
.section--flush-top { padding-top: 0; }
.section--flush-bottom { padding-bottom: 0; }

/* Section grounds */
.section--tint { background: var(--c-bone-deep); }
.section--paper { background: var(--c-paper); }
.section--dark {
  background: var(--c-ink);
  color: var(--c-on-dark);
}

/* .is-dark — put on ANY container to invert text colors for a dark ground.
   .section--dark already implies it. */
.section--dark,
.is-dark { color: var(--c-on-dark); }
.section--dark h1, .section--dark h2, .section--dark h3,
.section--dark h4, .section--dark h5, .section--dark h6,
.is-dark h1, .is-dark h2, .is-dark h3, .is-dark h4, .is-dark h5, .is-dark h6 {
  color: var(--c-bone);
}
.section--dark p, .is-dark p { color: var(--c-on-dark-mute); }
.section--dark a:not([class]), .is-dark a:not([class]) {
  color: var(--c-bone);
  text-decoration-color: rgba(246, 243, 236, 0.45);
}
.section--dark a:not([class]):hover, .is-dark a:not([class]):hover {
  color: #FFFFFF;
  text-decoration-color: currentColor;
}

/* Hairline separators between same-colored sections */
.section--ruled-top { border-top: 1px solid var(--c-line); }
.section--ruled-bottom { border-bottom: 1px solid var(--c-line); }
.section--dark.section--ruled-top { border-top-color: var(--c-ink-line); }

/* Two-column split. Default 1:1; modifiers change the ratio.
   Collapses to a single column at 860px. */
.split {
  display: grid;
  gap: clamp(2rem, 1.2rem + 3.4vw, 4.5rem);
  align-items: start;
}
/* Grid items default to min-width:auto, so one unbreakable token (an email
   address, a long URL) can force its track wider than the container. At 320px
   that pushed content under `overflow-x: clip` and silently sheared its right
   edge off. Letting the items shrink is the fix. */
.split > * { min-width: 0; }
@media (min-width: 861px) {
  .split { grid-template-columns: 1fr 1fr; }
  .split--wide-left  { grid-template-columns: 1.35fr 1fr; }
  .split--wide-right { grid-template-columns: 1fr 1.35fr; }
  .split--sticky-left  > :first-child { position: sticky; top: calc(var(--header-h) + 2rem); }
  .split--center { align-items: center; }
}

/* Vertical stack — sets consistent flow spacing on direct children. */
.stack > * + * { margin-top: var(--sp-sm); }
.stack--sm > * + * { margin-top: var(--sp-2xs); }
.stack--md > * + * { margin-top: var(--sp-md); }
.stack--lg > * + * { margin-top: var(--sp-lg); }
.stack--xl > * + * { margin-top: var(--sp-xl); }

/* Horizontal cluster (buttons, tags) that wraps cleanly. */
.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-sm);
  align-items: center;
}
.cluster--tight { gap: var(--sp-2xs); }
.cluster--center { justify-content: center; }


/* ==========================================================================
   06. SECTION RHYTHM: EYEBROW / HEADING / LEDE / RULE
   ========================================================================== */

/* The eyebrow echoes the letterspaced "CONSTRUCTION GROUP" in the logo. */
.eyebrow {
  display: block;
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--c-moss-deep);
  margin-bottom: var(--sp-xs);
}
.eyebrow--rule {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.eyebrow--rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--c-line-strong);
  max-width: 5rem;
}
.section--dark .eyebrow,
.is-dark .eyebrow { color: var(--c-tan); }
.section--dark .eyebrow--rule::after,
.is-dark .eyebrow--rule::after { background: var(--c-ink-line); }

/* Section header block. Add .section-head--center to center it. */
.section-head {
  max-width: 62ch;
  margin-bottom: clamp(2rem, 1.4rem + 2.2vw, 3.5rem);
}
.section-head--center {
  margin-inline: auto;
  text-align: center;
}
.section-head--center .eyebrow--rule { justify-content: center; }
.section-head--center .eyebrow--rule::before {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--c-line-strong);
  max-width: 5rem;
}
.section-head > * + * { margin-top: var(--sp-sm); }
.section-head .eyebrow + * { margin-top: 0; }

/* Lede — the intro paragraph under a heading. */
.lede {
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
  color: var(--c-text-muted);
  max-width: 60ch;
}
.section-head--center .lede { margin-inline: auto; }
.section--dark .lede, .is-dark .lede { color: var(--c-on-dark-mute); }

/* Short decorative rule — a tan hairline, used sparingly under headings. */
.rule {
  width: 3.5rem;
  height: 2px;
  background: var(--c-tan);
  border: 0;
  margin: var(--sp-md) 0;
}
.rule--center { margin-inline: auto; }
.rule--full { width: 100%; height: 1px; background: var(--c-line); }
.section--dark .rule--full, .is-dark .rule--full { background: var(--c-ink-line); }

/* A serif pull-quote / statement line for verbatim brand copy. */
.statement {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  line-height: 1.3;
  letter-spacing: var(--ls-tight);
  color: var(--c-ink);
  max-width: 30ch;
}
.section--dark .statement, .is-dark .statement { color: var(--c-bone); }


/* ==========================================================================
   07. BUTTONS
   ========================================================================== */

.btn {
  --btn-bg: var(--c-ink);
  --btn-fg: var(--c-bone);
  --btn-bd: var(--c-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6em;
  padding: 0.85rem 1.6rem;
  min-height: 48px;                 /* comfortable touch target */
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  line-height: 1.1;
  text-align: center;
  text-decoration: none;
  color: var(--btn-fg);
  background: var(--btn-bg);
  border: 1px solid var(--btn-bd);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease),
              color var(--t-base) var(--ease),
              transform var(--t-fast) var(--ease),
              box-shadow var(--t-base) var(--ease);
}
.btn:hover {
  --btn-bg: var(--c-moss-deep);
  --btn-bd: var(--c-moss-deep);
  color: var(--c-bone);
  box-shadow: var(--sh-sm);
}
.btn:active { transform: translateY(1px); }
.btn[disabled], .btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

/* Primary is the default .btn. Explicit class available for clarity. */
.btn--primary {
  --btn-bg: var(--c-ink);
  --btn-fg: var(--c-bone);
  --btn-bd: var(--c-ink);
}

/* Secondary — outlined on light grounds. */
.btn--secondary {
  --btn-bg: transparent;
  --btn-fg: var(--c-ink);
  --btn-bd: var(--c-input-border);
}
.btn--secondary:hover {
  --btn-bg: var(--c-ink);
  --btn-bd: var(--c-ink);
  color: var(--c-bone);
}

/* Ghost — for DARK grounds only (hero, CTA band, footer). */
.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--c-bone);
  --btn-bd: rgba(246, 243, 236, 0.42);
}
.btn--ghost:hover {
  --btn-bg: var(--c-bone);
  --btn-fg: var(--c-ink);
  --btn-bd: var(--c-bone);
  color: var(--c-ink);
}

/* Accent — the one moss-filled button. Use at most once per screen. */
.btn--accent {
  --btn-bg: var(--c-moss);
  --btn-fg: #FFFFFF;
  --btn-bd: var(--c-moss);
}
.btn--accent:hover {
  --btn-bg: var(--c-moss-deep);
  --btn-bd: var(--c-moss-deep);
}

.btn--sm { padding: 0.6rem 1.1rem; min-height: 40px; font-size: var(--fs-xs); }
.btn--lg { padding: 1.05rem 2.1rem; min-height: 56px; font-size: var(--fs-base); }
.btn--block { display: flex; width: 100%; }

/* Icon inside a button (inline SVG, currentColor) */
.btn svg { width: 1.05em; height: 1.05em; flex: none; }

/* Text link that behaves like a small CTA with a moving arrow. */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--c-moss-deep);
  border-bottom: 1px solid color-mix(in srgb, var(--c-moss-deep) 35%, transparent);
  padding-bottom: 2px;
}
.link-arrow::after {
  content: "\2192";
  transition: transform var(--t-base) var(--ease);
}
.link-arrow:hover { color: var(--c-ink); border-bottom-color: var(--c-ink); }
.link-arrow:hover::after { transform: translateX(4px); }
.is-dark .link-arrow, .section--dark .link-arrow {
  color: var(--c-tan);
  border-bottom-color: rgba(184, 163, 130, 0.4);
}
.is-dark .link-arrow:hover, .section--dark .link-arrow:hover {
  color: var(--c-bone); border-bottom-color: var(--c-bone);
}


/* ==========================================================================
   08. SITE HEADER + NAV
   --------------------------------------------------------------------------
   REQUIRED MARKUP (see contract):
   <header class="site-header" id="site-header" data-nav-open="false">
     <div class="site-header__inner container">
       <a class="brand" href="index.html">
         <img class="brand__logo" src="assets/img/logo-dark.png" alt="Two Trees Construction Group">
       </a>
       <button class="nav-toggle" id="nav-toggle" type="button"
               aria-expanded="false" aria-controls="primary-nav"
               aria-label="Open menu">
         <span class="nav-toggle__bars" aria-hidden="true"></span>
       </button>
       <nav class="site-nav" id="primary-nav" aria-label="Primary">
         <ul class="site-nav__list"> <li><a class="site-nav__link" ...> ... </ul>
         <div class="site-nav__cta"> ...phone link + button... </div>
       </nav>
     </div>
   </header>

   JS CONTRACT:
   - Open/close: toggle attribute  data-nav-open="true" | "false"
     on  #site-header  (the .site-header element). CSS keys off
     [data-nav-open="true"].
   - Also mirror state on the button:  aria-expanded="true"|"false".
   - Scroll:  add/remove class  .is-scrolled  on  #site-header.
   - Body scroll lock while the panel is open: add class  .has-overlay
     to <body> (shared with the lightbox).
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: var(--c-bone);
  border-bottom: 1px solid transparent;
  transition: background-color var(--t-base) var(--ease),
              box-shadow var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease);
}

/* Scrolled state — subtle: a hairline, a whisper of shadow, slight compression. */
.site-header.is-scrolled {
  background: color-mix(in srgb, var(--c-bone) 92%, transparent);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom-color: var(--c-line);
  box-shadow: var(--sh-header);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-md);
  min-height: var(--header-h);
  transition: min-height var(--t-base) var(--ease);
}
.site-header.is-scrolled .site-header__inner { min-height: calc(var(--header-h) - 8px); }

/* Groups the mobile call button and the hamburger on the right of the header. */
.site-header__controls { display: contents; }
@media (max-width: 900px) {
  .site-header__controls {
    display: flex;
    align-items: center;
    gap: var(--sp-2xs);
    flex: none;
  }
}

/* --- Brand lockup ------------------------------------------------------- */
.brand {
  display: inline-flex;
  align-items: center;
  flex: none;
  text-decoration: none;
  line-height: 0;
  border-radius: var(--r-xs);
  /* The lockup is short; pad the link out to a comfortable 44px target. */
  min-height: 44px;
}
.brand__logo {
  width: auto;
  height: clamp(34px, 26px + 2vw, 46px);   /* logo art is 1.877:1 */
  transition: height var(--t-base) var(--ease);
}
.site-header.is-scrolled .brand__logo { height: clamp(30px, 23px + 1.7vw, 40px); }

/* Footer / dark-ground lockup uses logo-light.png at a larger size. */
.brand--footer .brand__logo { height: clamp(46px, 36px + 3vw, 66px); }

/* Square mark (mark-dark.png / mark-light.png, 512²) */
.brand-mark { width: clamp(48px, 40px + 2vw, 68px); height: auto; }

/* --- Nav ---------------------------------------------------------------- */
.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 0.6rem + 1.8vw, 2.25rem);
}
.site-nav__list {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 0.6rem + 1.8vw, 2.25rem);
  margin: 0;
  padding: 0;
  list-style: none;
}
.site-nav__link {
  position: relative;
  display: inline-block;
  padding: 0.5rem 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--c-text);
  white-space: nowrap;
}
.site-nav__link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--c-moss);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-base) var(--ease);
}
.site-nav__link:hover { color: var(--c-ink); }
.site-nav__link:hover::after { transform: scaleX(1); }

/* Current page — page authors add class .is-current AND aria-current="page" */
.site-nav__link.is-current,
.site-nav__link[aria-current="page"] { color: var(--c-ink); }
.site-nav__link.is-current::after,
.site-nav__link[aria-current="page"]::after {
  transform: scaleX(1);
  background: var(--c-ink);
}

/* Header CTA cluster: phone number + a button. */
.site-nav__cta {
  display: flex;
  align-items: center;
  gap: var(--sp-sm);
}
.site-nav__phone {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-display);
  font-size: var(--fs-md);
  letter-spacing: var(--ls-normal);
  color: var(--c-ink);
  text-decoration: none;
  white-space: nowrap;
}
.site-nav__phone svg { width: 1em; height: 1em; color: var(--c-moss); }
.site-nav__phone:hover { color: var(--c-moss-deep); }

/* Hide the phone text on mid widths where space is tight (kept in panel). */
@media (max-width: 1120px) and (min-width: 901px) {
  .site-nav__phone span { display: none; }
}

/* --- Hamburger button ---------------------------------------------------- */
/* --- Mobile tap-to-call --------------------------------------------------
   Under 900px the header's phone link lives inside the collapsed nav panel, so
   on a phone there was NO tappable number on the first screen — the visitor had
   to open the menu or scroll. For a contractor whose whole funnel is "tap to
   call", that is the most valuable 48px on the site.
   ------------------------------------------------------------------------- */
.header-call {
  display: none;             /* shown under 900px */
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  min-height: 48px;
  padding-inline: 0.85rem;
  flex: none;
  border: 1px solid var(--c-ink);
  border-radius: var(--r-sm);
  background: var(--c-ink);
  color: var(--c-bone);
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
.header-call svg { width: 17px; height: 17px; flex: none; }
.header-call:hover { background: var(--c-moss-deep); border-color: var(--c-moss-deep); }
/* Once the panel is open the number is visible inside it — drop the duplicate. */
.site-header[data-nav-open="true"] .header-call { opacity: 0; pointer-events: none; }

@media (max-width: 900px) { .header-call { display: inline-flex; } }
/* Narrowest handsets only: keep the icon, drop the word, so the brand lockup
   is not squeezed. Most phones are 390-430px and have room for the label. */
@media (max-width: 359px) {
  .header-call { padding-inline: 0; width: 48px; }
  .header-call span {
    position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
}

.nav-toggle {
  display: none;             /* shown under 900px */
  position: relative;
  width: 48px;
  height: 48px;
  flex: none;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border: 1px solid var(--c-line-strong);
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--c-ink);
  transition: background-color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
.nav-toggle:hover { background: var(--c-bone-deep); border-color: var(--c-ink); }

/* Three bars built from one span + its two pseudo elements. */
.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: "";
  display: block;
  width: 22px;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform var(--t-base) var(--ease),
              opacity var(--t-fast) var(--ease),
              width var(--t-base) var(--ease);
}
.nav-toggle__bars { position: relative; }
.nav-toggle__bars::before { position: absolute; top: -7px; left: 0; }
.nav-toggle__bars::after  { position: absolute; top:  7px; left: 0; width: 15px; }

/* Open state → X. Driven by [data-nav-open="true"] on .site-header. */
.site-header[data-nav-open="true"] .nav-toggle__bars { background: transparent; }
.site-header[data-nav-open="true"] .nav-toggle__bars::before {
  top: 0; transform: rotate(45deg);
}
.site-header[data-nav-open="true"] .nav-toggle__bars::after {
  top: 0; width: 22px; transform: rotate(-45deg);
}

/* --- Mobile panel -------------------------------------------------------- */
@media (max-width: 900px) {
  .nav-toggle { display: inline-flex; }

  /* ---------------------------------------------------------------------
     NO JAVASCRIPT: the nav is a plain stacked block under the header. It is
     fully visible and usable, and the hamburger (which would do nothing) is
     hidden. The overlay panel below is opened only by main.js, so gating its
     closed state on `html.js` means a blocked or failed script can never leave
     a phone with no navigation at all.
     --------------------------------------------------------------------- */
  .site-nav {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--sp-sm) var(--gutter) var(--sp-lg);
    background: var(--c-bone);
    border-top: 1px solid var(--c-line);
  }
  html:not(.js) .nav-toggle { display: none; }

  /* ---------------------------------------------------------------------
     WITH JAVASCRIPT: the same markup becomes the slide-in overlay panel.
     --------------------------------------------------------------------- */
  html.js .site-nav {
    position: fixed;
    /* Full-viewport, tucked UNDER the sticky header, which has a higher
       z-index and an opaque background. Anchoring the panel to var(--header-h)
       left a gap once the header shrank by 8px on scroll, so a strip of the
       scrolled page showed through above it. */
    inset: 0;
    z-index: var(--z-navpanel);
    justify-content: flex-start;
    padding: calc(var(--header-h) + var(--sp-lg)) var(--gutter) var(--sp-2xl);
    border-top: 0;
    overflow-y: auto;
    overscroll-behavior: contain;

    /* Closed state. visibility + pointer-events keep it out of the tab order
       and off the screen when closed. */
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--t-base) var(--ease),
                visibility 0s linear var(--t-base);
  }

  html.js .site-header[data-nav-open="true"] .site-nav {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity var(--t-base) var(--ease), visibility 0s;
  }

  .site-nav__list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    width: 100%;
  }
  .site-nav__list li { border-bottom: 1px solid var(--c-line); }
  .site-nav__link {
    display: block;
    padding: var(--sp-sm) 0;
    font-size: var(--fs-lg);
    font-family: var(--font-display);
    font-weight: 400;
    letter-spacing: var(--ls-normal);
    text-transform: none;
  }
  .site-nav__link::after { display: none; }
  .site-nav__link.is-current,
  .site-nav__link[aria-current="page"] { color: var(--c-moss-deep); }

  .site-nav__cta {
    flex-direction: column;
    align-items: stretch;
    gap: var(--sp-sm);
    margin-top: var(--sp-lg);
  }
  .site-nav__phone {
    font-size: var(--fs-xl);
    justify-content: flex-start;
    /* Both controls in the open menu are primary conversion paths on a phone. */
    min-height: 44px;
  }
  .site-nav__phone span { display: inline; }
  .site-nav__cta .btn { width: 100%; min-height: 44px; }
}

/* Body scroll lock — main.js adds .has-overlay to <body> for the nav panel and
   the lightbox. position:fixed rather than plain overflow:hidden, because iOS
   Safari ignores overflow:hidden on <body> and scrolls the page behind the
   overlay anyway. main.js stores the scroll offset in `top` and restores it. */
body.has-overlay {
  position: fixed;
  width: 100%;
  overflow: hidden;
}


/* ==========================================================================
   09. HERO — full-bleed dark section, logo-light on the dark ground
   --------------------------------------------------------------------------
   <section class="hero">
     <div class="hero__inner container">
       <img class="hero__mark" src="assets/img/mark-light.png" alt="">
       <p class="hero__eyebrow">…</p>
       <h1 class="hero__title">…</h1>
       <p class="hero__tagline">Your Vision — Our Creation</p>
       <p class="hero__lede">…</p>
       <div class="hero__actions cluster">…buttons…</div>
       <ul class="hero__meta">…license / area / phone…</ul>
     </div>
   </section>
   ========================================================================== */

.hero {
  position: relative;
  isolation: isolate;
  background: var(--c-ink);
  color: var(--c-on-dark);
  padding-block: clamp(4rem, 2.4rem + 7vw, 9rem);
  overflow: hidden;
}

/* Soft vignette + a faint moss wash so the flat black has depth.
   Purely CSS — no image needed. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(115% 85% at 50% 0%,
      rgba(94, 107, 69, 0.22) 0%, rgba(94, 107, 69, 0) 62%),
    linear-gradient(180deg, #1B1D14 0%, #16170F 55%, #101109 100%);
}
/* Fine horizontal grain lines — very low contrast, adds a printed feel. */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.35;
  background-image: repeating-linear-gradient(
    180deg,
    rgba(246, 243, 236, 0.035) 0px,
    rgba(246, 243, 236, 0.035) 1px,
    transparent 1px,
    transparent 4px
  );
}

.hero__inner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  max-width: 900px;
}
/* Left-aligned variant for interior pages. */
.hero--left .hero__inner { align-items: flex-start; text-align: left; }

.hero__mark {
  width: clamp(72px, 56px + 5vw, 118px);
  height: auto;
  margin-bottom: var(--sp-md);
  opacity: 0.95;
}
/* Full lockup instead of the square mark, when the hero is the front door. */
.hero__logo {
  width: min(420px, 78%);
  height: auto;
  margin-bottom: var(--sp-lg);
}

.hero__eyebrow {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--c-tan);
  margin-bottom: var(--sp-sm);
}

.hero__title {
  font-family: var(--font-display);
  font-size: var(--fs-4xl);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tight);
  color: var(--c-bone);
  max-width: 18ch;
}
.hero--left .hero__title { max-width: 20ch; }
.hero--page .hero__title { font-size: var(--fs-3xl); }

/* Interior page heroes are shorter. */
.hero--page { padding-block: clamp(3rem, 2rem + 4vw, 5.5rem); }

.hero__tagline {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--fs-lg);
  color: var(--c-tan);
  margin-top: var(--sp-sm);
  letter-spacing: 0.01em;
}

.hero__lede {
  margin-top: var(--sp-md);
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
  color: var(--c-on-dark-mute);
  max-width: 56ch;
}

.hero__actions { margin-top: clamp(1.75rem, 1.2rem + 1.8vw, 2.75rem); }
.hero__inner:not(.hero--left .hero__inner) .hero__actions { justify-content: center; }
.hero--left .hero__actions { justify-content: flex-start; }

/* Small credibility strip under the hero actions — license, area, insured.
   Facts only. */
.hero__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-xs) var(--sp-md);
  justify-content: center;
  margin-top: clamp(2rem, 1.4rem + 2vw, 3rem);
  padding-top: var(--sp-md);
  border-top: 1px solid var(--c-ink-line);
  width: 100%;
  list-style: none;
  font-size: var(--fs-xs);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--c-on-dark-mute);
}
.hero--left .hero__meta { justify-content: flex-start; }
.hero__meta li {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
}
.hero__meta li::before {
  content: "";
  width: 5px; height: 5px;
  background: var(--c-tan);
  border-radius: 50%;
  flex: none;
}

/* Breadcrumb-ish page label inside interior heroes. */
.hero__crumb {
  font-size: var(--fs-xs);
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--c-on-dark-mute);
  margin-bottom: var(--sp-xs);
}
.hero__crumb a { color: inherit; text-decoration: none; border-bottom: 1px solid rgba(183,185,168,.4); }
.hero__crumb a:hover { color: var(--c-bone); }


/* --------------------------------------------------------------------------
   COMPACT HERO ON PHONES.
   At full size the home hero stacks logo + eyebrow + headline + tagline +
   paragraph + two buttons + a trust line. On a 320x640 phone that came to
   955px, putting BOTH calls to action ~720px down — a visitor on a small
   handset saw the logo and nothing they could tap. For a contractor whose
   funnel is "tap to call", that was the most expensive bug on the site.
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .hero { padding-block: clamp(2rem, 1rem + 5vw, 3.5rem); }
  .hero__logo { width: min(300px, 66%); margin-bottom: var(--sp-sm); }
  .hero__mark { margin-bottom: var(--sp-sm); }
  .hero__eyebrow { margin-bottom: var(--sp-2xs); }
  .hero__lede { margin-top: var(--sp-sm); }
  .hero__actions { margin-top: var(--sp-md); }
  .hero__meta { margin-top: var(--sp-md); }
}

/* Short screens (landscape, or a small phone like the SE) need a little more
   taken out again so the first button still clears the fold. */
@media (max-width: 640px) and (max-height: 720px) {
  .hero { padding-block: var(--sp-lg); }
  .hero__logo { width: min(250px, 58%); }
  .hero__title { font-size: var(--fs-2xl); }
  .hero__lede { margin-top: var(--sp-xs); }
}


/* ==========================================================================
   10. CARDS & CARD GRID  (services, value props)
   --------------------------------------------------------------------------
   <ul class="grid grid--3">
     <li><article class="card"> … </article></li>
   </ul>
   or <div class="grid grid--3"><a class="card card--link" href="…"> … </a></div>
   ========================================================================== */

.grid {
  display: grid;
  gap: clamp(1.25rem, 0.9rem + 1.4vw, 2rem);
  grid-template-columns: 1fr;
  list-style: none;
  margin: 0;
  padding: 0;
}
@media (min-width: 560px)  { .grid--2, .grid--3, .grid--4 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px)  { .grid--3 { grid-template-columns: repeat(3, 1fr); }
                             .grid--4 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1100px) { .grid--4 { grid-template-columns: repeat(4, 1fr); } }
/* Auto-fit variant for lists of unknown length. */
.grid--auto { grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); }

.card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: clamp(1.5rem, 1.2rem + 1vw, 2.25rem);
  background: var(--c-paper);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  box-shadow: var(--sh-xs);
  transition: box-shadow var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease),
              transform var(--t-base) var(--ease);
}

/* Card-as-link (whole tile clickable). */
a.card, .card--link {
  text-decoration: none;
  color: inherit;
}
a.card:hover, .card--link:hover {
  border-color: var(--c-line-strong);
  box-shadow: var(--sh-md);
  transform: translateY(-3px);
}
a.card:hover .card__title, .card--link:hover .card__title { color: var(--c-moss-deep); }

/* Icon plate — page authors drop an inline <svg> in here (stroke/fill
   currentColor, viewBox 0 0 24 24). */
.card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  flex: none;
  margin-bottom: var(--sp-sm);
  color: var(--c-moss-deep);
  background: var(--c-moss-soft);
  border-radius: var(--r-sm);
}
.card__icon svg { width: 24px; height: 24px; }

.card__title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  line-height: var(--lh-snug);
  color: var(--c-ink);
  transition: color var(--t-base) var(--ease);
}
.card__body {
  margin-top: var(--sp-2xs);
  font-size: var(--fs-base);
  line-height: var(--lh-loose);
  color: var(--c-text-muted);
}
/* Pushes a link/arrow to the bottom of an uneven-height card. */
.card__foot { margin-top: auto; padding-top: var(--sp-md); }

/* Numbered card (process / value props without icons). */
.card__num {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-2xl);
  line-height: 1;
  color: var(--c-tan);
  margin-bottom: var(--sp-xs);
}

/* Flat variant — no surface, just a top hairline. Good on tinted sections. */
.card--flat {
  background: transparent;
  border: 0;
  border-top: 2px solid var(--c-ink);
  border-radius: 0;
  box-shadow: none;
  padding: var(--sp-md) 0 0;
}
.card--flat:hover { transform: none; box-shadow: none; }

/* Card on a dark ground. */
.card--dark {
  background: var(--c-ink-soft);
  border-color: var(--c-ink-line);
  box-shadow: none;
}
.card--dark .card__title { color: var(--c-bone); }
.card--dark .card__body { color: var(--c-on-dark-mute); }
.card--dark .card__icon { background: rgba(246, 243, 236, 0.08); color: var(--c-tan); }
a.card--dark:hover, .card--dark.card--link:hover { border-color: var(--c-tan); }
a.card--dark:hover .card__title { color: var(--c-tan); }


/* ==========================================================================
   11. SERVICE DETAIL BLOCK + CHECK LISTS
   --------------------------------------------------------------------------
   <article class="service" id="kitchens">
     <div class="service__head">
       <span class="service__icon"><svg …></svg></span>
       <div>
         <h2 class="service__title">Kitchens</h2>
         <p class="service__intro">…</p>
       </div>
     </div>
     <ul class="list-check"> <li>…</li> </ul>
     <p class="service__note">…</p>
   </article>
   ========================================================================== */

.service {
  padding-block: clamp(2rem, 1.5rem + 2vw, 3.25rem);
  border-top: 1px solid var(--c-line);
}
.service:first-of-type { border-top: 0; padding-top: 0; }
.service:target { scroll-margin-top: calc(var(--header-h) + 2rem); }

.service__head {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-md);
  margin-bottom: var(--sp-md);
}
.service__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  flex: none;
  color: var(--c-moss-deep);
  background: var(--c-moss-soft);
  border-radius: var(--r-sm);
}
.service__icon svg { width: 28px; height: 28px; }

.service__title {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  color: var(--c-ink);
}
.service__intro {
  margin-top: var(--sp-3xs);
  color: var(--c-text-muted);
  max-width: 62ch;
}
.service__note {
  margin-top: var(--sp-md);
  font-size: var(--fs-sm);
  color: var(--c-text-faint);
  max-width: 62ch;
}

/* Two-column bullet list inside a service block. */
.list-check {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--sp-2xs) var(--sp-lg);
}
@media (min-width: 700px) { .list-check--2col { grid-template-columns: 1fr 1fr; } }

.list-check li {
  position: relative;
  padding-left: 1.6em;
  line-height: var(--lh-normal);
  color: var(--c-text-muted);
}
.list-check li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.52em;
  width: 0.55em;
  height: 0.3em;
  border-left: 2px solid var(--c-moss);
  border-bottom: 2px solid var(--c-moss);
  transform: rotate(-45deg);
}
.is-dark .list-check li, .section--dark .list-check li { color: var(--c-on-dark-mute); }
.is-dark .list-check li::before, .section--dark .list-check li::before {
  border-color: var(--c-tan);
}

/* Plain dash list — for terser lists (what's included / customer supplies). */
.list-dash { list-style: none; margin: 0; padding: 0; }
.list-dash li {
  position: relative;
  padding-left: 1.25em;
  color: var(--c-text-muted);
}
.list-dash li + li { margin-top: var(--sp-3xs); }
.list-dash li::before {
  content: "\2014";
  position: absolute;
  left: 0;
  color: var(--c-tan);
}

/* Small "quick index" of services / anchors. */
.chip-list { display: flex; flex-wrap: wrap; gap: var(--sp-2xs); list-style: none; margin: 0; padding: 0; }
.chip {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.4rem 0.95rem;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--c-text-muted);
  background: var(--c-paper);
  border: 1px solid var(--c-line);
  border-radius: var(--r-pill);
  text-decoration: none;
  transition: all var(--t-fast) var(--ease);
}
a.chip:hover { color: var(--c-bone); background: var(--c-ink); border-color: var(--c-ink); }
.is-dark .chip, .section--dark .chip {
  background: transparent; border-color: var(--c-ink-line); color: var(--c-on-dark-mute);
}
.is-dark a.chip:hover, .section--dark a.chip:hover {
  background: var(--c-bone); color: var(--c-ink); border-color: var(--c-bone);
}


/* ==========================================================================
   12. PROCESS / NUMBERED STEPS  (e.g. estimate → schedule → work → approval)
   --------------------------------------------------------------------------
   <ol class="steps"> <li class="steps__item">
        <h3 class="steps__title">…</h3><p class="steps__body">…</p>
   </li> </ol>
   ========================================================================== */

.steps {
  counter-reset: step;
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1.5rem, 1.1rem + 1.6vw, 2.5rem);
}
@media (min-width: 780px) { .steps { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 780px) { .steps--4 { grid-template-columns: repeat(4, 1fr); } }

.steps__item {
  counter-increment: step;
  padding-top: var(--sp-md);
  border-top: 1px solid var(--c-line);
}
.steps__item::before {
  content: counter(step, decimal-leading-zero);
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  color: var(--c-tan-text);
  margin-bottom: var(--sp-2xs);
  letter-spacing: 0.02em;
}
.steps__title { font-size: var(--fs-md); font-family: var(--font-display); }
.steps__body { margin-top: var(--sp-3xs); color: var(--c-text-muted); font-size: var(--fs-sm); line-height: var(--lh-normal); }
.section--dark .steps__item, .is-dark .steps__item { border-top-color: var(--c-ink-line); }
.section--dark .steps__body, .is-dark .steps__body { color: var(--c-on-dark-mute); }


/* ==========================================================================
   13. CALLOUT / PANEL / CTA BAND
   ========================================================================== */

/* Bordered aside for terms, disclaimers, "what we need from you". */
.callout {
  padding: clamp(1.25rem, 1rem + 1vw, 2rem);
  background: var(--c-moss-soft);
  border-left: 3px solid var(--c-moss);
  border-radius: 0 var(--r-md) var(--r-md) 0;
}
.callout__title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  margin-bottom: var(--sp-2xs);
}
.callout p { color: var(--c-text-muted); }
.callout--plain { background: var(--c-bone-deep); border-left-color: var(--c-tan); }

/* Neutral surface block — used to wrap forms and info groups. */
.panel {
  padding: clamp(1.5rem, 1.15rem + 1.6vw, 2.75rem);
  background: var(--c-paper);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  box-shadow: var(--sh-sm);
}
.panel--dark {
  background: var(--c-ink-soft);
  border-color: var(--c-ink-line);
  color: var(--c-on-dark);
  box-shadow: none;
}

/* Full-width dark CTA band — phone + estimate button. */
.cta-band {
  background: var(--c-ink);
  color: var(--c-on-dark);
  padding-block: clamp(2.75rem, 2rem + 3vw, 4.5rem);
}
.cta-band__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-lg);
}
.cta-band__title {
  font-family: var(--font-display);
  font-size: var(--fs-2xl);
  color: var(--c-bone);
  max-width: 22ch;
}
.cta-band__text { margin-top: var(--sp-2xs); color: var(--c-on-dark-mute); max-width: 46ch; }
.cta-band__actions { display: flex; flex-wrap: wrap; gap: var(--sp-sm); }
@media (max-width: 700px) {
  .cta-band__actions { width: 100%; }
  .cta-band__actions .btn { flex: 1 1 240px; }
}


/* ==========================================================================
   14. SERVICE-AREA TOWN LIST
   --------------------------------------------------------------------------
   <div class="towns">
     <section class="towns__group">
       <h3 class="towns__label">Bergen County</h3>
       <ul class="towns__list"><li>Westwood</li> … </ul>
     </section>
   </div>
   ========================================================================== */

.towns {
  display: grid;
  gap: clamp(1.5rem, 1.1rem + 1.6vw, 2.5rem);
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
}
.towns__group { min-width: 0; }
.towns__label {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--c-moss-deep);
  padding-bottom: var(--sp-2xs);
  margin-bottom: var(--sp-xs);
  border-bottom: 1px solid var(--c-line);
}
.towns__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 0.9rem;
}
.towns__list li {
  font-family: var(--font-display);
  font-size: var(--fs-base);
  line-height: 1.6;
  color: var(--c-text);
  white-space: nowrap;
}
.section--dark .towns__label, .is-dark .towns__label {
  color: var(--c-tan); border-bottom-color: var(--c-ink-line);
}
.section--dark .towns__list li, .is-dark .towns__list li { color: var(--c-bone); }

/* Closing note under the towns grid ("…and surrounding towns"). */
.towns__note {
  margin-top: var(--sp-lg);
  padding-top: var(--sp-md);
  border-top: 1px solid var(--c-line);
  font-size: var(--fs-sm);
  color: var(--c-text-faint);
}
.section--dark .towns__note, .is-dark .towns__note {
  border-top-color: var(--c-ink-line); color: var(--c-on-dark-mute);
}


/* ==========================================================================
   15. FAQ — native <details>/<summary> accordion (works with zero JS)
   --------------------------------------------------------------------------
   <div class="faq">
     <details class="faq__item">
       <summary class="faq__q">Question?</summary>
       <div class="faq__a"><p>Answer.</p></div>
     </details>
   </div>
   Optional JS: close siblings on open. No classes required for that.
   ========================================================================== */

.faq { border-top: 1px solid var(--c-line); }

.faq__item { border-bottom: 1px solid var(--c-line); }

.faq__q {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-md);
  padding: var(--sp-md) 0;
  cursor: pointer;
  list-style: none;
  font-family: var(--font-display);
  font-size: var(--fs-md);
  line-height: var(--lh-snug);
  color: var(--c-ink);
  transition: color var(--t-fast) var(--ease);
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q:hover { color: var(--c-moss-deep); }

/* Plus / minus indicator built from pseudo-elements. */
.faq__q::after {
  content: "";
  flex: none;
  position: relative;
  width: 16px;
  height: 16px;
  margin-top: 0.35em;
  background:
    linear-gradient(currentColor, currentColor) center/100% 2px no-repeat,
    linear-gradient(currentColor, currentColor) center/2px 100% no-repeat;
  transition: transform var(--t-base) var(--ease), opacity var(--t-fast) var(--ease);
  color: var(--c-moss);
}
.faq__item[open] > .faq__q::after {
  transform: rotate(90deg);
  background:
    linear-gradient(currentColor, currentColor) center/100% 2px no-repeat;
}
.faq__item[open] > .faq__q { color: var(--c-moss-deep); }

.faq__a {
  padding-bottom: var(--sp-md);
  max-width: var(--w-prose);
  color: var(--c-text-muted);
  animation: faq-in var(--t-base) var(--ease) both;
}
.faq__a > * + * { margin-top: var(--sp-sm); }

@keyframes faq-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}


/* ==========================================================================
   16. GALLERY GRID + LIGHTBOX
   --------------------------------------------------------------------------
   GRID (each tile is a <button> so it is keyboard-operable):
   <ul class="gallery">
     <li class="gallery__item">
       <button class="gallery__btn" type="button"
               data-lightbox
               data-full="assets/img/gallery/kitchen-01.jpg"
               data-caption="Kitchen remodel — Ridgewood, NJ">
         <img class="gallery__img" src="assets/img/gallery/kitchen-01.jpg"
              alt="Kitchen remodel in Ridgewood, New Jersey" loading="lazy"
              width="1200" height="900">
         <span class="gallery__caption">Kitchen remodel — Ridgewood</span>
       </button>
     </li>
   </ul>

   EMPTY STATE (there are currently no project photos):
   <div class="gallery-empty"> … </div>

   LIGHTBOX (one per page, last element inside <body>):
   <div class="lightbox" id="lightbox" role="dialog" aria-modal="true"
        aria-label="Project photo" hidden>
     <button class="lightbox__close" id="lightbox-close" type="button"
             aria-label="Close">&times;</button>
     <button class="lightbox__nav lightbox__prev" id="lightbox-prev" type="button"
             aria-label="Previous photo"></button>
     <button class="lightbox__nav lightbox__next" id="lightbox-next" type="button"
             aria-label="Next photo"></button>
     <figure class="lightbox__figure">
       <img class="lightbox__img" id="lightbox-img" src="" alt="">
       <figcaption class="lightbox__caption" id="lightbox-caption"></figcaption>
     </figure>
   </div>

   JS CONTRACT: remove [hidden], then add class .is-open to #lightbox
   (a frame later, so the transition runs). Add .has-overlay to <body>.
   ========================================================================== */

.gallery {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(0.75rem, 0.5rem + 1vw, 1.25rem);
  grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr));
}
.gallery__item { min-width: 0; }

.gallery__btn {
  display: block;
  width: 100%;
  padding: 0;
  cursor: zoom-in;
  background: var(--c-bone-deep);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  overflow: hidden;
  text-align: left;
  transition: border-color var(--t-base) var(--ease),
              box-shadow var(--t-base) var(--ease);
}
.gallery__btn:hover { border-color: var(--c-line-strong); box-shadow: var(--sh-md); }

.gallery__img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: var(--c-bone-deep);
  transition: transform var(--t-slow) var(--ease-out), filter var(--t-base) var(--ease);
}
.gallery__btn:hover .gallery__img { transform: scale(1.035); }

.gallery__caption {
  display: block;
  padding: 0.7rem 0.9rem 0.85rem;
  font-size: var(--fs-xs);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--c-text-muted);
  background: var(--c-paper);
  border-top: 1px solid var(--c-line);
}

/* Tall / wide tile modifiers for a more editorial mosaic. */
@media (min-width: 900px) {
  .gallery__item--wide { grid-column: span 2; }
  .gallery__item--wide .gallery__img { aspect-ratio: 16 / 9; }
  .gallery__item--tall .gallery__img { aspect-ratio: 3 / 4; }
}

/* Empty / placeholder state — no invented photos. */
.gallery-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sp-sm);
  padding: clamp(2.5rem, 2rem + 3vw, 4.5rem) var(--gutter);
  background: var(--c-bone-deep);
  border: 1px dashed var(--c-line-strong);
  border-radius: var(--r-md);
}
.gallery-empty__mark { width: 68px; height: auto; opacity: 0.4; }
.gallery-empty__title { font-family: var(--font-display); font-size: var(--fs-lg); }
.gallery-empty p { color: var(--c-text-muted); max-width: 46ch; }

/* --- Lightbox overlay ---------------------------------------------------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--z-lightbox);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 0.6rem + 2vw, 3rem);
  background: rgba(10, 11, 6, 0.94);
  opacity: 0;
  transition: opacity var(--t-base) var(--ease);
}
.lightbox.is-open { opacity: 1; }

.lightbox__figure {
  margin: 0;
  max-width: min(1100px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-sm);
  transform: scale(0.97);
  transition: transform var(--t-base) var(--ease-out);
}
.lightbox.is-open .lightbox__figure { transform: scale(1); }

.lightbox__img {
  max-width: 100%;
  max-height: calc(100vh - 9rem);
  max-height: calc(100dvh - 9rem);
  width: auto;
  object-fit: contain;
  border-radius: var(--r-sm);
  background: var(--c-ink-soft);
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.55);
}
.lightbox__caption {
  font-size: var(--fs-sm);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--c-on-dark-mute);
  text-align: center;
}

.lightbox__close {
  position: absolute;
  top: clamp(0.75rem, 0.4rem + 1.2vw, 1.5rem);
  right: clamp(0.75rem, 0.4rem + 1.2vw, 1.5rem);
  width: 48px;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.75rem;
  line-height: 1;
  color: var(--c-bone);
  background: rgba(246, 243, 236, 0.1);
  border: 1px solid rgba(246, 243, 236, 0.28);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease);
}
.lightbox__close:hover { background: rgba(246, 243, 236, 0.22); }

.lightbox__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 48px;
  height: 64px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--c-bone);
  background: rgba(246, 243, 236, 0.1);
  border: 1px solid rgba(246, 243, 236, 0.28);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease);
}
.lightbox__nav:hover { background: rgba(246, 243, 236, 0.22); }
.lightbox__prev { left: clamp(0.5rem, 0.2rem + 1vw, 1.5rem); }
.lightbox__next { right: clamp(0.5rem, 0.2rem + 1vw, 1.5rem); }
/* Arrow glyphs drawn with a rotated border — no icon font needed. */
.lightbox__nav::before {
  content: "";
  width: 12px; height: 12px;
  border-top: 2px solid currentColor;
  border-right: 2px solid currentColor;
}
.lightbox__prev::before { transform: rotate(-135deg); margin-left: 4px; }
.lightbox__next::before { transform: rotate(45deg); margin-right: 4px; }
.lightbox__nav[disabled] { opacity: 0.3; cursor: default; }

@media (max-width: 560px) {
  .lightbox__nav { top: auto; bottom: clamp(0.5rem, 0.3rem + 1vw, 1rem); transform: none; height: 48px; }
  .lightbox__img {
    max-height: calc(100vh - 12rem);
    max-height: calc(100dvh - 12rem);
  }
}


/* ==========================================================================
   17. FORMS
   --------------------------------------------------------------------------
   <form class="form" id="contact-form" novalidate>
     <div class="form__row form__row--2">
       <div class="field">
         <label class="field__label" for="name">Name <span class="field__req" aria-hidden="true">*</span></label>
         <input class="field__input" id="name" name="name" type="text" required
                autocomplete="name" aria-describedby="name-error">
         <p class="field__error" id="name-error">Please enter your name.</p>
       </div>
     </div>
     <div class="field">
       <label class="field__label" for="service">Service</label>
       <div class="field__select"><select class="field__input" id="service" name="service">…</select></div>
     </div>
     <div class="field">
       <label class="field__label" for="message">Project details</label>
       <textarea class="field__input" id="message" name="message" rows="6"></textarea>
       <p class="field__hint">…</p>
     </div>
     <div class="field field--hp" aria-hidden="true">   <!-- honeypot -->
       <label for="company">Company</label><input id="company" name="company" tabindex="-1" autocomplete="off">
     </div>
     <button class="btn btn--primary btn--lg" type="submit">Request an estimate</button>
     <p class="form__status" id="form-status" role="status" hidden></p>
   </form>

   JS CONTRACT:
   - Invalid field: add class .is-error to the wrapping .field  (the
     .field__error inside becomes visible automatically). Also set
     aria-invalid="true" on the input.
   - Clear by removing .is-error / aria-invalid.
   - Success: remove [hidden] from #form-status and add .is-success.
     Failure: add .is-error instead.
   ========================================================================== */

.form { max-width: 46rem; }
.form > * + * { margin-top: var(--sp-md); }

.form__row { display: grid; gap: var(--sp-md); }
@media (min-width: 640px) {
  .form__row--2 { grid-template-columns: 1fr 1fr; }
  .form__row--3 { grid-template-columns: repeat(3, 1fr); }
}

.field { display: flex; flex-direction: column; min-width: 0; }

.field__label {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--c-text-muted);
  margin-bottom: var(--sp-3xs);
}
.field__req { color: var(--c-moss-deep); }

.field__input {
  width: 100%;
  padding: 0.8rem 0.95rem;
  min-height: 48px;
  font-family: var(--font-body);
  font-size: var(--fs-base);
  line-height: 1.4;
  color: var(--c-text);
  background: var(--c-paper);
  border: 1px solid var(--c-input-border);
  border-radius: var(--r-sm);
  transition: border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease),
              background-color var(--t-fast) var(--ease);
  appearance: none;
  -webkit-appearance: none;
}
textarea.field__input { min-height: 9rem; line-height: var(--lh-normal); }

.field__input::placeholder { color: var(--c-text-faint); opacity: 1; }

.field__input:hover { border-color: var(--c-text-faint); }
.field__input:focus-visible {
  outline: none;
  border-color: var(--c-moss);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-moss) 26%, transparent);
}
/* Keep a visible ring for browsers without :focus-visible on inputs. */
.field__input:focus { border-color: var(--c-moss); }

.field__input[disabled], .field__input[readonly] {
  background: var(--c-bone-deep);
  color: var(--c-text-faint);
  cursor: not-allowed;
}

/* Select needs a custom chevron since appearance is stripped. */
.field__select { position: relative; }
.field__select select.field__input { padding-right: 2.75rem; cursor: pointer; }
.field__select::after {
  content: "";
  position: absolute;
  right: 1.1rem;
  top: 50%;
  width: 9px; height: 9px;
  margin-top: -6px;
  border-right: 2px solid var(--c-text-muted);
  border-bottom: 2px solid var(--c-text-muted);
  transform: rotate(45deg);
  pointer-events: none;
}

/* Checkbox / radio rows */
/* Touch targets: the box is 24x24 (WCAG 2.5.8) and the whole row is at least
   44px tall. Every label is tied to its input with for/id, so the real tap
   area is the full width of the row, not just the box. */
.field--check {
  flex-direction: row;
  align-items: center;
  gap: 0.65rem;
  min-height: 44px;
  padding-block: var(--sp-3xs);
}
.field--check input[type="checkbox"],
.field--check input[type="radio"] {
  width: 24px; height: 24px;
  flex: none;
  accent-color: var(--c-moss);
  cursor: pointer;
}
.field--check label {
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  line-height: var(--lh-normal);
  cursor: pointer;
  flex: 1;
  padding-block: var(--sp-3xs);
}

/* Honeypot — visually and assistively removed but still submitted. */
.field--hp {
  position: absolute !important;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

.field__hint {
  margin-top: var(--sp-3xs);
  font-size: var(--fs-xs);
  color: var(--c-text-faint);
  line-height: var(--lh-normal);
}

/* Error message — hidden until .is-error is on the .field wrapper. */
.field__error {
  display: none;
  margin-top: var(--sp-3xs);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--c-error);
  line-height: var(--lh-normal);
}
.field.is-error .field__error { display: block; }
.field.is-error .field__label { color: var(--c-error); }
.field.is-error .field__input,
.field__input.is-error,
.field__input[aria-invalid="true"] {
  border-color: var(--c-error);
  background: var(--c-error-soft);
}
.field.is-error .field__input:focus-visible,
.field__input[aria-invalid="true"]:focus-visible {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-error) 24%, transparent);
}

/* Form-level status message (submit result). */
.form__status {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: var(--sp-sm) var(--sp-md);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  border: 1px solid var(--c-line);
  border-radius: var(--r-sm);
  background: var(--c-bone-deep);
  color: var(--c-text-muted);
}
.form__status::before {
  content: "";
  flex: none;
  width: 1.1em; height: 1.1em;
  margin-top: 0.15em;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.35;
}
.form__status.is-success {
  background: var(--c-success-soft);
  border-color: color-mix(in srgb, var(--c-success) 35%, transparent);
  color: var(--c-success);
  font-weight: 600;
}
.form__status.is-success::before {
  opacity: 1;
  background: none;
  border-radius: 0;
  width: 0.75em; height: 0.42em;
  margin-top: 0.35em;
  border-left: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
}
.form__status.is-error {
  background: var(--c-error-soft);
  border-color: color-mix(in srgb, var(--c-error) 35%, transparent);
  color: var(--c-error);
  font-weight: 600;
}
.form__status.is-error::before { opacity: 1; }

/* Legal / privacy microcopy under the submit button. */
.form__fine {
  font-size: var(--fs-xs);
  color: var(--c-text-faint);
  line-height: var(--lh-normal);
  max-width: 52ch;
}

fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
legend {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  color: var(--c-ink);
  margin-bottom: var(--sp-2xs);
  padding: 0;
}


/* ==========================================================================
   18. CONTACT / INFO BLOCKS
   --------------------------------------------------------------------------
   <ul class="info-list">
     <li class="info-list__item">
       <span class="info-list__label">Phone</span>
       <a class="info-list__value" href="tel:+12012979703">201-297-9703</a>
     </li>
   </ul>
   ========================================================================== */

.info-list { list-style: none; margin: 0; padding: 0; }
.info-list__item { padding-block: var(--sp-sm); border-bottom: 1px solid var(--c-line); }
.info-list__item:first-child { padding-top: 0; }
.info-list__label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--c-text-faint);
  margin-bottom: var(--sp-3xs);
}
.info-list__value {
  display: inline-block;
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  line-height: var(--lh-snug);
  color: var(--c-ink);
  text-decoration: none;
  word-break: break-word;
}
a.info-list__value:hover { color: var(--c-moss-deep); text-decoration: underline; text-underline-offset: 0.2em; }
/* Phone and email here are primary conversion paths — only the links get the
   enlarged touch target; the plain-text values stay as they are. */
a.info-list__value {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.info-list__note { font-size: var(--fs-sm); color: var(--c-text-faint); margin-top: var(--sp-3xs); }

.section--dark .info-list__item, .is-dark .info-list__item { border-bottom-color: var(--c-ink-line); }
.section--dark .info-list__label, .is-dark .info-list__label { color: var(--c-tan); }
.section--dark .info-list__value, .is-dark .info-list__value { color: var(--c-bone); }
.section--dark a.info-list__value:hover, .is-dark a.info-list__value:hover { color: var(--c-tan); }
.section--dark .info-list__note, .is-dark .info-list__note { color: var(--c-on-dark-mute); }


/* ==========================================================================
   19. SITE FOOTER
   --------------------------------------------------------------------------
   NJ Home Improvement Contractor license #13VH12426800 MUST appear here on
   EVERY page — .footer__license is the designated slot.
   ========================================================================== */

.site-footer {
  background: var(--c-ink);
  color: var(--c-on-dark-mute);
  padding-top: clamp(3rem, 2.2rem + 3vw, 4.5rem);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
}

.site-footer__top {
  display: grid;
  gap: clamp(2rem, 1.4rem + 2.4vw, 3.5rem);
  grid-template-columns: 1fr;
  padding-bottom: clamp(2rem, 1.6rem + 2vw, 3rem);
}
@media (min-width: 700px)  { .site-footer__top { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1000px) { .site-footer__top { grid-template-columns: 1.5fr 1fr 1fr; } }

.footer__brand-copy {
  margin-top: var(--sp-md);
  max-width: 42ch;
  color: var(--c-on-dark-mute);
}
.footer__tagline {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--fs-md);
  color: var(--c-tan);
  margin-top: var(--sp-2xs);
}

.footer__heading {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--c-bone);
  margin-bottom: var(--sp-sm);
}

.footer__nav { list-style: none; margin: 0; padding: 0; }
.footer__nav li + li { margin-top: var(--sp-2xs); }
.footer__nav a {
  color: var(--c-on-dark-mute);
  /* Underlined by default: on a touch device there is no hover, so without
     this the footer links are indistinguishable from the text around them. */
  text-decoration: underline;
  text-decoration-color: rgba(184, 163, 130, 0.5);
  text-underline-offset: 0.25em;
  border-bottom: 1px solid transparent;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.footer__nav a:hover { color: var(--c-bone); border-bottom-color: var(--c-tan); }

.footer__contact { list-style: none; margin: 0; padding: 0; }
.footer__contact li + li { margin-top: var(--sp-2xs); }
.footer__contact a {
  color: var(--c-bone);
  text-decoration: none;
  border-bottom: 1px solid rgba(184, 163, 130, 0.45);
}
.footer__contact a:hover { color: var(--c-tan); border-bottom-color: var(--c-tan); }
/* The footer phone and email are the last conversion point on every page, and
   the one a visitor reaches after scrolling. Give them a real touch target. */
.footer__contact a,
.footer__nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.footer__contact .footer__place { color: var(--c-on-dark-mute); }

/* Bottom bar: license line + copyright. */
.site-footer__bottom {
  border-top: 1px solid var(--c-ink-line);
  padding-block: var(--sp-md) var(--sp-lg);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2xs) var(--sp-md);
  align-items: baseline;
  justify-content: space-between;
  font-size: var(--fs-xs);
  color: var(--c-on-dark-mute);
}

/* The required NJ HIC line. Keep it legible — do not shrink further. */
.footer__license {
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--c-bone);
  font-weight: 600;
}
.footer__license strong { color: var(--c-tan); font-weight: 700; letter-spacing: 0.08em; }

.footer__copyright { color: var(--c-on-dark-mute); }

/* Small credential row (licensed / insured / bonded — all stated in brief). */
.footer__creds {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2xs) var(--sp-md);
  list-style: none;
  margin: var(--sp-md) 0 0;
  padding: 0;
  font-size: var(--fs-xs);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--c-on-dark-mute);
}
.footer__creds li { display: inline-flex; align-items: center; gap: 0.5em; }
.footer__creds li::before {
  content: "";
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--c-tan);
  flex: none;
}


/* ==========================================================================
   20. REVEAL-ON-SCROLL  (JS-gated so it degrades to fully visible)
   --------------------------------------------------------------------------
   HOW IT DEGRADES: the hidden state is scoped to  html.js . The JS sets
       document.documentElement.classList.add('js')
   as its FIRST action. If JS never runs, .js is never added, so
   [data-reveal] elements are simply visible with no transform. Correct
   by default.

   JS then adds  .is-visible  to each [data-reveal] element when it enters
   the viewport (IntersectionObserver).

   Optional attribute:  data-reveal="up" | "fade" | "left" | "right"
   Optional stagger:    style="--reveal-delay: 90ms"  (or 2/3/4 via
                        [data-reveal-order]).
   ========================================================================== */

html.js [data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity var(--t-reveal) var(--ease-out) var(--reveal-delay, 0ms),
    transform var(--t-reveal) var(--ease-out) var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
html.js [data-reveal="fade"]  { transform: none; }
html.js [data-reveal="left"]  { transform: translateX(-22px); }
html.js [data-reveal="right"] { transform: translateX(22px); }

html.js [data-reveal].is-visible {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Convenience stagger hooks — no inline style needed. */
html.js [data-reveal-order="1"] { --reveal-delay:  70ms; }
html.js [data-reveal-order="2"] { --reveal-delay: 140ms; }
html.js [data-reveal-order="3"] { --reveal-delay: 210ms; }
html.js [data-reveal-order="4"] { --reveal-delay: 280ms; }
html.js [data-reveal-order="5"] { --reveal-delay: 350ms; }
html.js [data-reveal-order="6"] { --reveal-delay: 420ms; }


/* Long unbreakable strings — email addresses, URLs — must be able to break
   rather than widen their container on a narrow phone. */
.btn,
.btn > span,
a[href^="mailto:"] { overflow-wrap: anywhere; }


/* ==========================================================================
   21. SMALL UTILITIES  (kept deliberately short — only what pages need)
   ========================================================================== */

.text-center { text-align: center; }
.text-muted  { color: var(--c-text-muted); }
.text-serif  { font-family: var(--font-display); }
.measure     { max-width: var(--w-prose); }
.center      { margin-inline: auto; }
.mt-0  { margin-top: 0; }
.mt-md { margin-top: var(--sp-md); }
.mt-lg { margin-top: var(--sp-lg); }
.mt-xl { margin-top: var(--sp-xl); }
.nowrap { white-space: nowrap; }
.full-width { width: 100%; }

/* Any element that must scroll horizontally rather than break the page. */
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }


/* ==========================================================================
   22. REDUCED MOTION
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  /* Reveal elements must never be left hidden or offset. */
  html.js [data-reveal],
  html.js [data-reveal].is-visible {
    opacity: 1 !important;
    transform: none !important;
  }

  /* Kill the incidental movement, keep the state changes. */
  .btn:active,
  a.card:hover, .card--link:hover { transform: none; }
  .gallery__btn:hover .gallery__img { transform: none; }
  .link-arrow:hover::after { transform: none; }
  .lightbox__figure, .lightbox.is-open .lightbox__figure { transform: none; }

  /* The mobile nav panel still needs to appear/disappear instantly. */
  .site-nav { transition: none; transform: none; }
  .site-header[data-nav-open="true"] .site-nav { transform: none; }
}


/* ==========================================================================
   23. PRINT
   ========================================================================== */

@media print {
  :root {
    --c-text: #000;
    --c-text-muted: #222;
    --c-ink: #000;
  }

  html, body {
    background: #fff !important;
    color: #000 !important;
    font-size: 11pt;
    line-height: 1.4;
  }

  .site-header,
  .nav-toggle,
  .site-nav,
  .cta-band,
  .lightbox,
  .skip-link,
  .hero__actions,
  .gallery,
  .form__status,
  .btn { display: none !important; }

  /* Keep the hero text, drop its dark ground. */
  .hero, .section--dark, .panel--dark, .site-footer {
    background: #fff !important;
    color: #000 !important;
    padding-block: 1rem !important;
  }
  .hero::before, .hero::after { display: none !important; }
  .hero__title, .hero__tagline, .hero__lede, .hero__meta,
  .section--dark h1, .section--dark h2, .section--dark h3, .section--dark p,
  .site-footer, .site-footer a, .footer__license, .footer__license strong,
  .towns__list li, .info-list__value {
    color: #000 !important;
  }
  .hero__mark, .hero__logo, .brand--footer .brand__logo { filter: invert(1); }

  .section { padding-block: 1.25rem !important; }
  .card, .panel { border: 1px solid #999 !important; box-shadow: none !important; break-inside: avoid; }

  /* Expand every FAQ answer on paper. */
  .faq__item > .faq__a { display: block !important; }
  .faq__q::after { display: none; }

  /* Print the destination of real links. */
  a[href^="http"]::after,
  a[href^="tel:"]::after,
  a[href^="mailto:"]::after {
    content: " (" attr(href) ")";
    font-size: 9pt;
    color: #444;
    word-break: break-all;
  }

  h1, h2, h3, h4 { break-after: avoid; }
  p, li { orphans: 3; widows: 3; }

  /* Never hide content in print, even if JS never ran. */
  html.js [data-reveal] { opacity: 1 !important; transform: none !important; }
}
