/* ============================================================
   DESIGN BRIEF — England Brothers Painting LLC · Bandon, OR
   Niche: Home Services (residential painting) · Tier: rebuild, homepage first
   Personality: plain-spoken · hard-wearing · exacting
   Direction: Bold & Blocky lettered like a painted shop sign — condensed
              caps, cream ground, one scarlet, brass rules, hard edges.
   Fonts: Anton (400, caps) / Archivo (400, 600)
   Palette: paper #F7EFDD · ink #171310 · accent #B70202 · dark #14100D
            (brass #C79A55 rules and numerals only — 2.24:1 on paper,
             never carries text on the cream)
   Image treatment: "coast midday, corrected" — saturation of the hard August
            sky pulled down, whole frame warmed, contrast lifted. A grade,
            applied to every photograph, nothing added or removed.
   Signature moment: THE CUT LINE. The hand-cut edge a painter is judged on,
            used as the structure of the page: a 7px hard rule opens every
            major section, the hero panel breaks the photograph on one, and
            the ledger numerals hang off it.
   Primary action: free estimate (call or form)
   ============================================================ */

/* ---------- 0 · FONTS (self-hosted, latin subset, only the weights used) ---------- */
@font-face {
  font-family: 'Anton';
  src: url('../assets/fonts/anton-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Archivo';
  src: url('../assets/fonts/archivo-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Archivo';
  src: url('../assets/fonts/archivo-600.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}

/* ---------- 1 · TOKENS ---------- */
:root {
  /* Color */
  --paper:      #F7EFDD;
  --paper-2:    #EFE4CC;
  --ink:        #171310;
  --ink-soft:   #5A4F44;
  --accent:     #B70202;
  --accent-deep:#8C0505;
  --accent-ink: #FAF3E3;
  --brass:      #C79A55;
  --brass-deep: #7F5B1B;
  --line:       #DCCFB2;
  --dark:       #14100D;
  --dark-2:     #1E1813;
  --dark-ink:   #F2E9D6;
  --dark-soft:  #B9AC96;
  --dark-line:  #3A3025;

  /* Type */
  --font-display: 'Anton', 'Arial Narrow', Impact, sans-serif;
  --font-body: 'Archivo', system-ui, -apple-system, Segoe UI, sans-serif;
  --text-hero:    clamp(2.5rem, min(0.6rem + 5vw, 9.5vh), 5rem);
  --text-h2:      clamp(2rem, 1.1rem + 4vw, 4rem);
  --text-h3:      clamp(1.1rem, 1rem + 0.7vw, 1.4rem);
  --text-body:    1.0625rem;
  --text-small:   0.9375rem;
  --text-eyebrow: 0.75rem;

  /* Space */
  --s1: .5rem;  --s2: 1rem;   --s3: 1.5rem;
  --s4: 2.5rem; --s5: 4rem;   --s6: 6.5rem;  --s7: 9.5rem;

  /* Shape & motion */
  --radius: 0px;
  --cut: 7px;                 /* the cut line */
  --ease: cubic-bezier(.22,1,.36,1);
  --speed: .5s;
  --head-h: 74px;

  /* Layout */
  --w-narrow: 40rem;
  --w-mid: 58rem;
  --w-wide: 80rem;
  --gutter: clamp(1.25rem, 4vw, 3.5rem);
}

/* ---------- 2 · RESET / BASE ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, picture, svg { display: block; max-width: 100%; }
img { height: auto; }
ul, ol { list-style: none; padding: 0; }
button, input, textarea { font: inherit; color: inherit; }

::selection { background: var(--accent); color: var(--accent-ink); }

:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}
.site-foot :focus-visible,
.process :focus-visible,
.estimate :focus-visible,
.hero :focus-visible { outline-color: var(--brass); }

.skip {
  position: absolute; left: var(--s2); top: -100px; z-index: 200;
  background: var(--accent); color: var(--accent-ink);
  padding: .7em 1.2em; font-weight: 600; text-decoration: none;
  transition: top .2s var(--ease);
}
.skip:focus { top: var(--s2); }

[id] { scroll-margin-top: calc(var(--head-h) + 1rem); }

/* ---------- 3 · TYPOGRAPHY ---------- */
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  line-height: .93;
  letter-spacing: .004em;
  text-wrap: balance;
}
h1 { font-size: var(--text-hero); }
h2 { font-size: var(--text-h2); }
h3 { font-size: var(--text-h3); line-height: 1.08; letter-spacing: .015em; }
p { text-wrap: pretty; }

.eyebrow {
  font-family: var(--font-body);
  font-size: var(--text-eyebrow);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--brass-deep);
  margin-bottom: var(--s3);
  display: flex; align-items: center; gap: .75em;
}
.eyebrow::before {
  content: ""; width: 2.25rem; height: 3px; flex: none;
  background: var(--accent);
}
.eyebrow-light { color: var(--brass); }
.eyebrow-light::before { background: var(--brass); }

.section-lead {
  max-width: 34rem;
  color: var(--ink-soft);
  margin-top: var(--s3);
}
.section-head-light .section-lead { color: var(--dark-soft); }
.section-head h2 + .section-lead { margin-top: var(--s3); }

b, strong { font-weight: 600; }

/* ---------- 4 · LAYOUT PRIMITIVES ---------- */
main > section {
  padding-inline: var(--gutter);
}
.section-head { margin-bottom: var(--s5); }

/* ---------- 5 · COMPONENTS ---------- */

/* Links */
a { color: var(--accent); }
p a, .foot-line a, .estimate-call a {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: .18em;
  transition: text-decoration-thickness .15s var(--ease), color .15s var(--ease);
}
p a:hover, .foot-line a:hover, .estimate-call a:hover {
  text-decoration-thickness: 4px;
  color: var(--accent-deep);
}
.site-foot p a, .estimate-intro p a { color: var(--brass); }
.site-foot p a:hover, .estimate-intro p a:hover { color: var(--dark-ink); }

/* Buttons — one flat block, no offset shadow.
   The hard shadow read as a second rectangle sitting behind the first, which
   is a doubled edge rather than a designed one. The press is carried instead
   by the fill going a step deeper and the whole block moving 1px, which is
   what a real button does. Square corners and the heavy caps still do the
   Bold & Blocky work. */
.btn {
  display: inline-block;
  font-weight: 600;
  font-size: var(--text-small);
  text-transform: uppercase;
  letter-spacing: .09em;
  text-decoration: none;
  padding: .95em 1.7em;
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  transition: background-color .18s var(--ease), border-color .18s var(--ease),
              color .18s var(--ease), translate .12s var(--ease);
  cursor: pointer;
  text-align: center;
}
.btn:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.btn:active { translate: 0 1px; }

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.btn-primary:hover { background: var(--accent-deep); border-color: var(--accent-deep); color: var(--accent-ink); }

.btn-ghost {
  background: transparent;
  border-color: var(--dark-ink);
  color: var(--dark-ink);
}
.btn-ghost:hover { background: var(--dark-ink); border-color: var(--dark-ink); color: var(--dark); }
.btn:disabled { opacity: .6; cursor: wait; }

/* Header */
.site-head {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 100;
  min-height: var(--head-h);
  display: flex; align-items: center; gap: var(--s3);
  padding: .7rem var(--gutter);
  transition: background-color .3s var(--ease), box-shadow .3s var(--ease);
}
.site-head::before {
  content: ""; position: absolute; inset: 0 0 -46px 0; z-index: -1;
  background: linear-gradient(to bottom, rgba(10,7,5,.9) 0%, rgba(10,7,5,.66) 45%, rgba(10,7,5,0) 100%);
  transition: opacity .3s var(--ease);
}
.site-head.is-stuck {
  background: var(--dark);
  border-bottom: 3px solid var(--accent);
}
.site-head.is-stuck::before { opacity: 0; }

.brand { display: flex; align-items: center; gap: .7rem; text-decoration: none; margin-inline-end: auto; }
.brand-badge { width: 52px; height: 52px; flex: none; }
.brand-words { display: flex; flex-direction: column; line-height: 1; }
.brand-name {
  font-family: var(--font-display); text-transform: uppercase;
  font-size: 1.32rem; letter-spacing: .015em; color: var(--dark-ink);
}
.brand-sub {
  font-size: .72rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .13em; color: var(--brass); margin-top: .3rem;
}

.nav-panel { display: contents; }
.nav-list { display: flex; align-items: center; gap: clamp(1rem, 2vw, 2rem); }
.nav-list a {
  position: relative;
  font-size: .82rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .1em; color: var(--dark-ink); text-decoration: none;
  padding: .5rem 0;
  transition: color .15s var(--ease);
}
/* the underline is drawn, not switched on */
.nav-list a:not(.nav-cta)::after {
  content: ""; position: absolute; inset-inline: 0; inset-block-end: 0;
  height: 2px; background: var(--brass);
  scale: 0 1; transform-origin: left center;
  transition: scale .28s var(--ease);
}
.nav-list a:not(.nav-cta):hover::after,
.nav-list a:not(.nav-cta):focus-visible::after { scale: 1 1; }
/* scroll spy: whichever section you are actually looking at */
.nav-list a[aria-current="true"] { color: var(--brass); }
.nav-list a[aria-current="true"]:not(.nav-cta)::after { scale: 1 1; }

.nav-cta {
  background: var(--accent); color: var(--accent-ink) !important;
  padding: .7rem 1.1rem !important;
  transition: background-color .15s var(--ease);
}
.nav-cta:hover { background: var(--accent-deep); }
.nav-toggle { display: none; }
.nav-foot { display: none; }

/* the scroll rule: the cut line advancing down the page */
.head-progress {
  position: absolute; inset-inline: 0; inset-block-end: 0; height: 3px;
  display: block; overflow: hidden; opacity: 0;
  transition: opacity .3s var(--ease);
}
.site-head.is-stuck .head-progress { opacity: 1; }
.head-progress i {
  display: block; height: 100%; width: 100%;
  background: var(--brass);
  transform-origin: left center;
  scale: var(--progress, 0) 1;
}

.head-phone {
  display: flex; flex-direction: column; align-items: flex-end;
  text-decoration: none; line-height: 1; padding: .35rem 0;
}
.head-phone-label {
  font-size: .7rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .15em; color: var(--brass);
}
.head-phone-number {
  font-family: var(--font-display); font-size: 1.45rem;
  color: var(--dark-ink); margin-top: .35rem; letter-spacing: .01em;
  font-variant-numeric: tabular-nums;
  transition: color .15s var(--ease);
}
.head-phone:hover .head-phone-number { color: var(--brass); }

@media (max-width: 1023px) {
  .head-phone { display: none; }
}
@media (max-width: 899px) {
  :root { --head-h: 66px; }
  .brand-badge { width: 44px; height: 44px; }
  .brand-name { font-size: 1.1rem; }
  .brand-sub { font-size: .6rem; }

  .nav-toggle {
    display: flex; align-items: center; gap: .55rem;
    background: transparent; border: 2px solid var(--dark-ink);
    color: var(--dark-ink); padding: .55rem .8rem; cursor: pointer;
    font-size: .72rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .12em; min-height: 44px;
  }
  .nav-toggle-bars {
    width: 18px; height: 2px; background: currentColor; position: relative;
  }
  .nav-toggle-bars::before, .nav-toggle-bars::after {
    content: ""; position: absolute; left: 0; width: 18px; height: 2px;
    background: currentColor; transition: translate .2s var(--ease);
  }
  .nav-toggle-bars::before { top: -6px; }
  .nav-toggle-bars::after  { top: 6px; }
  .nav-toggle[aria-expanded="true"] { background: var(--accent); border-color: var(--accent); }

  /* the mobile menu is a ticket stub: a full color panel, oversized numbered
     links that arrive one after another, and the shop details at the bottom */
  .nav-panel {
    display: flex; flex-direction: column;
    position: fixed;
    inset-block-start: var(--head-h); inset-block-end: 0; inset-inline: 0;
    background: var(--dark);
    border-top: var(--cut) solid var(--accent);
    padding: var(--s2) var(--gutter) var(--s4);
    overflow-y: auto; overscroll-behavior: contain;
    visibility: hidden;
    clip-path: inset(0 0 100% 0);
    transition: clip-path .42s var(--ease), visibility 0s linear .42s;
  }
  .nav-panel[data-open] {
    visibility: visible;
    clip-path: inset(0 0 0 0);
    transition: clip-path .42s var(--ease), visibility 0s;
  }

  .nav-list { flex-direction: column; align-items: stretch; gap: 0; counter-reset: nav; }
  .nav-list li + li { border-top: 1px solid var(--dark-line); }
  .nav-list li {
    opacity: 0; translate: 0 14px;
    transition: opacity .34s var(--ease), translate .34s var(--ease);
  }
  .nav-panel[data-open] .nav-list li { opacity: 1; translate: 0 0; }
  .nav-panel[data-open] .nav-list li:nth-child(1) { transition-delay: .10s; }
  .nav-panel[data-open] .nav-list li:nth-child(2) { transition-delay: .16s; }
  .nav-panel[data-open] .nav-list li:nth-child(3) { transition-delay: .22s; }
  .nav-panel[data-open] .nav-list li:nth-child(4) { transition-delay: .28s; }
  .nav-panel[data-open] .nav-list li:nth-child(5) { transition-delay: .34s; }

  .nav-list a {
    display: flex; align-items: baseline; gap: .8rem;
    padding: 1.05rem 0;
    font-family: var(--font-display); font-size: 1.7rem;
    font-weight: 400; letter-spacing: .02em; text-transform: uppercase;
  }
  .nav-list a:not(.nav-cta)::before {
    counter-increment: nav; content: "0" counter(nav);
    font-size: .8rem; color: var(--brass-deep); letter-spacing: .06em;
    font-variant-numeric: tabular-nums; flex: none;
    transition: color .18s var(--ease), translate .18s var(--ease);
  }
  .nav-list a:not(.nav-cta)::after { inset-block-end: -1px; height: 3px; }
  .nav-list a:not(.nav-cta):hover::before,
  .nav-list a[aria-current="true"]::before { color: var(--brass); translate: 3px 0; }

  .nav-cta {
    margin-top: var(--s3); text-align: center; justify-content: center;
    padding: 1rem !important; font-size: 1.5rem !important;
  }
  .nav-list li:has(.nav-cta) { border-top: 0; }

  .nav-foot {
    display: block; position: relative;
    margin-top: auto; padding-top: var(--s4);
    opacity: 0; translate: 0 14px;
    transition: opacity .34s var(--ease) .40s, translate .34s var(--ease) .40s;
  }
  .nav-panel[data-open] .nav-foot { opacity: 1; translate: 0 0; }
  .nav-foot::before {
    content: ""; display: block; width: 3.5rem; height: 3px;
    background: var(--accent); margin-bottom: var(--s3);
  }
  .nav-foot-phone { display: block; text-decoration: none; }
  .nav-foot-phone span {
    display: block; font-size: .68rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .15em; color: var(--brass);
  }
  .nav-foot-phone b {
    display: block; margin-top: .35rem;
    font-family: var(--font-display); font-weight: 400; font-size: 1.9rem;
    color: var(--dark-ink); letter-spacing: .015em; font-variant-numeric: tabular-nums;
  }
  .nav-foot-hours, .nav-foot-ccb {
    margin-top: .7rem; font-size: .7rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .12em; color: var(--dark-soft);
    padding-inline-end: 6.5rem;      /* clear of the badge */
  }
  .nav-foot-badge {
    position: absolute; inset-block-end: 0; inset-inline-end: 0;
    width: 86px; height: 86px; opacity: .9;
  }

  /* the bars become a cross */
  .nav-toggle-bars { transition: background-color .2s var(--ease); }
  .nav-toggle-bars::before, .nav-toggle-bars::after {
    transition: translate .2s var(--ease), rotate .2s var(--ease) .2s;
  }
  .nav-toggle[aria-expanded="true"] .nav-toggle-bars { background: transparent; }
  .nav-toggle[aria-expanded="true"] .nav-toggle-bars::before { translate: 0 6px; rotate: 45deg; }
  .nav-toggle[aria-expanded="true"] .nav-toggle-bars::after  { translate: 0 -6px; rotate: -45deg; }
}

/* Forms */
.field { display: flex; flex-direction: column; gap: .45rem; }
.field label {
  font-size: .72rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .13em; color: var(--brass);
}
.field label span[aria-hidden] { color: var(--accent-ink); }
.field .opt { color: var(--dark-soft); letter-spacing: .1em; text-transform: none; font-weight: 400; }
.field input, .field textarea {
  background: var(--dark-2);
  border: 2px solid var(--dark-line);
  border-radius: var(--radius);
  color: var(--dark-ink);
  padding: .8rem .9rem;
  font-size: 1rem;               /* 16px — stops iOS Safari zooming on focus */
  min-height: 48px;
  transition: border-color .15s var(--ease), background-color .15s var(--ease);
}
.field textarea { resize: vertical; min-height: 7rem; line-height: 1.55; }
.field input::placeholder, .field textarea::placeholder { color: #7C7062; }
.field input:focus, .field textarea:focus {
  border-color: var(--brass); background: #241D17; outline: none;
}
.field input:focus-visible, .field textarea:focus-visible { outline: 3px solid var(--brass); outline-offset: 2px; }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Reveal — the one motion idea */
[data-reveal] {
  opacity: 0; translate: 0 26px;
  transition: opacity var(--speed) var(--ease), translate var(--speed) var(--ease);
}
[data-reveal].in { opacity: 1; translate: 0 0; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; translate: none; transition: none; }
  .btn, .nav-list a, a { transition: none !important; }
}

/* ---------- 6 · SECTIONS ---------- */

/* HERO
   ------------------------------------------------------------------
   THE PAINTER MUST NEVER SIT BEHIND THE PANEL. Two rules keep him clear,
   and `node tools/hero-clearance.mjs` proves it across 74 window sizes:

   1 · Where the panel is. Below the "room for a side panel" breakpoint the
       panel runs full width along the bottom, so it cannot sit beside anyone.
       Above it, the panel is capped at 50vw / 42rem — its right edge can
       never reach --subject-x.
   2 · Where he is. With object-fit: cover, the point named by
       object-position is the one point that stays put however the frame is
       cropped; everything else moves around it. object-position-x is pinned
       to --subject-x, which is the painter's left edge in hero-wide-*.jpg
       (0.62 of the frame, set by X_WINDOW in build-images.py). He therefore
       lands on 62% of the hero at EVERY window size.

   Change --subject-x, the panel width, or X_WINDOW["hero-wide"], and re-run
   the clearance check.
   ------------------------------------------------------------------ */
:root { --subject-x: 62%; }

.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto;
  align-items: end;
  background: var(--dark);
  isolation: isolate;
  padding: 0;
}
.hero-media { position: absolute; inset: 0; z-index: -1; }
.hero-media img {
  width: 100%; height: 100%; object-fit: cover;
  /* The phone crop has NO vertical overflow — the file is taller than it is
     wide and the hero is taller still, so cover matches on height and the 42%
     does nothing on a phone. It only bites once the wide crop is in play.
     What the phone actually shows is the top ~54% of hero-tall (42% on a
     360x640), so the painter is placed there by Y_WINDOW in build-images.py,
     not by this line. Change one and re-check the other. */
  object-position: 50% 42%;
}

/* the default panel: full width along the bottom */
.hero-panel {
  grid-row: 2;
  width: 100%;
  background: var(--dark);
  border-top: var(--cut) solid var(--accent);
  padding: var(--s3) clamp(1.25rem, 3.5vw, var(--s4)) var(--s4);
  margin-block-end: 0;
}
.hero-title { color: var(--dark-ink); }
.hero-lead {
  color: var(--dark-soft);
  max-width: 30rem;
  margin-top: var(--s2);
  font-size: 1rem;
}
.hero-actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: var(--s3); }
.hero-actions .btn { flex: 1 1 100%; }
.hero-panel .eyebrow { margin-bottom: var(--s2); }
.hero-stamp { display: none; }

