/* 10-4 Handyman Services
   Tokens from DESIGN.md. Do not introduce colors outside this block. */

:root {
  /* brand */
  --navy-900: #001A35;
  --navy-800: #002850;   /* base */
  --navy-700: #003A70;
  --navy-600: #00508F;
  --navy-100: #E6EDF5;

  --orange-700: #AD5600; /* text-safe orange: 5.11:1 on white, 4.77:1 on --surface-soft.
                            #B85C00 passed on white but only hit 4.29:1 on soft grey. */
  --orange-600: #E07200;
  --orange-500: #FF8200; /* base — Tennessee orange */
  --orange-100: #FFE8D1;

  /* surfaces */
  --surface:        #FFFFFF;
  --surface-soft:   #F7F7F7;
  --surface-strong: #F2F2F2;
  --surface-tint:   #EEF3F8;   /* pale navy wash for alternating sections — orange-700 4.58:1, text-muted 4.85:1 */
  --hairline:       #DDDDDD;
  --hairline-soft:  #EBEBEB;
  --text-muted:     #6A6A6A;

  /* type */
  --font-display: 'Archivo', system-ui, -apple-system, sans-serif;
  --font-body: 'Public Sans', system-ui, -apple-system, sans-serif;

  /* spacing — 4px base */
  --xxs: 2px;  --xs: 4px;   --sm: 8px;   --md: 12px;
  --base: 16px; --lg: 24px; --xl: 32px;  --xxl: 48px; --section: 64px;

  /* radius — inputs stay square-ish; cards 16; buttons and badges are pills */
  --r-sm: 6px; --r-md: 12px; --r-lg: 16px; --r-pill: 999px;

  /* the navy band behind the homepage hero and every inner page head */
  --band-bg: radial-gradient(120% 90% at 100% 100%, var(--navy-700) 0%, transparent 60%),
             linear-gradient(160deg, var(--navy-900) 0%, var(--navy-800) 55%, var(--navy-800) 100%);

  --shadow: rgba(0,0,0,0.02) 0 0 0 1px,
            rgba(0,0,0,0.04) 0 2px 6px,
            rgba(0,0,0,0.10) 0 4px 8px;

  --header-h: 76px;
}

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

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
  /* The scroll indicator is exempt. It is driven by the user's own scrolling,
     not autonomous motion, and the blanket rule above would break a
     scroll-driven timeline by forcing a real duration onto it. */
  .scroll-progress { animation-duration: auto !important; }
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--navy-800);
  font-family: var(--font-body);
  font-size: 18px;              /* 18px base — older audience */
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

/* height:auto is required — without it the HTML height attribute wins
   and every aspect-ratio below is ignored. */
img { max-width: 100%; height: auto; display: block; }

/* focus — visible on everything */
:focus-visible {
  outline: 3px solid var(--orange-500);
  outline-offset: 2px;
  border-radius: 2px;
}

.skip {
  position: absolute; left: -9999px;
  background: var(--navy-800); color: #fff;
  padding: var(--md) var(--lg); z-index: 200;
  text-decoration: none; font-weight: 600;
}
.skip:focus { left: var(--base); top: var(--base); }

/* visually hidden, still read by screen readers */
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.wrap { width: 100%; max-width: 1160px; margin: 0 auto; padding: 0 var(--lg); }

/* ---------- type ---------- */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  margin: 0;
  text-wrap: balance;
  letter-spacing: -0.015em;
}
h1 { font-size: clamp(34px, 5.4vw, 48px); font-weight: 700; line-height: 1.08; letter-spacing: -0.02em; }
h2 { font-size: clamp(30px, 4.2vw, 42px); font-weight: 600; line-height: 1.12; letter-spacing: -0.02em; }
h3 { font-size: 24px; font-weight: 600; line-height: 1.25; }
p { margin: 0; }

