/* ============================================================================
   Meredith Marine Construction — spec landing page
   ----------------------------------------------------------------------------
   ONE stylesheet, ONE font file, no framework, no build step. That is the point:
   this build is priced low, so it has to be cheap to maintain by hand. Anyone
   who can read CSS can re-skin it from the token block below.

   Colour is NOT invented. It is sampled from Meredith's OWN logo artwork (their
   Facebook profile picture, 1152px): navy #1E3C66, red #D82418, yellow #F6C000
   — the yellow is the excavator in their mark, and it earns its place below.

   The accent is declared TWICE, and their own palette is why. Their red carries
   text fine on the linen but only reaches 3.0:1 on the navy, which is enough
   for a button block and not enough for a word. Their YELLOW reaches 8.96:1 on
   the same navy. So the accent is their red on the light ground and their
   yellow on the dark one, and both are colours they already use.

   Measured, all against the grounds actually used here:
     #B81C10 red   5.91:1 on linen, 5.36:1 on the band   (their hue, deepened)
     #D82418 red   white on it 5.02:1                    (their exact fill red)
     #F6C000 yellow 8.96:1 on the navy                   (their exact yellow)
     #122740 navy  white 15.1:1                          (their hue, deepened)
   No rule downstream hard-codes a colour, so swapping these tokens re-skins the
   whole page for the next marine contractor.
   ========================================================================== */