@media (max-width: 899px) {
  /* Both actions, stacked. The sticky call bar tucks itself away while the
     hero is on screen, so the number is not doubled up — and the panel still
     clears the 60px the bar occupies once it arrives. */
  /* No room is reserved for the call bar here: it is tucked away for as long
     as the hero is on screen. With JavaScript off the bar is always up, so the
     <noscript> rule in the head puts the 62px back. */
  .hero-panel { padding-block-end: var(--s4); }
  /* The photograph is the point of the first screen, so the panel gives back
     everything it can: the second sentence of the lead waits until there is
     room for it, and the rest tightens up. */
  .hero-lead-more { display: none; }
  .hero-lead { font-size: .92rem; line-height: 1.5; margin-top: .6rem; }
  .hero-actions { gap: .5rem; margin-top: .85rem; }
  .hero-actions .btn { padding-block: .7em; font-size: .86rem; }
  .hero-panel { padding-block-start: 1.1rem; }
  .hero-panel .eyebrow { margin-bottom: .55rem; }
}

/* Short phones (an SE at 568px tall, a phone held in a split view). Two
   actions plus a headline is more than the screen has room for at full size,
   so the panel tightens rather than sliding under the header. */
@media (max-width: 899px) and (max-height: 660px) {
  .hero-panel { padding-block-start: var(--s2); }
  .hero-panel .eyebrow { margin-bottom: .55rem; }
  .hero-lead { font-size: .92rem; line-height: 1.5; margin-top: .55rem; }
  .hero-actions { margin-top: .9rem; }
  .hero-actions .btn { padding-block: .72em; font-size: .86rem; }
}
/* An SE-sized screen cannot hold the headline, the paragraph, two actions AND
   a photograph worth looking at. The paragraph goes; the eyebrow already says
   house painters, Bandon, Oregon, so who / what / where survives. */