/* 14px is the floor everywhere — DESIGN.md §7, older audience */
.eyebrow {
  font-family: var(--font-display);
  font-size: 14px; font-weight: 700;
  letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--orange-700);
}
.lede { font-size: 20px; color: #3F4E5F; max-width: 62ch; }
.muted { color: var(--text-muted); }

/* ---------- buttons — orange takes NAVY text (white fails AA) ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sm);
  min-height: 48px; padding: 12px 24px;
  font-family: var(--font-display); font-size: 17px; font-weight: 600;
  border-radius: var(--r-pill); border: 2px solid transparent;
  text-decoration: none; cursor: pointer;
  transition: background-color .16s ease-out, border-color .16s ease-out;
}
.btn-primary { background: var(--orange-500); color: var(--navy-800); }
.btn-primary:hover { background: var(--orange-600); }
.btn-secondary { background: var(--navy-800); color: #fff; }
.btn-secondary:hover { background: var(--navy-700); }
.btn-ghost { background: transparent; color: var(--navy-800); border-color: var(--hairline); }
.btn-ghost:hover { border-color: var(--navy-800); background: var(--surface-soft); }
.btn-lg { min-height: 56px; font-size: 18px; padding: 14px 30px; }

/* ---------- header ---------- */
.header {
  position: sticky; top: 0; z-index: 100;
  background: var(--surface);
  border-bottom: 1px solid var(--hairline);
}
.header-inner {
  display: flex; align-items: center; gap: var(--lg);
  min-height: var(--header-h);
}

/* Scroll progress — sits on the header's bottom hairline and fills as you
   read. Orientation aid, not decoration: it answers "how much is left".
   CSS-only, so there is no scroll listener running on every frame.
   Starts at scaleX(0), so browsers without scroll-driven animation support
   simply show nothing rather than a permanently full bar. */
.scroll-progress {
  position: absolute; left: 0; bottom: -1px;
  width: 100%; height: 3px;
  background: var(--orange-500);
  transform: scaleX(0); transform-origin: 0 50%;
  pointer-events: none;
}
@supports (animation-timeline: scroll()) {
  .scroll-progress {
    animation: scroll-progress linear both;
    animation-timeline: scroll(root block);
  }
}
@keyframes scroll-progress { to { transform: scaleX(1); } }
.brand {
  display: flex; align-items: center; gap: 10px; min-height: 48px;
  text-decoration: none; color: var(--navy-800);
  font-family: var(--font-display); font-weight: 800;
  font-size: 20px; letter-spacing: -0.02em; white-space: nowrap;
}
.brand svg { width: 34px; height: 34px; flex: none; }

.nav { display: flex; gap: var(--xs); margin-left: auto; }
.nav a {
  display: flex; align-items: center;
  min-height: 44px; padding: 0 14px;
  color: var(--navy-800); text-decoration: none;
  font-weight: 500; font-size: 17px;
  border-radius: var(--r-sm);
  border-bottom: 3px solid transparent;
}
.nav a:hover { background: var(--surface-soft); }
.nav a[aria-current="page"] { border-bottom-color: var(--orange-500); font-weight: 600; }
.nav a { white-space: nowrap; }
/* needs .nav a prefix to outrank `.nav a { display:flex }` above */
.nav a.nav-quote { display: none; }   /* the orange button covers this on desktop */

.header-cta { display: flex; align-items: center; gap: var(--base); }
/* phone is a primary CTA, not a detail */
.tel {
  display: flex; align-items: center; gap: var(--sm);
  font-family: var(--font-display); font-weight: 700; font-size: 20px;
  color: var(--navy-800); text-decoration: none; white-space: nowrap;
  min-height: 48px; padding: 0 var(--sm); border-radius: var(--r-sm);
}
.tel:hover { color: var(--orange-700); }
.tel svg { width: 20px; height: 20px; flex: none; }

.menu-btn {
  display: none; align-items: center; gap: var(--sm);
  min-height: 48px; padding: 0 var(--base);
  background: var(--surface); border: 2px solid var(--navy-800);
  border-radius: var(--r-pill); color: var(--navy-800);
  font-family: var(--font-display); font-weight: 600; font-size: 16px;
  cursor: pointer;
}

/* ---------- hero ----------
   Full-width navy gradient with the quote card floating in it. The photo
   library is portrait phone shots, so the gradient carries the mood and a
   single captioned tile keeps one real job in view. Text sits on the darker
   left/top of the gradient: orange eyebrow is 5.95:1 on navy-800 and 4.59:1
   on navy-700, so it must not drift toward the bottom-right. */
.hero {
  padding: var(--xxl) 0 var(--xxl);
  color: #fff;
  background: var(--navy-800);
  background-image: var(--band-bg);
}
.hero-grid {
  display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, .7fr);
  gap: var(--xxl); align-items: end;
}
.hero .eyebrow { color: var(--orange-500); }
.hero h1 { margin-top: var(--md); color: #fff; max-width: 16ch; font-size: clamp(34px, 5.4vw, 52px); }
.hero .lede { margin-top: var(--lg); color: #C9D6E4; max-width: 50ch; }

/* Quote starter. One field, one button — the full form lives on quote.html
   and this hands the description over in the query string. */
.hero-card {
  margin-top: 28px;
  background: var(--surface); color: var(--navy-800);
  border-radius: var(--r-lg); padding: var(--md);
  box-shadow: 0 12px 40px rgba(0, 10, 25, .35);
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--md);
  align-items: center;
}
.hero-field {
  display: flex; align-items: center; gap: var(--md);
  min-height: 56px; padding: 0 var(--base);
  background: var(--surface-strong); border-radius: var(--r-md);
  border: 1px solid transparent;
}
.hero-field:focus-within { border-color: var(--navy-800); background: var(--surface); box-shadow: 0 0 0 3px var(--orange-500); }
.hero-field svg { width: 22px; height: 22px; flex: none; color: var(--navy-600); }
/* override the global input rule — the wrapper carries the fill and focus */
.hero-field input[type="text"] {
  align-self: stretch; min-height: 54px; padding: 0; border: 0; background: transparent;
  font-size: 17px; box-shadow: none;
}
.hero-field input:focus { box-shadow: none; border: 0; background: transparent; }
.hero-field input::placeholder { color: #5F6B78; opacity: 1; }   /* 5.44:1 white, 4.86:1 on the fill */
.hero-card .btn { white-space: nowrap; }

.hero-alt { margin-top: var(--base); font-size: 16px; color: #C9D6E4; max-width: 52ch; }
.hero-alt a {
  color: #fff; font-family: var(--font-display); font-weight: 700;
  padding: 12px 0;   /* inline, so this only enlarges the tap target */
  white-space: nowrap;   /* never split the number across lines */
  text-decoration-color: rgba(255,255,255,.4); text-underline-offset: 4px;
}
.hero-alt a:hover { color: var(--orange-500); }

/* Stat strip. Only verified figures go here — the Google rating was checked
   against the live listing the day it was added. No made-up job counts. */
.hero-stats {
  display: flex; flex-wrap: wrap; gap: var(--base) var(--xl);
  margin: 28px 0 0; padding-top: var(--lg);
  border-top: 1px solid rgba(255,255,255,.18);
}
.hero-stats > div { display: grid; gap: 2px; }
.hero-stats dt {
  font-family: var(--font-display); font-weight: 700; font-size: 30px;
  line-height: 1.1; letter-spacing: -0.02em; color: #fff;
  display: flex; align-items: center; gap: 6px;
}
.hero-stats dt svg { width: 22px; height: 22px; color: var(--orange-500); }
.hero-stats dd { margin: 0; font-size: 15px; color: #B9C7D6; }

/* One captioned job photo, like a polaroid pinned to the corner. */
.hero-tile { position: relative; margin: 0; }
.hero-tile img {
  width: 100%; aspect-ratio: 4 / 5; object-fit: cover; object-position: center 45%;
  border-radius: var(--r-lg);
  background: var(--navy-700);
}
.hero-tile figcaption {
  position: absolute; left: var(--md); right: var(--md); bottom: var(--md);
  background: rgba(255,255,255,.96); color: var(--navy-800);
  border-radius: var(--r-md); padding: var(--md) var(--base);
  font-size: 15px; line-height: 1.4;
}
.hero-tile b {
  display: block; font-family: var(--font-display); font-weight: 700;
  font-size: 14px; letter-spacing: .09em; text-transform: uppercase; color: var(--orange-700);
  margin-bottom: 2px;
}

/* Kept for inner pages that still use the split hero-media layout. */
.hero-media { position: relative; }
.hero-media img {
  width: 100%; aspect-ratio: 4 / 5; object-fit: cover;
  object-position: center 34%;
  border-radius: var(--r-md);
  background: var(--surface-strong);
}
.hero-tag {
  position: absolute; left: var(--base); bottom: var(--base); right: var(--base);
  background: rgba(255,255,255,0.96);
  border-radius: var(--r-sm); padding: var(--md) var(--base);
  font-size: 15px; line-height: 1.4;
}
.hero-tag b { font-family: var(--font-display); display: block; font-size: 16px; }

/* ---------- sections ---------- */
.section { padding: var(--section) 0; }
.section-alt { background: var(--surface-tint); }
.section-head { max-width: 62ch; }
.section-head h2 { margin-top: var(--sm); }
.section-head p { margin-top: var(--md); }

/* ---------- services ---------- */
/* 8 cards — explicit column counts so a row is never left half-empty.
   auto-fit gave 3 columns here, leaving a dead slot in the last row. */
.services {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: var(--base); margin-top: var(--xl);
}
/* 6-card variant (About). Never set this inline — inline styles beat the
   media queries below and the grid stays 3-up on a phone. */
.services.cols-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 1000px) { .services, .services.cols-3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px)  { .services, .services.cols-3 { grid-template-columns: 1fr; } }
.service {
  background: var(--surface); border: 0;
  border-radius: var(--r-lg); padding: 28px var(--lg);
}
.service h3 { font-size: 19px; margin-bottom: var(--sm); }
.service p { font-size: 16px; color: var(--text-muted); }
.service .ico {
  width: 40px; height: 40px; margin-bottom: var(--md);
  color: var(--orange-700);
}
.service .ico svg { width: 100%; height: 100%; }

.services-more {
  margin-top: var(--lg); display: flex; flex-wrap: wrap;
  align-items: center; gap: var(--md);
  font-size: 17px;
}

/* ---------- before / after ---------- */
.ba-grid {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: var(--base); margin-top: var(--xl);
}
.ba figure { margin: 0; }
.ba img {
  width: 100%; aspect-ratio: 4 / 5; object-fit: cover;
  border-radius: var(--r-md);
}
.ba figcaption {
  margin-top: var(--md);
  font-family: var(--font-display); font-weight: 700;
  font-size: 15px; letter-spacing: 0.09em; text-transform: uppercase;
}
.ba .before figcaption { color: var(--text-muted); }
.ba .after figcaption { color: var(--orange-700); }
.ba-note {
  margin-top: var(--lg); padding-top: var(--lg);
  border-top: 1px solid var(--hairline);
  display: flex; flex-wrap: wrap; gap: var(--sm) var(--lg);
  align-items: baseline;
}
.ba-note b { font-family: var(--font-display); font-size: 19px; }

/* ---------- before/after wipe slider ----------
   The control is a real <input type="range">, not custom drag code: that
   gives keyboard arrows, touch and screen-reader support for free, which
   matters more here than a bespoke interaction would.
   Without JS the --pos default still renders a valid 50/50 split. */
.wipe {
  --pos: 0%;
  position: relative;
  border-radius: var(--r-md); overflow: hidden;
  background: var(--surface-strong);
  touch-action: pan-y;   /* let the page still scroll vertically over it */
}
.wipe-shot {
  display: block; width: 100%; aspect-ratio: 4 / 5;
  object-fit: cover; object-position: center 45%;
}
/* The finished shot is the base layer. The "before" sits on top and is
   peeled away from the left as --pos grows, so the page lands on the
   unrepaired state and the swipe reveals the result. */
.wipe-shot.is-cover {
  position: absolute; inset: 0; height: 100%;
  clip-path: inset(0 0 0 var(--pos));
}
.wipe-range {
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; opacity: 0; cursor: ew-resize; -webkit-appearance: none; appearance: none;
  background: transparent;
}
.wipe-range::-webkit-slider-thumb { -webkit-appearance: none; width: 64px; height: 100vh; }
.wipe-range::-moz-range-thumb { width: 64px; height: 100vh; border: 0; }

.wipe-line {
  position: absolute; top: 0; bottom: 0; left: var(--pos);
  width: 4px; margin-left: -2px; background: #fff;
  box-shadow: 0 0 0 1px rgba(0,0,0,.25);
  pointer-events: none;
}
.wipe-grip {
  position: absolute; top: 50%; left: 50%;
  width: 52px; height: 52px; margin: -26px 0 0 -26px;
  border-radius: 50%; background: var(--orange-500);
  border: 3px solid #fff; box-shadow: 0 2px 10px rgba(0,0,0,.35);
  display: grid; place-items: center; color: var(--navy-800);
}
.wipe-grip svg { width: 26px; height: 26px; }
.wipe:focus-within .wipe-grip { outline: 3px solid var(--navy-800); outline-offset: 3px; }

/* Each label lives in a full-size layer clipped exactly like the image it
   belongs to, so a tag is only ever visible over its own photo. At the
   extremes the label for the hidden side clips away entirely, rather than
   sitting on top of the wrong picture. */
.wipe-side { position: absolute; inset: 0; pointer-events: none; }
.wipe-side.for-after  { clip-path: inset(0 calc(100% - var(--pos)) 0 0); }
.wipe-side.for-before { clip-path: inset(0 0 0 var(--pos)); }

.wipe-tag {
  position: absolute; top: var(--base);
  font-family: var(--font-display); font-weight: 700;
  font-size: 14px; letter-spacing: .09em; text-transform: uppercase;
  background: rgba(255,255,255,.94); color: var(--navy-800);
  padding: 6px 12px; border-radius: var(--r-sm); pointer-events: none;
  white-space: nowrap;
}
.for-after  .wipe-tag { left: var(--base); }    /* finished shot sits left  */
.for-before .wipe-tag { right: var(--base); }   /* untouched shot sits right */

.wipe-hint {
  margin-top: var(--md); font-size: 16px; color: var(--text-muted);
  display: flex; align-items: center; gap: var(--sm);
}
.wipe-hint svg { width: 18px; height: 18px; flex: none; color: var(--orange-700); }

/* Prompt sitting on the image itself, so the affordance is where the
   interaction is. Fades out once the handle has been moved. */
.wipe-prompt {
  position: absolute; left: 50%; bottom: var(--base);
  transform: translateX(-50%);
  display: flex; align-items: center; gap: var(--sm);
  background: rgba(255,255,255,.95); color: var(--navy-800);
  font-family: var(--font-display); font-weight: 600; font-size: 16px;
  padding: 10px 16px; border-radius: var(--r-sm);
  box-shadow: 0 2px 10px rgba(0,0,0,.28);
  pointer-events: none; white-space: nowrap;
}
.wipe-prompt svg { width: 20px; height: 20px; color: var(--orange-700); }

@media (max-width: 620px) {
  .wipe-shot { aspect-ratio: 3 / 4; }
  .wipe-grip { width: 46px; height: 46px; margin: -23px 0 0 -23px; }
}

/* ---------- work gallery ---------- */
/* 6 jobs — 3+3 or 2+2+2, never a stranded card */
.work {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--base); margin-top: var(--xl);
}
@media (max-width: 1000px) { .work { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .work { grid-template-columns: 1fr; } }
.job {
  background: var(--surface); border: 0;
  border-radius: var(--r-lg); overflow: hidden;
  display: flex; flex-direction: column;
  transition: box-shadow .18s ease-out, transform .18s ease-out;
}
.job:hover { box-shadow: var(--shadow); transform: translateY(-2px); }
.job img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.job-body { padding: var(--base) var(--lg) var(--lg); }
.job h3 { font-size: 19px; }
.job p { font-size: 16px; color: var(--text-muted); margin-top: var(--xs); }
/* navy on orange-100 = 12.5:1. orange-700 on it was 3.88:1 and failed AA. */
.tag {
  display: inline-block; margin-bottom: var(--sm);
  background: var(--orange-100); color: var(--navy-800);
  font-family: var(--font-display); font-weight: 700;
  font-size: 14px; letter-spacing: 0.07em; text-transform: uppercase;
  padding: 4px 12px; border-radius: var(--r-pill);
}

/* ---------- how we work ---------- */
.how-grid {
  display: grid; grid-template-columns: 0.9fr 1.1fr;
  gap: var(--xxl); align-items: center; margin-top: var(--xl);
}
.how-grid img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--r-md); }
.steps { list-style: none; margin: var(--lg) 0 0; padding: 0; }
.steps li {
  display: grid; grid-template-columns: 40px 1fr; gap: var(--base);
  padding: var(--base) 0; border-top: 1px solid var(--hairline);
}
.steps li:first-child { border-top: none; padding-top: 0; }
.steps .n {
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--navy-800); color: #fff;
  display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 700; font-size: 16px;
}
.steps b { font-family: var(--font-display); font-size: 18px; display: block; }
.steps p { font-size: 16px; color: var(--text-muted); margin-top: var(--xxs); }