@font-face {
  font-family: 'Hanken Grotesk';
  src: url('../assets/fonts/hanken-grotesk-latin-wght-normal.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* grounds */
  --ground:      #F6F3EE;   /* warm linen — the page */
  --ground-2:    #EDE8E0;   /* one step down, for banded sections */
  --ink:         #122740;   /* their navy, deepened — body text AND the dark ground */
  --ink-2:       #1E3C66;   /* their navy EXACTLY — lifted panels on the dark ground */
  --body:        #3C4B57;   /* body copy on the light ground — 8.1:1 */
  --muted:       #586573;   /* captions, meta — 5.4:1, small text still passes */
  --line:        rgba(11, 31, 46, 0.14);
  --line-soft:   rgba(11, 31, 46, 0.07);

  /* accent — their own inks. See the header note. */
  --accent:         #B81C10;   /* text on the LIGHT ground: 5.91:1 on #F6F3EE */
  --accent-on-dark: #F6C000;   /* text on the NAVY  ground: 8.96:1 on #122740 */
  --accent-fill:    #D82418;   /* their exact red, for fills: white on it 5.02:1 */
  --accent-soft:    rgba(216, 36, 24, 0.10);

  /* type scale — clamped, so there are no breakpoint-specific font sizes */
  --h1:   clamp(2.35rem, 1.30rem + 4.4vw, 5.1rem);
  --h2:   clamp(1.85rem, 1.28rem + 2.3vw, 3.1rem);
  --h3:   clamp(1.15rem, 1.02rem + 0.5vw, 1.4rem);
  --lead: clamp(1.05rem, 0.98rem + 0.4vw, 1.28rem);

  --wrap:      1200px;
  --wrap-text: 760px;
  --gut:       clamp(20px, 5vw, 56px);
  --header-h:  74px;

  --radius: 3px;   /* almost square. Marine work is not soft. */
  --shadow: 0 18px 40px -22px rgba(18, 39, 64, 0.45);
}

/* Dark sections re-declare the tokens, so the same components invert without
   a single `.dark &` override anywhere below.

   THE VALUES BELOW ARE LITERAL ON PURPOSE. Writing `--ground: var(--ink)` here
   does NOT reach the navy defined on :root — a var() resolves against the
   element's OWN computed value of that property, and this block redefines
   --ink two lines later. It silently produced #F2F6F8 text on an #F2F6F8
   ground: a 1.0:1 ratio, and the section read as blank rather than as broken.
   Never reference a token that the same block reassigns. */
.on-dark,
.site-footer {
  --ground:    #122740;   /* their navy, deepened */
  --ground-2:  #1E3C66;   /* their navy exactly */
  --ink:       #FFFFFF;   /* 15.1:1 */
  --body:      #C3D0E0;   /*  9.7:1 */
  --muted:     #93A5BC;   /*  6.0:1 */
  --line:      rgba(255, 255, 255, 0.18);
  --line-soft: rgba(255, 255, 255, 0.09);
  --accent:    #F6C000;   /*  9.0:1 — their yellow. Their red only manages 3.0 here. */
  --accent-soft: rgba(246, 192, 0, 0.14);
}

/* ---------------------------------------------------------------- reset --- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--ground);
  color: var(--body);
  font-family: 'Hanken Grotesk', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 17px;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, video { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
button { font: inherit; }

h1, h2, h3, h4 {
  color: var(--ink);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -0.028em;
  margin: 0 0 0.5em;
  text-wrap: balance;
}
h1 { font-size: var(--h1); font-weight: 800; }
h2 { font-size: var(--h2); }
h3 { font-size: var(--h3); line-height: 1.25; letter-spacing: -0.015em; }
p  { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 200;
  background: var(--ink); color: #fff; padding: 10px 16px; border-radius: var(--radius);
  transition: top .2s;
}
.skip-link:focus { top: 12px; }

:where(a, button, summary, input, textarea, select):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

/* --------------------------------------------------------------- layout --- */
.wrap { width: min(var(--wrap), 100%); margin-inline: auto; padding-inline: var(--gut); }

.section {
  background: var(--ground);
  color: var(--body);
  padding-block: clamp(64px, 9vw, 118px);
  position: relative;
}
.section--band { background: var(--ground-2); }
.section--tight { padding-block: clamp(44px, 6vw, 76px); }

.eyebrow {
  display: flex; align-items: center; gap: 12px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 18px;
}
.eyebrow::before {
  content: ""; width: 28px; height: 2px; background: currentColor; flex: none;
}

/* On the navy ground the eyebrow WORDS go near-white and only the rule stays red:
   at 12px the lifted red clears 4.5:1 by 0.04, which is not a margin worth shipping. */
.on-dark .eyebrow { color: var(--ink); }
.on-dark .eyebrow::before { background: var(--accent-on-dark); }

.section__head { max-width: var(--wrap-text); margin-bottom: clamp(36px, 5vw, 60px); }
.section__head p { font-size: var(--lead); }
.lead { font-size: var(--lead); color: var(--body); }

/* --------------------------------------------------------------- header --- */
.site-header {
  position: fixed; inset: 0 0 auto; z-index: 100;
  height: var(--header-h);
  display: flex; align-items: center;
  transition: background-color .3s ease, box-shadow .3s ease, border-color .3s ease;
  border-bottom: 1px solid transparent;
}
.site-header__bar {
  display: flex; align-items: center; gap: 20px; width: 100%;
}
.site-header__brand {
  display: flex; align-items: center; gap: 11px;
  text-decoration: none; color: #fff; margin-right: auto;
  transition: color .3s ease;
}
/* ------------------------------------------------------------------ logo --
   Their OWN artwork, from their Facebook profile picture — the only copy on the
   public web. Facebook's square avatar crop cuts the excavator's bucket off the
   left and the CONSTRUCTION bar off the right, so it reads "CONS". Shipping it
   cropped is Ben's call and it is the right one: their real mark beats a redraw.

   The artwork is flat ink on solid white with the excavator stacked ABOVE the
   wordmark, roughly 1.27:1. Two consequences:
     - It needs a white plaque. Keyed transparent, its navy would vanish into a
       dark waterfront photograph in the header.
     - At any sane header height the word MEREDITH lands under ~10px, so the
       company name sits beside it as ordinary text. That text is not a redrawn
       wordmark; it is the site's own face, doing the legibility the shrunken
       artwork cannot. It also gives the header something a screen reader and a
       crawler can read. */
.site-header__logo {
  display: flex; align-items: center; justify-content: center;
  flex: none;
  background: #fff;
  border-radius: var(--radius);
  padding: 5px 8px;
  box-shadow: 0 1px 0 rgba(18,39,64,.10);
}
.site-header__logo img { height: 46px; width: auto; display: block; }

.brand-name {
  display: grid; line-height: 1.12;
}
.brand-name b {
  font-size: 16px; font-weight: 800; letter-spacing: -0.018em;
  color: var(--brand-ink); white-space: nowrap;
}
.brand-name span {
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.20em;
  text-transform: uppercase; color: var(--brand-sub);
}

.site-header            { --brand-ink: #ffffff; --brand-sub: rgba(255,255,255,.76); }
.site-header.is-stuck   { --brand-ink: var(--ink); --brand-sub: var(--muted); }
.site-footer            { --brand-ink: #ffffff; --brand-sub: rgba(255,255,255,.72); }

.foot-brand .site-header__logo { padding: 7px 11px; }
.foot-brand .site-header__logo img { height: 58px; }
.foot-brand .foot-lockup { display: flex; align-items: center; gap: 13px; margin-bottom: 18px; }
.foot-brand .brand-name b { font-size: 18px; }

.nav { display: flex; align-items: center; gap: 28px; }
/* :not(.btn) is load-bearing. The call button lives inside the nav, and
   `.site-header.is-stuck .nav a` (0,2,1) outranks `.btn--primary` (0,1,0), so
   without this the button quietly took navy text on its red fill — 3.01:1 —
   and dropped from 700 to 500 weight. It only misbehaved after scrolling,
   which is most of the page. */
.nav a:not(.btn) {
  color: #fff; text-decoration: none; font-size: 15px; font-weight: 500;
  opacity: .88; transition: opacity .2s, color .3s ease;
}
.nav a:not(.btn):hover { opacity: 1; }

/* Scrolled: the bar solidifies and every ink token flips to the dark-on-light set. */
.site-header.is-stuck {
  background: var(--ground);
  border-bottom-color: var(--line-soft);
  box-shadow: 0 10px 30px -24px rgba(18, 39, 64, .6);
}
.site-header.is-stuck .site-header__brand,
.site-header.is-stuck .nav a:not(.btn) { color: var(--ink); }

.nav-toggle {
  display: none; width: 42px; height: 42px; padding: 0;
  background: none; border: 1px solid rgba(255,255,255,.34); border-radius: var(--radius);
  color: #fff; cursor: pointer;
}
.site-header.is-stuck .nav-toggle { color: var(--ink); border-color: var(--line); }
.nav-toggle svg { margin: auto; }

/* --------------------------------------------------------------- buttons -- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 15px 26px;
  font-size: 15px; font-weight: 700; letter-spacing: 0.015em;
  text-decoration: none; border: 1px solid transparent; border-radius: var(--radius);
  cursor: pointer; white-space: nowrap;
  transition: background-color .2s, border-color .2s, color .2s, transform .2s;
}
.btn:hover { transform: translateY(-1px); }
.btn--primary { background: var(--accent-fill); color: #fff; }
.btn--primary:hover { background: #AE1A0F; }
/* On navy the fill stays the DEEP red — white on it measures 6.95:1, where the
   lifted red would only reach 4.35:1. */
.on-dark .btn--primary { background: var(--accent-fill); color: #fff; }
.on-dark .btn--primary:hover { background: #AE1A0F; }
.btn--ghost { border-color: currentColor; color: var(--ink); background: transparent; }
.btn--ghost:hover { background: var(--ink); color: var(--ground); }
.btn--on-photo { border-color: rgba(255,255,255,.5); color: #fff; }
.btn--on-photo:hover { background: #fff; color: var(--ink); border-color: #fff; }
.btn--sm { padding: 11px 18px; font-size: 14px; }

.btn-row { display: flex; flex-wrap: wrap; gap: 12px; }

/* ------------------------------------------------------------------ hero -- */
.hero {
  position: relative;
  min-height: min(94vh, 860px);
  display: flex; align-items: flex-end;
  padding-top: calc(var(--header-h) + 40px);
  padding-bottom: clamp(48px, 7vw, 88px);
  background: var(--ink);
  overflow: hidden;
}
.hero__media { position: absolute; inset: 0; }
.hero__media img { width: 100%; height: 100%; object-fit: cover; }
/* THE SCRIM IS MEASURED, NOT EYEBALLED. No computed style can judge white text
   over a photograph, so tools/check_hero_contrast.py composites these exact
   gradients over the real hero file — applying object-fit:cover per viewport,
   because each width shows a different slice — and checks every pixel of the
   region the text actually occupies, measured off the DOM with a Range.

   The previous values were tuned against a hero whose middle band was dark
   trees. This photograph has a bright cirrus sky exactly where the headline
   sits: they left 28.6% of the desktop copy area and 43.7% of the mobile one
   below 4.5:1, worst case 1.36:1. White on cloud.

   Measured with the values below: desktop 6.97:1 worst, mobile 5.31:1 worst,
   nothing below AA at either width. Re-run that script after ANY hero change. */
.hero__media::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(to bottom,
      rgba(18,39,64,.64) 0%,
      rgba(18,39,64,.58) 10%,
      rgba(18,39,64,.72) 50%,
      rgba(18,39,64,.91) 85%,
      rgba(18,39,64,.96) 100%);
}
/* On anything wide enough for the copy to sit in the left two-thirds, a second
   pass darkens that side only, so the sky stays open on the right. Below this
   width the text spans nearly the full hero and the vertical scrim carries it
   alone — which is why the vertical one has to pass on its own. */
@media (min-width: 861px) {
  .hero__media::before {
    content: "";
    position: absolute; inset: 0; z-index: 1;
    background:
      linear-gradient(to right,
        rgba(18,39,64,.60) 0%,
        rgba(18,39,64,.36) 58%,
        rgba(18,39,64,0) 94%);
  }
}
.hero__inner { position: relative; z-index: 2; width: 100%; }
.hero__copy { max-width: 940px; }
.hero .eyebrow { color: #fff; opacity: .9; }
.hero h1 { color: #fff; margin-bottom: 0.42em; }
.hero__sub {
  font-size: var(--lead); color: rgba(255,255,255,.9);
  max-width: 620px; margin-bottom: 30px;
}
.hero .btn-row { margin-bottom: 34px; }

.hero__facts {
  display: flex; flex-wrap: wrap; gap: 10px 34px;
  padding-top: 22px; border-top: 1px solid rgba(255,255,255,.22);
  list-style: none; margin: 0; padding-left: 0;
}
.hero__facts li {
  display: flex; align-items: center; gap: 9px;
  color: #fff; font-size: 14px; font-weight: 600; letter-spacing: .01em;
}
.hero__facts svg { flex: none; color: var(--accent-on-dark); }

/* ------------------------------------------------------------- services --- */
.cards {
  display: grid; gap: clamp(14px, 1.6vw, 22px);
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.card {
  background: var(--ground);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex; flex-direction: column;
  transition: border-color .25s, transform .25s, box-shadow .25s;
}
.section--band .card { background: var(--ground); }
.card:hover { border-color: var(--accent); transform: translateY(-3px); box-shadow: var(--shadow); }
.card__media { aspect-ratio: 3 / 2; background: var(--ground-2); overflow: hidden; }
.card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
.card:hover .card__media img { transform: scale(1.04); }
.card__body { padding: 22px 24px 26px; }
.card__body h3 { margin-bottom: 8px; }
.card__body p { font-size: 15.5px; margin: 0; color: var(--body); }

/* ------------------------------------------------------------------ work -- */
.gallery {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.gallery figure { margin: 0; position: relative; overflow: hidden; border-radius: var(--radius); }
.gallery img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; transition: transform .6s ease; }
.gallery figure:hover img { transform: scale(1.05); }
.gallery figcaption {
  position: absolute; inset: auto 0 0 0;
  padding: 26px 16px 13px;
  background: linear-gradient(to top, rgba(18,39,64,.92) 35%, rgba(18,39,64,.55) 70%, transparent);
  color: #fff; font-size: 13px; font-weight: 600; letter-spacing: .02em;
  /* Text over a photograph cannot be proven legible by a contrast calculation,
     because the thing behind it changes per pixel. The shadow is the cheap
     insurance a measurement cannot provide. */
  text-shadow: 0 1px 3px rgba(18,39,64,.9);
}
/* Five photographs, not six: that is how many distinct jobs are on their public
   page, and padding it out by showing one twice would be the first dishonest
   thing here. An explicit 3-column grid with the first tile double-height lands
   5 items cleanly; auto-fit left a ragged row. */
@media (min-width: 900px) {
  .gallery--tall { grid-template-columns: repeat(3, 1fr); }
  .gallery--tall figure:first-child { grid-row: span 2; }
  .gallery--tall figure:first-child img { height: 100%; aspect-ratio: auto; }
}

/* An honest empty state. Used where the fictional build had invented content. */
.empty-state {
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  padding: clamp(30px, 5vw, 54px);
  text-align: center;
  color: var(--muted);
  background: var(--ground-2);
}
.empty-state strong { display: block; color: var(--ink); font-size: var(--h3); margin-bottom: 8px; }
.empty-state p { max-width: 46ch; margin-inline: auto; font-size: 15.5px; }

/* ----------------------------------------------------------------- split -- */
.split {
  display: grid; gap: clamp(30px, 5vw, 68px);
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  align-items: center;
}
.split__media img { border-radius: var(--radius); width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.split__body { max-width: 60ch; }

/* --------------------------------------------------------------- process -- */
.steps { display: grid; gap: 2px; background: var(--line-soft); border-block: 1px solid var(--line-soft); }
.step {
  background: var(--ground); padding: 26px clamp(18px, 3vw, 34px);
  display: grid; grid-template-columns: 62px 1fr; gap: 6px 22px; align-items: start;
}
.step__num {
  font-size: 13px; font-weight: 800; letter-spacing: .12em;
  color: var(--accent); padding-top: 5px;
}
.step h3 { margin-bottom: 6px; }
.step p { grid-column: 2; font-size: 15.5px; margin: 0; }

/* ----------------------------------------------------------- service area - */
.area {
  display: grid; gap: clamp(30px, 5vw, 60px);
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  align-items: start;
}
.town-list {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 0;
}
.town-list li {
  padding: 11px 0; border-bottom: 1px solid var(--line-soft);
  font-size: 15.5px; font-weight: 600; color: var(--ink);
  display: flex; align-items: center; gap: 10px;
}
.town-list li::before {
  content: ""; width: 5px; height: 5px; flex: none;
  background: var(--accent); border-radius: 50%;
}
.map-frame {
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
  aspect-ratio: 4 / 3; background: var(--ground-2);
}
.map-frame iframe { width: 100%; height: 100%; border: 0; display: block; }

/* --------------------------------------------------------------- reviews -- */
.quotes { display: grid; gap: clamp(14px, 1.6vw, 22px); grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); }
.quote {
  background: var(--ground); border: 1px solid var(--line-soft);
  border-radius: var(--radius); padding: 28px 26px;
  display: flex; flex-direction: column; gap: 14px;
}
.quote blockquote { margin: 0; font-size: 16.5px; color: var(--ink); line-height: 1.6; }
.quote figcaption { font-size: 13.5px; color: var(--muted); margin-top: auto; }
.quote figcaption b { color: var(--ink); font-weight: 700; display: block; font-size: 14.5px; }
.stars { color: var(--accent); font-size: 14px; letter-spacing: .14em; }

/* ONE review exists for this company, so it is set as a statement rather than
   dropped into a card grid built for six. A lone bordered box in a 1200px band
   reads as a gap where the other five should be; centred with the mark above
   it reads as a choice. There is no star row anywhere on this page, because
   the Google profile carries no rating to show. */
.solo-quote { max-width: 780px; margin-inline: auto; text-align: center; }
.solo-quote__mark {
  font-size: 76px; line-height: .6; color: var(--accent);
  font-weight: 800; display: block; margin-bottom: 12px;
}
.solo-quote blockquote {
  margin: 0 0 24px;
  font-size: clamp(1.5rem, 1.1rem + 1.8vw, 2.5rem);
  line-height: 1.22; letter-spacing: -0.025em; font-weight: 700;
  color: var(--ink); text-wrap: balance;
}
.solo-quote figcaption { font-size: 14.5px; color: var(--muted); }
.solo-quote figcaption b {
  display: block; color: var(--ink); font-size: 16px; font-weight: 700;
  margin-bottom: 3px;
}

/* ------------------------------------------------------------------ faqs -- */
.faqs { max-width: 860px; border-top: 1px solid var(--line-soft); }
.faqs details { border-bottom: 1px solid var(--line-soft); }
.faqs summary {
  list-style: none; cursor: pointer; padding: 22px 44px 22px 0; position: relative;
  font-size: var(--h3); font-weight: 700; color: var(--ink); line-height: 1.3;
  letter-spacing: -0.012em;
}
.faqs summary::-webkit-details-marker { display: none; }
.faqs summary::after {
  content: ""; position: absolute; right: 6px; top: 50%;
  width: 11px; height: 11px; margin-top: -7px;
  border-right: 2px solid var(--accent); border-bottom: 2px solid var(--accent);
  transform: rotate(45deg); transition: transform .25s;
}
.faqs details[open] summary::after { transform: rotate(-135deg); margin-top: -3px; }
.faqs details > div { padding: 0 44px 24px 0; font-size: 16px; max-width: 68ch; }

/* --------------------------------------------------------------- contact --
   There is no form. Ben's call, and it is the right one for this trade: a
   waterfront owner with a washing-out bank picks up the phone, and a form with
   no backend behind it is worse than no form at all. */
.contact-grid {
  display: grid; gap: clamp(30px, 5vw, 64px);
  grid-template-columns: repeat(auto-fit, minmax(310px, 1fr));
  align-items: start;
}
.reach { display: grid; gap: 14px; align-content: start; }

.reach__call {
  display: flex; align-items: center; gap: 18px;
  padding: 24px 26px;
  background: var(--accent-fill); color: #fff;
  border-radius: var(--radius); text-decoration: none;
  transition: background-color .2s, transform .2s;
}
.reach__call:hover { background: #AE1A0F; transform: translateY(-2px); }
.reach__call svg { flex: none; }
.reach__call span { display: grid; line-height: 1.2; }
.reach__call b {
  font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  opacity: .85;
}
.reach__call strong {
  font-size: clamp(1.5rem, 1.2rem + 1.3vw, 2.1rem); font-weight: 800;
  letter-spacing: -0.02em; margin: 4px 0 3px;
}
.reach__call em { font-style: normal; font-size: 13.5px; opacity: .88; }

.reach__row {
  display: flex; align-items: center; gap: 14px;
  padding: 17px 20px;
  border: 1px solid var(--line); border-radius: var(--radius);
  color: var(--ink); text-decoration: none;
  transition: border-color .2s, background-color .2s;
  overflow-wrap: anywhere;
}
.reach__row:hover { border-color: var(--accent); background: var(--accent-soft); }
.reach__row svg { flex: none; color: var(--accent); }
.reach__row span { display: grid; font-size: 15.5px; line-height: 1.35; }
.reach__row b {
  font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 3px;
}

.socials { display: flex; flex-wrap: wrap; gap: 10px; }
.socials a {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 13px 20px;
  border: 1px solid var(--line); border-radius: var(--radius);
  color: var(--ink); text-decoration: none;
  font-size: 15px; font-weight: 600;
  transition: border-color .2s, background-color .2s;
}
.socials a:hover { border-color: var(--accent); background: var(--accent-soft); }
.socials svg { color: var(--accent); }

.contact-card { display: grid; gap: 22px; }
.contact-row { display: flex; gap: 14px; align-items: flex-start; }
.contact-row svg { flex: none; color: var(--accent); margin-top: 3px; }
.contact-row b { display: block; color: var(--ink); font-size: 12px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; margin-bottom: 3px; }
.contact-row a { color: var(--ink); text-decoration: none; font-size: 18px; font-weight: 600; }
.contact-row a:hover { color: var(--accent); }
.contact-row p { margin: 0; font-size: 16px; color: var(--ink); }

/* ----------------------------------------------------------------- footer - */
.site-footer { background: var(--ground); color: var(--body); padding-block: clamp(48px, 6vw, 76px) 0; }
.foot-grid {
  display: grid; gap: 34px clamp(24px, 4vw, 60px);
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  padding-bottom: 44px;
}
.foot-grid h4 { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); font-weight: 700; margin-bottom: 14px; }
.foot-grid ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.foot-grid a { color: var(--body); text-decoration: none; font-size: 15px; }
.foot-grid a:hover { color: var(--accent); }
.foot-brand p { font-size: 15px; max-width: 34ch; }
.foot-bottom {
  border-top: 1px solid var(--line-soft); padding-block: 22px 30px;
  display: flex; flex-wrap: wrap; gap: 10px 24px; justify-content: space-between;
  font-size: 13px; color: var(--muted);
}
.foot-bottom a { color: var(--muted); }

/* Sticky call bar — phones only. A contractor's site lives or dies on the tap. */
.call-bar {
  position: fixed; inset: auto 0 0 0; z-index: 90;
  display: none; gap: 1px;
  background: var(--line);
  box-shadow: 0 -8px 26px -18px rgba(18,39,64,.8);
}
.call-bar a {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 15px 10px; text-decoration: none;
  font-size: 15px; font-weight: 700;
  background: var(--ink); color: #fff;
}
.call-bar a.is-primary { background: var(--accent-fill); color: #fff; }

/* ---------------------------------------------------------------- motion -- */
.rv { opacity: 0; transform: translateY(18px); transition: opacity .7s ease, transform .7s cubic-bezier(.22,.61,.36,1); }
.rv.is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .rv { opacity: 1; transform: none; transition: none; }
  .card, .gallery img, .btn { transition: none !important; }
}

/* ------------------------------------------------------------ responsive -- */
@media (max-width: 860px) {
  .nav {
    position: fixed; inset: var(--header-h) 0 auto 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--ground); border-bottom: 1px solid var(--line);
    padding: 6px 0 14px;
    transform: translateY(-8px); opacity: 0; pointer-events: none;
    transition: opacity .22s, transform .22s;
  }
  .nav.is-open { opacity: 1; transform: none; pointer-events: auto; }
  .nav a:not(.btn) { color: var(--ink); padding: 14px var(--gut); font-size: 17px; opacity: 1; }
  .nav .btn { margin: 10px var(--gut) 0; }
  .nav-toggle { display: flex; }
  .site-header:has(.nav.is-open) { background: var(--ground); }
  .site-header:has(.nav.is-open) .site-header__brand,
  .site-header:has(.nav.is-open) .nav-toggle { color: var(--ink); }
  .site-header:has(.nav.is-open) { --brand-ink: var(--ink); --brand-sub: var(--muted); }
  .site-header:has(.nav.is-open) .nav-toggle { border-color: var(--line); }

  .call-bar { display: flex; }
  body { padding-bottom: 54px; }
  .hero { min-height: 640px; }
  .hero__facts { gap: 8px 22px; }
  .step { grid-template-columns: 1fr; }
  .step p { grid-column: 1; }
  .step__num { padding-top: 0; }
}

/* ------------------------------------------------------------- waterline --
   The one piece of ornament on the page, and it is 12 lines: a hairline wave
   that sits on the seam between two sections. It is the only thing here that
   says "water" without spending a photograph on it, and it inherits --line so
   it inverts with the section like everything else. */
.section--wave { padding-top: calc(clamp(64px, 9vw, 118px) + 22px); }
.section--wave::before {
  content: "";
  position: absolute; inset: 0 0 auto 0; height: 12px;
  background-repeat: repeat-x;
  background-size: 76px 12px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='76' height='12' viewBox='0 0 76 12'%3E%3Cpath d='M0 8c9.5 0 9.5-4 19-4s9.5 4 19 4 9.5-4 19-4 9.5 4 19 4' fill='none' stroke='%23122740' stroke-opacity='.22' stroke-width='1.4'/%3E%3C/svg%3E");
}
.on-dark.section--wave::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='76' height='12' viewBox='0 0 76 12'%3E%3Cpath d='M0 8c9.5 0 9.5-4 19-4s9.5 4 19 4 9.5-4 19-4 9.5 4 19 4' fill='none' stroke='%23F6C000' stroke-opacity='.5' stroke-width='1.4'/%3E%3C/svg%3E");
}