@media (max-width: 899px) and (max-height: 600px) {
  .hero-lead { display: none; }
}

/* Short landscape windows — a 13" laptop with the dock showing. The panel
   tightens up so its top edge never runs under the fixed header. */
@media (min-width: 820px) and (max-height: 800px) {
  .hero-panel { padding-block: var(--s3); margin-block-end: var(--s3); }
  .hero-lead { margin-top: var(--s2) !important; }
  .hero-actions { margin-top: var(--s3) !important; }
}
@media (min-width: 820px) and (max-height: 720px) {
  /* tighter still: the two actions stay on one row instead of stacking */
  .hero-lead { font-size: .96rem !important; }
  .hero-actions .btn { padding: .8em 1.1em; font-size: .8rem; }
  .hero-panel .eyebrow { margin-bottom: var(--s2); }
}

/* ROOM FOR A SIDE PANEL — a wide window, or a merely wide-ish one that is
   also landscape. The same query drives the <picture> element in the markup,
   so the wide crop and the side panel always arrive together. */
@media (min-width: 1000px), (min-width: 820px) and (min-aspect-ratio: 6/5) {
  .hero-media img { object-position: var(--subject-x) 42%; }
  .hero-panel {
    justify-self: start;
    width: min(50vw, 42rem);
    padding: var(--s4) var(--s4) var(--s4) var(--gutter);
    margin-block-end: clamp(2rem, 9vh, 7rem);
  }
  .hero-lead { font-size: 1.0625rem; margin-top: var(--s3); }
  .hero-actions { gap: var(--s2); margin-top: var(--s4); }
  .hero-actions .btn { flex: 0 1 auto; }
  .hero-panel .eyebrow { margin-bottom: var(--s3); }

  .hero-stamp {
    display: block;
    position: absolute; inset-block-end: var(--s3); inset-inline-end: var(--gutter);
    font-size: .7rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .16em; color: var(--dark-ink);
    background: rgba(10,7,5,.62); padding: .5rem .8rem;
    border-inline-start: 3px solid var(--brass);
    font-variant-numeric: tabular-nums;
  }
  .hero-stamp b { color: var(--brass); font-weight: 600; }
}