/* ---------- CTA band ---------- */
.cta {
  background: var(--navy-800); color: #fff; padding: var(--section) 0;
  position: relative; overflow: hidden;
}
/* Falling tools. A repeating SVG tile scrolled by one tile height, so the
   loop is seamless with no JS and no per-element animation. Kept very faint:
   this is texture behind the copy, not a thing to look at. */
.cta::before {
  content: ""; position: absolute; inset: 0;
  background: url("../assets/tools-tile.svg") repeat;
  background-size: 320px 320px;
  opacity: .085;
  animation: tools-fall 38s linear infinite;
  pointer-events: none;
}
@keyframes tools-fall { to { background-position: 0 320px; } }
/* keep the copy and the mascot above the texture */
.cta > .wrap { position: relative; z-index: 1; }
/* two columns once there is room for the mascot; the wrap stays single-column
   on narrow screens so the CTA button never gets pushed down the page */
.cta-grid {
  display: grid; grid-template-columns: 1fr auto;
  gap: var(--xxl); align-items: end;
}
.cta-mascot {
  width: 300px; align-self: end; margin-bottom: calc(var(--section) * -1);
  /* composited on --navy-800 already, so no transparency needed */
  transform-origin: 50% 100%;
  animation: mascot-idle 3.6s ease-in-out infinite;
}
/* Breathing idle. It only ever travels UP from rest, and scales from the
   bottom edge, because the image is a navy rectangle: moving down would slide
   that block over the darker footer and become visible. Up and inward stays
   navy-on-navy and reads as just the character moving. */