/* CREDENTIALS — one bar, split hard down the middle: the two-tone house, and
   the same cut line the hero panel uses, turned on its side. */
.creds {
  display: grid; grid-template-columns: repeat(2, 1fr);
  border-top: var(--cut) solid var(--accent);
  padding-inline: 0;
}
.creds > div { padding: var(--s3) var(--gutter); }
.creds-light { background: var(--paper-2); }
.creds-dark  { background: var(--dark); color: var(--dark-ink); }
.creds b {
  display: block; font-family: var(--font-display); font-weight: 400;
  font-size: clamp(1.5rem, 1rem + 2vw, 2.4rem); line-height: 1;
  font-variant-numeric: tabular-nums;
}
.creds-light b { color: var(--ink); }
.creds-dark  b { color: var(--brass); }
.creds span {
  display: block; margin-top: .5rem;
  font-size: .68rem; font-weight: 600; text-transform: uppercase; letter-spacing: .13em;
}
.creds-light span { color: var(--brass-deep); }
.creds-dark  span { color: var(--dark-soft); }
@media (max-width: 799px) {
  /* Two up, checkerboarded, so no two touching cells share a ground. The
     grounds are set by position here rather than by class, which also puts
     the two identity facts on the top row and the two money facts below. */
  .creds > div:nth-child(2) { background: var(--dark); color: var(--dark-ink); }
  .creds > div:nth-child(2) b { color: var(--brass); }
  .creds > div:nth-child(2) span { color: var(--dark-soft); }

  .creds > div:nth-child(4) { background: var(--paper-2); color: var(--ink); }
  .creds > div:nth-child(4) b { color: var(--ink); }
  .creds > div:nth-child(4) span { color: var(--brass-deep); }
}
@media (min-width: 800px) { .creds { grid-template-columns: repeat(4, 1fr); } }

/* THE MIDDLE — DARK SPINE
   The middle of the page inverts. A dark core between the hero and the form,
   with photography reduced to small bright plates in hard frames and one flat
   scarlet block doing the shouting. Every section enters on a different
   device: four huge figures, a color block, a headline, a tiny label, an
   outlined numeral bleeding off the edge. */

/* --- the shout --- */
.shout {
  background: var(--accent);
  border-top: 4px solid var(--dark);
  padding-block: clamp(var(--s5), 9vw, var(--s6));
}
.shout p {
  max-width: var(--w-wide); margin-inline: auto;
  -webkit-text-stroke: 3px var(--dark);
  paint-order: stroke fill;   /* keyline behind the letterform, not eating it */
  font-family: var(--font-display); text-transform: uppercase;
  color: var(--accent-ink);
  font-size: clamp(1.9rem, .8rem + 5vw, 4.4rem); line-height: .98; letter-spacing: .01em;
  text-wrap: balance;
}

/* --- services, the one light band --- */
.services {
  background: var(--paper);
  padding-block: clamp(var(--s5), 8vw, var(--s6));
}
.services-in { max-width: var(--w-wide); margin-inline: auto; }
.services-head {
  font-size: clamp(2rem, 1.1rem + 4vw, 3.6rem);
  margin-bottom: var(--s4);
}
/* The numeral, the name and the description are three grid items, placed
   explicitly. They used to be two — the name and description were wrapped in a
   <div>, so the third column below was never filled and 64% of every row on a
   desktop screen was empty while the description crammed itself into the
   column meant for the title. If you ever wrap these again, this whole block
   stops working. Fixed 16 Aug 2026. */
.ledger li {
  display: grid; grid-template-columns: 4.5rem 1fr; gap: .35rem var(--s2);
  align-items: baseline;
  padding-block: var(--s3);
  border-top: 1px solid var(--line);
}
.ledger li:last-child { border-bottom: 1px solid var(--line); }
.ledger span {
  grid-column: 1; grid-row: 1;
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 1rem + 2.2vw, 3rem); line-height: .9;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
.ledger h3 { grid-column: 2; grid-row: 1; }
.ledger p {
  grid-column: 2; grid-row: 2;
  color: var(--ink-soft); font-size: var(--text-small); max-width: 40rem;
}
@media (min-width: 800px) {
  /* name and description sit side by side, the numeral hanging off the rule */
  .ledger li { grid-template-columns: 7rem minmax(15rem, 20rem) 1fr; gap: var(--s3); }
  .ledger p { grid-column: 3; grid-row: 1; padding-top: .25rem; }
}

/* --- plates --- */
.plates {
  background: var(--dark); color: var(--dark-ink);
  border-top: var(--cut) solid var(--brass);
  padding-block: clamp(var(--s5), 8vw, var(--s6));
}
.plates > * { max-width: var(--w-wide); margin-inline: auto; }
.plates-note {
  font-size: .7rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .16em; color: var(--brass);
  padding: 0 var(--gutter) .8rem; border-bottom: 1px solid var(--dark-line);
  margin-bottom: var(--s4);
}
/* the work section is now a swipe carousel — one photo at a time, full frame,
   with a blurred fill so portrait and landscape shots sit in the same stage
   without black bars or cropping the actual work. */
.swipe { --slide-h: clamp(320px, 62vh, 600px); position: relative; }
.swipe-viewport {
  display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch; scrollbar-width: none; outline: none;
}
.swipe-viewport::-webkit-scrollbar { display: none; }
.swipe-track { display: flex; width: 100%; margin: 0; padding: 0; list-style: none; }
.swipe-slide {
  position: relative; flex: 0 0 100%; scroll-snap-align: center;
  height: var(--slide-h); overflow: hidden; background: var(--dark-2);
}
.swipe-slide::before {                       /* blurred fill from the same photo */
  /* --bg is set inline on the <li>, but it is CONSUMED here, so the browser
     resolves the relative URL against this stylesheet — not the document.
     That is why the inline value is written ../assets/img/…  Write it as
     assets/img/… and every slide silently 404s to css/assets/img/…  */
  content: ""; position: absolute; inset: -5%; z-index: 0;
  background: var(--bg) center / cover no-repeat;
  filter: blur(34px) brightness(.42) saturate(.85);
}
.swipe-slide picture { position: relative; z-index: 1; display: block; height: 100%; }
.swipe-slide img { width: 100%; height: 100%; object-fit: contain; }
.swipe-cap {
  position: absolute; z-index: 2; inset-inline: 0; inset-block-end: 0;
  padding: 2.6rem var(--gutter) 1.1rem;
  background: linear-gradient(to top, rgba(0,0,0,.62), transparent);
  font-size: .72rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .1em; color: var(--dark-ink);
}
.swipe-btn {
  position: absolute; inset-block-start: calc(var(--slide-h) / 2); translate: 0 -50%;
  z-index: 3; width: 48px; height: 48px; display: grid; place-items: center;
  background: color-mix(in oklab, var(--dark) 68%, transparent);
  color: var(--dark-ink); border: 1px solid var(--brass);
  font-family: var(--font-display); font-size: 1.7rem; line-height: 0; cursor: pointer;
  transition: background .2s var(--ease), color .2s var(--ease);
}
.swipe-btn:hover, .swipe-btn:focus-visible { background: var(--brass); color: var(--dark); }
.swipe-prev { inset-inline-start: clamp(.5rem, 2vw, 1.1rem); }
.swipe-next { inset-inline-end: clamp(.5rem, 2vw, 1.1rem); }
/* The mark stays 10px; the button around it is the target. It used to be the
   other way round — a 10x10 button with a .6rem gap, which is under the 24x24
   WCAG 2.2 minimum with no spacing exemption available, because a 24px circle
   on one dot would overlap its neighbor. Fourteen 44px targets do not fit
   across a phone, so below 700px the row takes back the section gutter and
   the targets shrink to whatever fits, never below 24px; if even that will not
   fit, they wrap rather than being clipped. Fixed 16 Aug 2026. */
.swipe-dots {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 0; margin-top: calc(var(--s3) - 12px);
}
.swipe-dot {
  flex: 0 0 auto;
  width: 44px; height: 44px; padding: 0; margin: 0;
  border: 0; background: transparent; cursor: pointer;
  display: grid; place-items: center;
}
.swipe-dot::before {
  content: ""; width: 10px; height: 10px;
  border: 1px solid var(--brass); background: transparent;
  transition: background-color .2s var(--ease);
}
.swipe-dot[aria-current="true"]::before { background: var(--brass); }
@media (max-width: 700px) {
  .swipe-dots { margin-inline: calc(var(--gutter) * -1); }
  .swipe-dot { width: clamp(24px, calc(100vw / 14), 44px); }
}
@media (max-width: 600px) { .swipe-btn { width: 40px; height: 40px; font-size: 1.4rem; } }
@media (prefers-reduced-motion: reduce) { .swipe-viewport { scroll-behavior: auto; } }

/* --- the recommendation ---
   One real, attributed, dated quote, set as a pull-quote on cream. It sits
   between the photographs and the seven steps on purpose: you have just
   looked at the work, someone vouches for it, then we say how it is done.
   It also breaks the two dark bands apart, which the page needed.

   Deliberately NOT the shout treatment (scarlet ground, stroked letters) —
   that block is the business talking. This one is somebody else talking, so
   it is ink on cream with the quotation marks in scarlet. The marks are not
   decoration: without them the page appears to be making the claim in its
   own voice. No stars. No rating. See the comment in index.html. */