@keyframes mascot-idle {
  0%, 100% { transform: translateY(0)    scale(1,     1); }
  50%      { transform: translateY(-5px) scale(1.006, 0.994); }
}
.cta h2 { color: #fff; }
.cta p { color: #C9D6E4; margin-top: var(--md); max-width: 56ch; font-size: 19px; }
.cta-actions { display: flex; flex-wrap: wrap; gap: var(--md); margin-top: var(--xl); }
.cta .btn-ghost { color: #fff; border-color: rgba(255,255,255,.45); }
.cta .btn-ghost:hover { background: rgba(255,255,255,.1); border-color: #fff; }
.cta-tel {
  display: inline-flex; align-items: center; gap: var(--sm);
  color: #fff; text-decoration: none;
  font-family: var(--font-display); font-weight: 700; font-size: 26px;
  min-height: 48px;
}
.cta-tel:hover { color: var(--orange-500); }

/* ---------- footer ---------- */
.footer { background: var(--navy-900); color: #B9C7D6; padding: var(--xxl) 0 var(--lg); font-size: 16px; }
.footer a { color: #fff; }
.footer-grid {
  display: grid; grid-template-columns: 1.3fr 0.8fr 1fr 1.1fr;
  gap: var(--xl); padding-bottom: var(--xl);
  border-bottom: 1px solid rgba(255,255,255,.14);
}

/* Service area. A hand-drawn map rather than a Google embed: no third-party
   script, and no pin on the owner's home address, which is what their Google
   listing points at. The town names stay as real text below it so they remain
   readable, selectable and indexable. */
.area-map {
  display: block; width: 100%; max-width: 220px;
  margin: 0 0 var(--md);
}
.area-towns {
  margin: 0; font-size: 15px; line-height: 1.7; color: #B9C7D6;
}
.area-note { margin-top: var(--md); font-size: 15px; color: #93A5B8; }
.area-note a { color: #fff; }
.footer h4 {
  font-size: 14px; letter-spacing: 0.09em; text-transform: uppercase;
  color: #fff; margin-bottom: var(--md);
}
.footer ul { list-style: none; margin: 0; padding: 0; }
.footer li { margin-bottom: var(--sm); }
.footer li a { display: inline-flex; min-height: 44px; align-items: center; }
.footer-brand { display: flex; align-items: center; gap: 10px; color: #fff;
  font-family: var(--font-display); font-weight: 800; font-size: 20px; }
.footer-brand svg { width: 34px; height: 34px; }
.footer-bottom {
  padding-top: var(--lg); display: flex; flex-wrap: wrap;
  gap: var(--sm) var(--lg); justify-content: space-between; font-size: 15px;
}

/* Studio credit. Deliberately quiet — it sits in the client's footer, so it
   introduces no new colour and never outweighs their own brand. */
.credit {
  display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px 8px;
  min-height: 44px;   /* a link standing on its own needs a real target */
  color: #B9C7D6; text-decoration: none;
}
/* "Site by" earns its three words: without a verb the studio name reads as a
   partner or a supplier rather than the people who built the thing. */
.credit .credit-by { font-size: 14px; color: #93A5B8; }
.credit .credit-name {
  font-family: var(--font-display); font-weight: 700;
  font-size: 14px; letter-spacing: .16em; text-transform: uppercase;
  color: #FFFFFF;
  /* Every other footer link is underlined, and on a phone there is no hover to
     fall back on, so without this nobody knows the credit is clickable. Faint
     rule on the name only: readable as a link, still quieter than the client's
     own links right above it. */
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, .38);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}
a.credit:hover .credit-name { color: var(--orange-500); text-decoration-color: var(--orange-500); }

@media (max-width: 620px) {
  .footer-bottom { gap: var(--md); }
}

/* ---------- page header (inner pages) ----------
   The homepage hero's band, shorter. Every page opens the same way: white
   header, navy band, white content. */
.page-head {
  padding: var(--xxl) 0;
  color: #fff;
  background: var(--navy-800);
  background-image: var(--band-bg);
}
.page-head .eyebrow { color: var(--orange-500); }
.page-head h1 { margin-top: var(--sm); color: #fff; max-width: 18ch; }
.page-head .lede { margin-top: var(--base); color: #C9D6E4; max-width: 56ch; }
.page-head a { color: #fff; text-decoration-color: rgba(255,255,255,.4); text-underline-offset: 4px; }
.page-head a:hover { color: var(--orange-500); }

/* ---------- forms ---------- */
.form-layout {
  display: grid; grid-template-columns: 1.25fr 0.75fr;
  gap: var(--xxl); align-items: start;
}
.form-card {
  background: var(--surface); border: 0;
  border-radius: var(--r-lg); padding: var(--xl);
}
.field { margin-bottom: var(--lg); }
.field > label,
.fieldset-label {
  display: block; margin-bottom: var(--sm);
  font-family: var(--font-display); font-weight: 600; font-size: 17px;
  color: var(--navy-800);
}
/* Hints sit OUTSIDE the <label>, deliberately. Netlify names each field in the
   notification email after its label text, so instructional copy left inside
   the label ends up in every lead the owner reads. Tied to the input with
   aria-describedby instead, which is better for screen readers anyway. */
.field .hint { display: block; font-family: var(--font-body); font-weight: 400;
  font-size: 15px; color: var(--text-muted); margin: -2px 0 8px; }
/* Required marker drawn with generated content, not markup. Netlify names each
   field in the notification email after the label's text content, and CSS
   content is not part of that, so the owner reads "Phone number:" rather than
   "Phone number *:". The input's required attribute is what actually conveys
   this to assistive tech; the asterisk is purely visual. */
.field label.is-required::after {
  content: " *"; color: var(--orange-700); font-weight: 700;
}
.req { color: var(--orange-700); font-weight: 700; }

input[type="text"], input[type="tel"], input[type="email"],
select, textarea {
  width: 100%; min-height: 52px; padding: 12px var(--base);
  font-family: var(--font-body); font-size: 17px; color: var(--navy-800);
  background: var(--surface-strong);
  border: 1px solid var(--hairline); border-radius: var(--r-sm);
}
textarea { min-height: 150px; resize: vertical; line-height: 1.6; }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--navy-800);
  box-shadow: 0 0 0 3px var(--orange-500);
  background: var(--surface);
}
input[type="file"] {
  width: 100%; padding: var(--base);
  background: var(--surface-strong);
  border: 2px dashed var(--hairline); border-radius: var(--r-sm);
  font-size: 16px;
}
input[type="file"]:focus { outline: 3px solid var(--orange-500); outline-offset: 2px; }

fieldset { border: 0; margin: 0 0 var(--lg); padding: 0; }
.checks { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sm); }
.check {
  display: flex; align-items: center; gap: var(--md);
  min-height: 48px; padding: 0 var(--base);
  border: 1px solid transparent; border-radius: var(--r-md);
  background: var(--surface-strong); cursor: pointer; font-size: 16px;
}
.check:hover { border-color: var(--navy-600); }
.check input { width: 22px; height: 22px; accent-color: var(--navy-800); flex: none; margin: 0; }
.check:has(input:checked) { border-color: var(--navy-800); background: var(--navy-100); }

.form-actions { margin-top: var(--xl); padding-top: var(--lg); border-top: 1px solid var(--hairline); }
.form-actions .btn { width: 100%; }
.form-note { margin-top: var(--md); font-size: 15px; color: var(--text-muted); }
.hp { position: absolute; left: -9999px; }

/* quote sidebar */
.aside-card {
  background: var(--navy-800); color: #fff;
  border-radius: var(--r-lg); padding: var(--xl);
}
.aside-card h3 { color: #fff; }
.aside-card p { color: #C9D6E4; margin-top: var(--sm); font-size: 16px; }
.aside-tel {
  display: flex; align-items: center; gap: var(--sm);
  margin-top: var(--base); min-height: 48px;
  color: #fff; text-decoration: none;
  font-family: var(--font-display); font-weight: 700; font-size: 26px;
}
.aside-tel:hover { color: var(--orange-500); }
.aside-list { list-style: none; margin: var(--lg) 0 0; padding: 0; }
.aside-list li {
  display: flex; gap: var(--md); padding: var(--md) 0;
  border-top: 1px solid rgba(255,255,255,.16); font-size: 16px; color: #DCE5EE;
}
.aside-list li:first-child { border-top: 0; }
.aside-list svg { width: 20px; height: 20px; flex: none; color: var(--orange-500); margin-top: 3px; }

/* ---------- service detail cards ---------- */
/* 8 cards, two-up. Flat tint on the white page, same language as the
   homepage service grid. */
.svc-detail { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--base); }
.svc-row {
  padding: 28px var(--lg);
  background: var(--surface-tint); border-radius: var(--r-lg);
}
.svc-row h3 { font-size: 22px; margin-bottom: var(--sm); }
.svc-row p { font-size: 17px; }
.svc-row ul { margin: var(--md) 0 0; padding-left: var(--lg); color: var(--text-muted); font-size: 16px; }
.svc-row li { margin-bottom: var(--xs); }
@media (max-width: 760px) { .svc-detail { grid-template-columns: 1fr; } }

/* ---------- job detail (our work) ---------- */
.job-detail {
  padding: var(--xl) var(--lg); margin-top: var(--base);
  background: var(--surface-tint); border-radius: var(--r-lg);
}
.job-detail:first-of-type { margin-top: var(--xxl); }
.job-detail:last-of-type { margin-bottom: var(--xxl); }
.job-shots { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--base); margin-top: var(--lg); }
.job-shots.two { grid-template-columns: repeat(2, 1fr); }
.job-shots figure { margin: 0; }
.job-shots img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; border-radius: var(--r-md); }
.job-shots figcaption {
  margin-top: var(--sm); font-family: var(--font-display);
  font-weight: 700; font-size: 15px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-muted);
}
.job-shots .is-after figcaption { color: var(--orange-700); }

/* ---------- about ---------- */
.about-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--xxl); align-items: center; }
.about-grid img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--r-md); }
.area-list {
  display: flex; flex-wrap: wrap; gap: var(--sm); margin-top: var(--lg); padding: 0; list-style: none;
}
.area-list li {
  background: var(--surface-tint); border: 0;
  border-radius: var(--r-md); font-size: 16px;
  display: flex; align-items: stretch;
}
/* plain text (service area) vs links (404 nav) — both need a 44px target */
.area-list li { padding: 0; }
.area-list li > a,
.area-list li:not(:has(a)) {
  display: flex; align-items: center;
  min-height: 44px; padding: 0 var(--base);
}
.area-list li > a { text-decoration: none; color: var(--navy-800); font-weight: 500; }
.area-list li > a:hover { color: var(--orange-700); }

/* A link sitting alone in its own paragraph is a destination, not part of a
   sentence, so the WCAG inline exception does not cover it. Give it a real
   target instead of a 20px line of text. */
.link-back {
  display: inline-flex; align-items: center; min-height: 48px;
  color: var(--orange-700); font-weight: 600;
}

/* ---------- responsive ---------- */
@media (max-width: 1040px) {
  .footer-grid { grid-template-columns: 1.2fr 1fr; }
}

@media (max-width: 980px) {
  .hero-grid, .how-grid, .form-layout, .about-grid { grid-template-columns: 1fr; gap: var(--xl); }
  .svc-row { grid-template-columns: 1fr; gap: var(--sm); }
  .job-shots { grid-template-columns: repeat(2, 1fr); }
  .hero-media { order: -1; }
  .hero-media img { aspect-ratio: 4 / 3; }
  /* keep the phone hero short: copy, card, stats. the tile returns on wide screens */
  .hero-tile { display: none; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 1040px) {
  .nav {
    display: none; position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; gap: 0;
    background: var(--surface); border-bottom: 1px solid var(--hairline);
    padding: var(--sm) var(--lg) var(--base);
    box-shadow: var(--shadow);
  }
  .nav.open { display: flex; }
  .nav a { min-height: 52px; border-bottom: 1px solid var(--hairline-soft); border-radius: 0; }
  .nav a[aria-current="page"] { border-bottom-color: var(--orange-500); }
  .menu-btn { display: inline-flex; margin-left: auto; }
  .header-cta .btn { display: none; }   /* phone stays; quote button lives in the menu */
  .header-inner { position: relative; gap: var(--md); }
  .nav a.nav-quote {
    display: flex;
    color: var(--orange-700); font-weight: 700;
  }
}

@media (max-width: 620px) {
  body { font-size: 17px; }
  :root { --section: 48px; }
  .brand span { display: none; }        /* mark only — keeps the phone visible */
  .brand { min-width: 48px; }     /* label is hidden above, so the mark alone must still be a target */
  .tel { font-size: 18px; }
  /* source photos are portrait; a landscape crop here reads as a thin strip */
  .hero-media img { aspect-ratio: 1 / 1; }
  .ba-grid { grid-template-columns: 1fr; }
  .hero-actions .btn { width: 100%; }
  .hero { padding-top: var(--lg); }
  .hero .lede { font-size: 18px; }
  .hero-card { grid-template-columns: 1fr; }
  .hero-card .btn { width: 100%; }
  .hero-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--md); }
  .hero-stats dt { font-size: 24px; }
  .hero-stats dd { font-size: 14px; line-height: 1.35; }
  .checks { grid-template-columns: 1fr; }
  .form-card { padding: var(--lg); }
  .job-detail { padding: var(--lg) var(--base); }
  .svc-row { padding: var(--lg) var(--base); }
  .job-shots, .job-shots.two { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr; gap: var(--lg); }
}

/* Below ~880px the copy column gets too narrow to sit beside a 300px figure.
   Drop the mascot rather than squeeze the CTA — the estimate button and the
   phone number are what this band exists for. */
@media (max-width: 880px) {
  .cta-grid { grid-template-columns: 1fr; }
  .cta-mascot { display: none; }
}

/* small phones (320-400px): the phone number must stay visible, so shrink
   everything around it rather than dropping it. */
@media (max-width: 400px) {
  .wrap { padding: 0 var(--base); }
  .header-inner { gap: var(--sm); }
  .tel { font-size: 16px; gap: 6px; padding: 0 4px; }
  .tel svg { width: 18px; height: 18px; }
  .menu-btn { padding: 0 var(--md); gap: 6px; font-size: 15px; }
  .brand svg { width: 30px; height: 30px; }
}