.vouch {
  background: var(--paper-2);
  border-top: var(--cut) solid var(--accent);
  padding-block: clamp(var(--s5), 8vw, var(--s6));
  position: relative; isolation: isolate;
}
.vouch-in { max-width: var(--w-wide); margin-inline: auto; }
/* a real heading, set as an eyebrow so it matches the rest of the page */
.vouch-h {
  font-family: var(--font-body);
  font-size: var(--text-eyebrow); font-weight: 600;
  text-transform: uppercase; letter-spacing: .16em; line-height: 1.4;
  color: var(--brass-deep);
  display: flex; align-items: center; gap: .75em;
  margin-bottom: var(--s4);
}
.vouch-h::before {
  content: ""; width: 2.25rem; height: 3px; flex: none; background: var(--accent);
}
.vouch figure { margin: 0; }
/* Measured in rem, not ch — Anton's zero is far narrower than its caps, so a
   ch-based measure threw one sentence onto seven lines and left the right
   two-thirds of the band dead. This lands it on three. */
.vouch blockquote { margin: 0; max-width: 46rem; }
.vouch blockquote p {
  font-family: var(--font-display); font-weight: 400;
  text-transform: uppercase;
  font-size: clamp(1.75rem, .9rem + 3.3vw, 3.4rem);
  line-height: .95; letter-spacing: .004em;
  color: var(--ink); text-wrap: balance;
}
.vouch blockquote .q { color: var(--accent); }
.vouch-by {
  display: inline-block;
  margin-top: var(--s4); padding-top: var(--s2);
  border-top: 3px solid var(--brass);
}
.vouch-by b {
  display: block;
  font-family: var(--font-display); font-weight: 400;
  text-transform: uppercase; letter-spacing: .02em;
  font-size: clamp(1rem, .9rem + .5vw, 1.3rem);
  color: var(--ink);
}
.vouch-by span {
  display: block; margin-top: .45rem;
  font-size: .72rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .13em;
  color: var(--brass-deep);
}

/* --- process --- */
.process {
  background: var(--dark-2); color: var(--dark-ink);
  border-top: 4px solid var(--dark);
  padding-block: clamp(var(--s5), 8vw, var(--s6));
  position: relative; overflow: hidden;
}
.process-in { position: relative; z-index: 1; max-width: var(--w-wide); margin-inline: auto; }
.process h2 { color: var(--dark-ink); font-size: clamp(2rem, 1.1rem + 4vw, 3.6rem); }
.process-lead { color: var(--dark-soft); max-width: 32rem; margin-top: var(--s3); margin-bottom: var(--s5); }
.steps { display: grid; gap: var(--s3) var(--s5); }
.steps li { border-top: 1px solid var(--dark-line); padding-top: var(--s2); }
.steps span {
  font-family: var(--font-display); font-size: 1rem; color: var(--brass);
  letter-spacing: .06em; font-variant-numeric: tabular-nums;
}
.steps h3 { color: var(--dark-ink); margin: .2rem 0 .4rem; }
.steps p { color: var(--dark-soft); font-size: var(--text-small); }
@media (min-width: 700px)  { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1050px) { .steps { grid-template-columns: repeat(3, 1fr); } }

/* The same badge tile as the footer, behind this section (it replaced the old
   giant "07" outline). Mask, color and tile size are shared with the footer in
   the watermark block below (search "as a watermark"); only the opacity differs
   — this panel carries content, so the tile is set a little stronger there. */
.process::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  pointer-events: none; user-select: none;
}

/* --- area, back to paper --- */
.area {
  background: var(--paper-2);
  border-top: var(--cut) solid var(--accent);
  padding-block: clamp(var(--s5), 8vw, var(--s6));
}
.area-in { max-width: var(--w-wide); margin-inline: auto; }
.area h2 { margin-bottom: var(--s4); }
.towns {
  display: flex; flex-wrap: wrap; gap: .1em .5em; align-items: baseline;
  font-family: var(--font-display); text-transform: uppercase;
  font-size: clamp(1.3rem, .7rem + 2.8vw, 2.6rem); line-height: 1.1; letter-spacing: .012em;
}
.towns li { display: flex; align-items: baseline; gap: .5em; }
.towns li:not(:last-child)::after {
  content: ""; width: .28em; height: .28em; background: var(--brass);
  border-radius: 50%; translate: 0 -.2em;
}
.area-note { margin-top: var(--s3); color: var(--ink-soft); max-width: 34rem; }

.town-home { color: var(--accent); }

/* ESTIMATE */
.estimate {
  background: var(--dark);
  color: var(--dark-ink);
  border-top: var(--cut) solid var(--accent);
  padding-block: clamp(var(--s5), 9vw, var(--s6));
  display: grid; gap: var(--s5);
}
.estimate h2 { color: var(--dark-ink); }
.estimate-intro p { color: var(--dark-soft); margin-top: var(--s3); max-width: 30rem; }
.estimate-call { font-size: 1.05rem; }
.estimate-call a { font-family: var(--font-display); font-size: 1.75rem; letter-spacing: .015em; }
.estimate-hours {
  font-size: .74rem !important; font-weight: 600; text-transform: uppercase;
  letter-spacing: .13em; color: var(--brass) !important;
}

.form { display: grid; gap: var(--s3); grid-template-columns: 1fr; }
.form-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s3); margin-top: var(--s1); }
.form-promise {
  font-size: .74rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .13em; color: var(--brass);
}
.form-msg { display: none; }
.form-msg[data-show] {
  display: block;
  border-inline-start: 4px solid var(--brass);
  background: var(--dark-2);
  padding: .9rem 1rem; font-size: var(--text-small); color: var(--dark-ink);
}
.form-msg[data-show="bad"] { border-inline-start-color: var(--accent); }

@media (min-width: 700px) {
  .form { grid-template-columns: 1fr 1fr; }
  .field-wide, .form-foot, .form-msg[data-show] { grid-column: 1 / -1; }
}
@media (min-width: 1000px) {
  .estimate {
    grid-template-columns: 1fr 1.15fr;
    gap: var(--s5) clamp(var(--s4), 6vw, var(--s6));
    max-width: calc(var(--w-wide) + var(--gutter) * 2);
    margin-inline: auto;
    align-items: start;
  }
}

/* FOOTER */
.site-foot {
  background: var(--dark-2);
  color: var(--dark-ink);
  border-top: var(--cut) solid var(--brass);
  padding: var(--s5) var(--gutter) var(--s4);
  display: grid; gap: var(--s4);
  max-width: none;
}
.foot-brand img { width: 118px; height: 118px; }
.foot-nap h2 {
  font-size: clamp(1.6rem, 1rem + 2vw, 2.35rem);
  color: var(--dark-ink); margin-bottom: var(--s2);
}
.foot-nap h2 span { color: var(--brass); }
.foot-line { font-size: var(--text-small); color: var(--dark-soft); }
.foot-phone a {
  display: inline-block; font-family: var(--font-display); font-size: 1.6rem;
  letter-spacing: .015em; color: var(--brass); padding-block: .35rem;
  text-decoration-thickness: 2px; text-underline-offset: .14em;
}
.foot-phone a:hover { color: var(--dark-ink); }
.foot-line a { display: inline-block; padding-block: .3rem; }
.foot-hours, .foot-ccb {
  font-size: .74rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .12em; color: var(--brass); margin-top: .5rem;
}
.foot-nav ul { display: flex; flex-wrap: wrap; gap: var(--s2) var(--s3); }
.foot-nav a {
  font-size: .78rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .12em; color: var(--dark-ink); text-decoration: none;
  border-bottom: 2px solid transparent; padding-block: .85rem;
}
.foot-nav a:hover { border-bottom-color: var(--brass); }
.foot-credit {
  display: flex; flex-wrap: wrap; gap: .4rem var(--s3);
  border-top: 1px solid var(--dark-line); padding-top: var(--s3);
  font-size: .8rem; color: var(--dark-soft);
}
@media (min-width: 800px) {
  .site-foot {
    grid-template-columns: auto 1fr auto;
    align-items: start;
    column-gap: var(--s5);
    max-width: calc(var(--w-wide) + var(--gutter) * 2);
    margin-inline: auto;
  }
  .foot-credit { grid-column: 1 / -1; justify-content: space-between; }
  .foot-brand img { width: 150px; height: 150px; }
}

/* STICKY CALL BAR — phones only */
.callbar { display: none; }
@media (max-width: 899px) {
  .callbar {
    position: fixed; inset-inline: 0; inset-block-end: 0; z-index: 90;
    display: grid; grid-template-columns: 1fr 1fr;
    border-top: 3px solid var(--accent-deep);
    padding-bottom: env(safe-area-inset-bottom);
    transition: translate .25s var(--ease);
  }
  .callbar[data-hidden] { translate: 0 110%; }
  .callbar a {
    text-align: center; text-decoration: none;
    font-size: .82rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .1em; padding: 1.05rem .5rem; min-height: 52px;
  }
  .callbar-call { background: var(--accent); color: var(--accent-ink); }
  .callbar-quote { background: var(--dark); color: var(--dark-ink); }
  body { padding-bottom: 60px; }
}
@media (prefers-reduced-motion: reduce) { .callbar { transition: none; } }

/* the narrowest phones still in service */
@media (max-width: 380px) {
  /* the wordmark stays on one line; the hero eyebrow says Bandon anyway */
  .brand-name { font-size: 1rem; white-space: nowrap; }
  .brand-sub { display: none; }
  .callbar { grid-template-columns: 1.3fr 1fr; }
  .callbar a { font-size: .76rem; letter-spacing: .04em; padding-inline: .35rem; }
}


/* ============================================================
   THE DETAIL LAYER
   Everything below is the stuff that separates a studio build from a
   template: drawn states rather than switched ones, staggered arrivals,
   hovers that confirm rather than decorate, a wordmark cropped by the
   viewport, and a page that prints properly. Every single one of them is
   switched off under prefers-reduced-motion at the bottom of this file.
   ============================================================ */

/* --- buttons that say what it costs you ------------------------------- */
.btn-swap { position: relative; overflow: hidden; }
.btn-swap > span, .btn-swap::after {
  display: block;
  transition: translate .26s var(--ease), opacity .26s var(--ease);
}
.btn-swap::after {
  content: attr(data-swap);
  position: absolute; inset: 0;
  display: grid; place-items: center;
  translate: 0 100%; opacity: 0;
  padding-inline: 1.2em;
}
.btn-swap:hover > span, .btn-swap:focus-visible > span { translate: 0 -140%; opacity: 0; }
.btn-swap:hover::after, .btn-swap:focus-visible::after { translate: 0 0; opacity: 1; }

/* --- reveals: everything arrives in reading order ---------------------- */
[data-reveal] > * { transition-delay: inherit; }
.ledger li, .steps li, .plate-row figure {
  opacity: 0; translate: 0 18px;
  transition: opacity .5s var(--ease), translate .5s var(--ease);
}
.in .ledger li, .in .steps li, .in .plate-row figure,
.ledger.in li, .steps.in li, .plate-row.in figure {
  opacity: 1; translate: 0 0;
}
.ledger li:nth-child(1), .steps li:nth-child(1), .plate-row figure:nth-child(1) { transition-delay: .00s; }
.ledger li:nth-child(2), .steps li:nth-child(2), .plate-row figure:nth-child(2) { transition-delay: .07s; }
.ledger li:nth-child(3), .steps li:nth-child(3), .plate-row figure:nth-child(3) { transition-delay: .14s; }
.ledger li:nth-child(4), .steps li:nth-child(4), .plate-row figure:nth-child(4) { transition-delay: .21s; }
.ledger li:nth-child(5), .steps li:nth-child(5) { transition-delay: .28s; }
.ledger li:nth-child(6), .steps li:nth-child(6) { transition-delay: .35s; }
.steps li:nth-child(7) { transition-delay: .42s; }

/* --- the ledger: a rule is drawn in as you go down it ------------------ */
.ledger li { position: relative; transition-property: opacity, translate, background-color; }
.ledger li::before {
  content: ""; position: absolute; inset-block: 0; inset-inline-start: 0;
  width: 3px; background: var(--accent);
  scale: 1 0; transform-origin: center top;
  transition: scale .3s var(--ease);
}
.ledger li:hover::before { scale: 1 1; }
.ledger li:hover { background: color-mix(in oklab, var(--brass) 12%, transparent); }
.ledger span { transition: translate .3s var(--ease); }
.ledger li:hover span { translate: 6px 0; }

/* --- plates: the photograph settles into its frame -------------------- */
.plate-row figure { position: relative; }
.plate-row img { transition: translate .35s var(--ease), outline-offset .35s var(--ease); }
.plate-row figure:hover img { translate: -4px -4px; outline-offset: 11px; }
.plate-row figcaption { transition: color .2s var(--ease); }
.plate-row figure:hover figcaption { color: var(--brass); }

/* --- towns light up ---------------------------------------------------- */
.towns li { transition: color .18s var(--ease); }
.towns li:hover { color: var(--accent); cursor: default; }

/* --- the shout gets a hairline of its own ----------------------------- */
.shout p { position: relative; }

/* --- form: states that behave like a person --------------------------- */
.field input:user-invalid, .field textarea:user-invalid { border-color: var(--accent); }
.field input:user-valid, .field textarea:user-valid { border-color: color-mix(in oklab, var(--brass) 70%, var(--dark-line)); }
.form-msg[data-show] { animation: msg-in .34s var(--ease) both; }
@keyframes msg-in { from { opacity: 0; translate: 0 8px; } to { opacity: 1; translate: 0 0; } }
.btn:disabled { opacity: .75; cursor: wait; }

/* --- the badge, as a watermark (tiled) --------------------------------- */
/* The wordmark that used to sit here clipped to "ENGLAND BROTHER" on a narrow
   screen, which is worse than no wordmark. The badge does the job better and
   it is theirs. What is loaded is only its linework as an alpha mask — the
   color comes from --dark-line, so the watermark follows the palette instead
   of being a picture of one. Rebuild it with build-mark.py.

   Treatment: the mask is tiled across the whole footer as a faint texture —
   fabric up close, plain dark from across the room. Because the mask repeats,
   the .foot-mark box fills the footer (inset:0) rather than being one sized
   badge; scale is set by mask-size, weight by opacity. */
.site-foot { position: relative; overflow: hidden; }
.site-foot > * { position: relative; z-index: 1; }
.foot-mark {
  display: block;
  position: absolute; z-index: 0;
  inset: 0;                                  /* fill the footer; the tile repeats */
  pointer-events: none; user-select: none;
}
@supports ((mask-image: url("")) or (-webkit-mask-image: url(""))) {
  .foot-mark, .process::before {
    background: var(--dark-line);
    -webkit-mask-image: url("../assets/img/mark-720.webp");
            mask-image: url("../assets/img/mark-720.webp");
    -webkit-mask-repeat: repeat;      mask-repeat: repeat;
    -webkit-mask-size: 132px 132px;   mask-size: 132px 132px;   /* tile pitch */
    -webkit-mask-position: top left;  mask-position: top left;
  }
  .foot-mark       { opacity: .09; }   /* footer: a whisper over empty space */
  .process::before { opacity: .16; }   /* process: stronger — it textures the section */
}
@media (max-width: 799px) {
  .foot-mark, .process::before {
    -webkit-mask-size: 104px 104px;   mask-size: 104px 104px;   /* smaller tile on phones */
  }
  .foot-mark       { opacity: .08; }
  .process::before { opacity: .14; }
}
@media (forced-colors: active), print { .foot-mark, .process::before { display: none; } }

/* --- sticky call bar arrives rather than being there ------------------ */
@media (max-width: 899px) {
  /* The bar is not there to begin with. The hero already carries both
     actions, so it only arrives once you have scrolled past them — and it
     ducks away again over the estimate form, which has its own. With
     JavaScript off it is pinned up permanently by the <noscript> rule,
     because then it is the only phone number on the first screen. */
  .callbar { translate: 0 110%; }
  .callbar[data-shown] { translate: 0 0; }
  .callbar[data-shown][data-hidden] { translate: 0 110%; }
}

/* --- high contrast / forced colors ----------------------------------- */
@media (forced-colors: active) {
  .btn, .nav-cta, .callbar a { border: 2px solid ButtonText; }
  .head-progress i, .eyebrow::before, .nav-foot::before { forced-color-adjust: none; }
}

/* --- print: someone will print the estimate page ---------------------- */
@media print {
  .site-head, .callbar, .hero-media, .plates, .foot-mark,
  .nav-panel, .form, .btn { display: none !important; }
  body { background: #fff; color: #000; padding: 0; font-size: 11pt; }
  .hero { min-height: auto; background: #fff; }
  .hero-panel { background: #fff; border-top: 3px solid #000; padding: 0 0 1rem; width: auto; }
  .hero-title, .hero-lead, .creds-dark, .creds-dark b, .creds-dark span,
  .process, .process h2, .steps h3, .steps p, .estimate, .estimate h2,
  .site-foot, .foot-nap h2, .foot-line { color: #000 !important; background: #fff !important; }
  .shout { background: #fff !important; border: 2px solid #000; }
  .shout p { color: #000 !important; }
  main > section { break-inside: avoid; padding-block: .5rem; }
  a[href^="tel"]::after, a[href^="mailto"]::after { content: ""; }
}

/* --- and none of it moves if you have asked it not to ----------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
  .ledger li, .steps li, .plate-row figure,
  .nav-list li, .nav-foot { opacity: 1; translate: none; }
  .nav-panel { clip-path: none; }
  .nav-panel:not([data-open]) { visibility: hidden; }
  .btn-swap::after { display: none; }
  .btn-swap > span { translate: none !important; opacity: 1 !important; }
}


/* ============================================================
   TEXTURE — the drop cloth and the brushed board
   Both tiles are LUMINANCE ONLY: mid gray is neutral, and they carry just the
   light and shade of the weave and the brush drag. They are laid over the
   existing grounds in soft-light / overlay, so --paper and --accent are
   untouched, every contrast ratio still holds, and changing a color token
   changes the textured panel with it. Rebuild them with build-textures.py.
   ============================================================ */
:root {
  --tex-canvas: image-set(
    url("../assets/img/tex-canvas-900.avif") type("image/avif"),
    url("../assets/img/tex-canvas-900.webp") type("image/webp"));
  --tex-brush: image-set(
    url("../assets/img/tex-brush-900.avif") type("image/avif"),
    url("../assets/img/tex-brush-900.webp") type("image/webp"));
}

.services, .area, .vouch, .creds-light, .shout { position: relative; isolation: isolate; }
.services::before, .area::before, .vouch::before, .creds-light::before, .shout::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  pointer-events: none;
  background-repeat: repeat;
}

/* cream grounds get the canvas */
.services::before, .area::before, .vouch::before, .creds-light::before {
  background-image: var(--tex-canvas);
  background-size: 520px 520px;
  mix-blend-mode: overlay;
  opacity: 1;
}
/* paper-2 is already a step darker, so the same tile bites harder there —
   pull it back so both cream grounds carry the same amount of cloth */
.area::before, .vouch::before { opacity: .68; }  /* paper-2 grounds take the tile harder */
.creds-light::before { background-size: 360px 360px; opacity: .68; }

/* the scarlet block gets the brush, running the way a brush runs */
.shout::before {
  background-image: var(--tex-brush);
  background-size: 620px 620px;
  mix-blend-mode: overlay;
  opacity: .85;
}

@media (forced-colors: active) {
  .services::before, .area::before, .vouch::before, .creds-light::before, .shout::before { display: none; }
}
@media print {
  .services::before, .area::before, .vouch::before, .creds-light::before, .shout::before { display: none !important; }
}
