/* Optimal Plumbing — site styles.
   Navy and copper, matching the brand used across quotes and invoices.

   Two layers of colour, on purpose:

   1. Brand constants (--navy-*, --copper-*). These are the palette and never
      change between themes; navy is navy on a printed invoice too.
   2. Semantic tokens (--page, --surface, --ink, --band, ...). Only these are
      used below, and only these are redefined for dark mode. Anything that
      hardcodes a hex outside the palette block will be wrong in one theme.

   The theme resolves in three states: an explicit choice puts data-theme on
   <html>, and with no choice the system preference decides. Every dark rule is
   written twice for that reason — once under prefers-color-scheme guarded with
   :not([data-theme="light"]), once under [data-theme="dark"] — so an explicit
   choice always beats the system setting, in both directions. */

:root {
  /* ---- Brand palette: fixed in both themes ---------------------------- */
  --navy-50: #f2f6fb;
  --navy-100: #e3ecf7;
  --navy-200: #c5d7ec;
  --navy-500: #2c5f9e;
  --navy-700: #1b3c66;
  --navy-900: #0e2038;
  --copper-50: #fdf5ee;
  --copper-400: #d98b4a;
  --copper-500: #c4712c;
  --copper-600: #a85f22;

  /* ---- Semantic tokens: light ----------------------------------------- */
  color-scheme: light;

  --page: #ffffff;
  --surface: #ffffff;
  --surface-2: #f2f6fb;
  --ink: #1a2433;
  --ink-strong: #0e2038;
  --muted: #5b6b80;
  --hairline: #e2e8f0;

  --field-bg: #ffffff;
  --field-border: #758cab;
  --focus-ring: #2c5f9e;

  --link: #1b3c66;
  --accent: #c4712c;
  --accent-hover: #a85f22;
  --accent-ink: #ffffff;
  --accent-soft: #fdf5ee;
  --accent-quiet: #a85f22;

  /* Bands are the dark chrome — top bar, hero, footer — in both themes. */
  --band: #0e2038;
  --band-ink: #ffffff;
  --band-muted: #e3ecf7;
  --band-faint: #c5d7ec;
  --band-accent: #d98b4a;

  --shadow: rgba(14, 32, 56, .07);

  --ok-bg: #ecfdf5;
  --ok-border: #a7f3d0;
  --ok-ink: #065f46;
  --err-bg: #fef2f2;
  --err-border: #fecaca;
  --err-ink: #991b1b;
  --note-bg: #fdf5ee;
  --note-border: #d98b4a;
  --note-ink: #7c3f10;
  --danger: #dc2626;
}

/* ---- Semantic tokens: dark --------------------------------------------
   Only the tokens are redefined. Copper is lifted to --copper-400 because
   #c4712c on a dark ground falls under 4.5:1, and navy text would vanish
   entirely. */
:root:not([data-theme="light"]) {
  @media (prefers-color-scheme: dark) {
    color-scheme: dark;

    --page: #0d141d;
    --surface: #161f2b;
    --surface-2: #1d2836;
    --ink: #e4ecf6;
    --ink-strong: #f4f8fd;
    --muted: #a3b4c9;
    --hairline: #2a3646;

    --field-bg: #111a24;
    --field-border: #5d7694;
    --focus-ring: #7aa9e0;

    --link: #9cc2ee;
    --accent: #d9853f;
    --accent-hover: #e79b58;
    --accent-ink: #16100a;
    --accent-soft: #2b1e12;
    --accent-quiet: #e3a069;

    --band: #070d16;
    --band-ink: #f4f8fd;
    --band-muted: #c3d2e4;
    --band-faint: #93a7bf;
    --band-accent: #e3a069;

    --shadow: rgba(0, 0, 0, .45);

    --ok-bg: #0f2a20;
    --ok-border: #2c6b51;
    --ok-ink: #8be0b4;
    --err-bg: #2b1417;
    --err-border: #7f3036;
    --err-ink: #f4a6a6;
    --note-bg: #2b1e12;
    --note-border: #8a5a28;
    --note-ink: #f0be86;
    --danger: #f87171;
  }
}

/* Nested @media inside a selector is recent; repeat it flat for older
   browsers, then let the explicit choice win over both. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --page: #0d141d;
    --surface: #161f2b;
    --surface-2: #1d2836;
    --ink: #e4ecf6;
    --ink-strong: #f4f8fd;
    --muted: #a3b4c9;
    --hairline: #2a3646;
    --field-bg: #111a24;
    --field-border: #5d7694;
    --focus-ring: #7aa9e0;
    --link: #9cc2ee;
    --accent: #d9853f;
    --accent-hover: #e79b58;
    --accent-ink: #16100a;
    --accent-soft: #2b1e12;
    --accent-quiet: #e3a069;
    --band: #070d16;
    --band-ink: #f4f8fd;
    --band-muted: #c3d2e4;
    --band-faint: #93a7bf;
    --band-accent: #e3a069;
    --shadow: rgba(0, 0, 0, .45);
    --ok-bg: #0f2a20;
    --ok-border: #2c6b51;
    --ok-ink: #8be0b4;
    --err-bg: #2b1417;
    --err-border: #7f3036;
    --err-ink: #f4a6a6;
    --note-bg: #2b1e12;
    --note-border: #8a5a28;
    --note-ink: #f0be86;
    --danger: #f87171;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --page: #0d141d;
  --surface: #161f2b;
  --surface-2: #1d2836;
  --ink: #e4ecf6;
  --ink-strong: #f4f8fd;
  --muted: #a3b4c9;
  --hairline: #2a3646;
  --field-bg: #111a24;
  --field-border: #5d7694;
  --focus-ring: #7aa9e0;
  --link: #9cc2ee;
  --accent: #d9853f;
  --accent-hover: #e79b58;
  --accent-ink: #16100a;
  --accent-soft: #2b1e12;
  --accent-quiet: #e3a069;
  --band: #070d16;
  --band-ink: #f4f8fd;
  --band-muted: #c3d2e4;
  --band-faint: #93a7bf;
  --band-accent: #e3a069;
  --shadow: rgba(0, 0, 0, .45);
  --ok-bg: #0f2a20;
  --ok-border: #2c6b51;
  --ok-ink: #8be0b4;
  --err-bg: #2b1417;
  --err-border: #7f3036;
  --err-ink: #f4a6a6;
  --note-bg: #2b1e12;
  --note-border: #8a5a28;
  --note-ink: #f0be86;
  --danger: #f87171;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font: 16px/1.6 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

a { color: var(--link); }
.wrap { max-width: 1100px; margin: 0 auto; padding: 0 20px; }
.narrow { max-width: 760px; }

/* ---- Header ---------------------------------------------------------- */
.topbar { background: var(--band); color: var(--band-ink); }
.topbar .wrap {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding-top: 6px; padding-bottom: 6px; font-size: 14px;
}
.topbar span { color: var(--band-muted); }
.topbar a { color: var(--band-ink); font-weight: 600; text-decoration: none; }
.topbar a:hover { color: var(--band-accent); }
/* The phone number is the highest-intent element on a plumbing site and it
   was breaking across three lines on a 375px screen — "(914)" / "429-" /
   "6900" — which reads as a rendering fault rather than a number to tap.
   It never wraps; the hours label beside it gives up the space instead. */
.topbar a[href^="tel:"] { white-space: nowrap; }
.topbar > .wrap > span:first-child { min-width: 0; }

.masthead { border-bottom: 1px solid var(--hairline); background: var(--surface); }
.masthead .wrap {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; padding-top: 14px; padding-bottom: 14px; flex-wrap: wrap;
}
.brand { font-size: 20px; font-weight: 800; letter-spacing: -.02em; color: var(--ink-strong); text-decoration: none; }
.brand span { color: var(--accent); }
.nav { display: flex; gap: 20px; flex-wrap: wrap; align-items: center; }
.nav a { color: var(--link); text-decoration: none; font-weight: 500; font-size: 15px; }
.nav a:hover, .nav a[aria-current="page"] { color: var(--accent-quiet); }

/* ---- Brand mark -------------------------------------------------------- */
/* The seal is a navy disc on a cream field. On a dark ground that disc turns
   into a hole, so a reverse cut is shipped alongside it and the theme decides
   which one is painted. Written across all three theme states for the same
   reason the colours are: an explicit choice must beat the OS setting. */
.brand-mark { display: inline-flex; flex: 0 0 auto; line-height: 0; }
.brand-mark img {
  display: block;
  width: var(--brand-mark-size, 34px);
  height: var(--brand-mark-size, 34px);
}
/* The `img` is carried through every one of these selectors on purpose: without
   it `.brand-mark img` above outranks a bare class and both cuts paint. */
.brand-mark img.brand-mark__dark { display: none; }

:root[data-theme="dark"] .brand-mark img.brand-mark__light { display: none; }
:root[data-theme="dark"] .brand-mark img.brand-mark__dark { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-mark img.brand-mark__light { display: none; }
  :root:not([data-theme="light"]) .brand-mark img.brand-mark__dark { display: block; }
}

/* The masthead brand is now a mark plus a wordmark. */
.brand { display: inline-flex; align-items: center; gap: 10px; }

/* Document header — the full seal centred above an invoice or a receipt. */
.doc-seal { display: flex; justify-content: center; margin: 0 0 14px; }

/* ---- Theme toggle ----------------------------------------------------- */
.theme-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 1px solid currentColor; border-radius: 999px;
  padding: 4px 11px; font: inherit; font-size: 13px; font-weight: 600;
  color: inherit; cursor: pointer; line-height: 1.4;
}
/* No opacity fade here: dimming --muted to .85 on white drops the label to
   3.96:1, and a control you have to hunt for is not a subtle control. */
.theme-toggle:hover { border-color: var(--accent); color: var(--accent-quiet); }
.topbar .theme-toggle:hover { color: var(--band-accent); border-color: var(--band-accent); }
.theme-toggle:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.theme-toggle .t-dark { display: none; }
/* Swap the label to match what the button will switch *to*. */
:root[data-theme="dark"] .theme-toggle .t-dark { display: inline; }
:root[data-theme="dark"] .theme-toggle .t-light { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .t-dark { display: inline; }
  :root:not([data-theme="light"]) .theme-toggle .t-light { display: none; }
}
.nav .theme-toggle { border-color: var(--field-border); color: var(--muted); }

/* ---- Buttons --------------------------------------------------------- */
.btn {
  display: inline-block; border: 0; border-radius: 10px; cursor: pointer;
  padding: 13px 24px; font-size: 16px; font-weight: 700; text-decoration: none;
  font-family: inherit;
}
/* --accent-quiet, not --accent: white on #c4712c is 3.6:1, which fails at
   this text size. The darker copper clears 4.5:1 in light, and in dark the
   button flips to dark-on-copper, which clears it the other way. */
.btn-primary { background: var(--accent-quiet); color: var(--accent-ink); }
.btn-primary:hover { background: var(--accent); }
:root[data-theme="dark"] .btn-primary,
:root[data-theme="dark"] .btn-primary:hover { color: #16100a; }
.btn-ghost { background: var(--surface); color: var(--link); border: 1px solid var(--field-border); }
/* Same [hidden] trap as .field and .chat below: inline-block above would keep
   a hidden button on screen. The search box's Clear link is rendered hidden
   until there is something to clear. */
.btn[hidden] { display: none !important; }
.btn-ghost:hover { background: var(--surface-2); }
.btn[disabled] { opacity: .5; cursor: not-allowed; }

/* ---- Hero carousel --------------------------------------------------- */
.hero { position: relative; isolation: isolate; overflow: hidden; background: var(--band); color: #fff; }
.hero .slides { position: absolute; inset: 0; z-index: 0; }
.hero .slide {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0; transition: opacity 1.1s ease-in-out;
}
.hero .slide.on { opacity: 1; }
/* The scrim is what makes the headline readable over a photograph. It is
   identical in both themes on purpose: it sits on top of the photo, so any
   theme-driven change to it changes how the photo itself looks. Dark mode
   once darkened it further, to stop the hero glowing against a dark page,
   and the cost was the photographs going murky — the wrong trade for the one
   part of the site whose job is to show the work. */
.hero .scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(14,32,56,.86) 0%, rgba(14,32,56,.74) 45%, rgba(14,32,56,.90) 100%);
}

/* Photographs are content, not chrome: no theme may tint, dim or invert them.
   A photo of the company's own work should look the same to every visitor.
   (The carousel's crossfade animates opacity, which this does not touch.) */
img { filter: none; }
.hero-in { position: relative; z-index: 2; padding: 56px 0 44px; text-align: center; }
.hero h1 {
  margin: 8px 0 12px; font-size: 32px; line-height: 1.2; letter-spacing: -.02em;
  color: #fff; text-shadow: 0 1px 12px rgba(0,0,0,.35);
}
.hero-kicker {
  margin: 0; font-size: 15px; font-weight: 600; letter-spacing: .01em;
  color: var(--band-accent, #e0a86a); text-shadow: 0 1px 10px rgba(0,0,0,.45);
}
.hero .lede { margin: 0 auto; max-width: 36rem; color: #dce7f4; }
.hero .cta-row { margin-top: 26px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.hero .btn-ghost { background: rgba(255,255,255,.10); color: #fff; border-color: rgba(255,255,255,.45); }
.hero .btn-ghost:hover { background: rgba(255,255,255,.18); }
.dots { position: relative; z-index: 2; display: flex; justify-content: center; gap: 9px; padding: 0 0 20px; }
.dots button {
  width: 9px; height: 9px; padding: 0; border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(255,255,255,.42); transition: background .25s, transform .25s;
}
.dots button[aria-selected="true"] { background: var(--copper-400); transform: scale(1.35); }
.dots button:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

/* ---- Sections and cards ---------------------------------------------- */
main section { padding: 52px 0; }
main section + section { border-top: 1px solid var(--hairline); }
/* The page title. Every page has exactly one, naming what the page is about;
   the section headings under it are h2. Sized a step above them so the
   hierarchy reads on screen the way it reads to a crawler. The homepage hero
   overrides this further down. */
h1 { font-size: 30px; line-height: 1.2; margin: 0 0 8px; letter-spacing: -.02em; color: var(--ink-strong); }
h2 { font-size: 24px; margin: 0 0 6px; letter-spacing: -.01em; color: var(--ink-strong); }
h3 { color: var(--ink-strong); }
.section-lede { margin: 0 0 24px; color: var(--muted); }

.grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.card {
  background: var(--surface); border: 1px solid var(--hairline); border-radius: 12px;
  padding: 22px; text-decoration: none; color: inherit; display: block;
}
a.card:hover { border-color: var(--accent); box-shadow: 0 2px 14px var(--shadow); }
.card h3 { margin: 0 0 6px; font-size: 17px; color: var(--link); }
.card p { margin: 0; color: var(--muted); font-size: 15px; }

.hours { border: 1px solid var(--hairline); border-radius: 12px; overflow: hidden; max-width: 480px; background: var(--surface); }
.hours div {
  display: flex; justify-content: space-between; gap: 16px;
  padding: 13px 20px; border-bottom: 1px solid var(--hairline); font-size: 15px;
}
.hours div:last-child { border-bottom: 0; }
.hours span:last-child { color: var(--muted); }

/* ---- FAQ -------------------------------------------------------------- */
/* A definition list, not an accordion. The answers are marked up as FAQPage,
   and Google requires a marked-up answer to be visible without interaction. */
.faq { margin: 20px 0 0; border-top: 1px solid var(--hairline); }
.faq dt { font-weight: 650; color: var(--ink-strong); padding: 18px 0 0; }
.faq dd {
  margin: 6px 0 0; padding: 0 0 18px; color: var(--muted); font-size: 15px;
  border-bottom: 1px solid var(--hairline);
}

/* ---- NAP -------------------------------------------------------------- */
/* Name, address, phone. The block search engines and directories read to
   decide two listings are the same business, so the wording here has to match
   the Google Business Profile character for character. */
.nap { font-style: normal; line-height: 1.7; }
.nap strong { color: var(--ink-strong); }

/* ---- Tables ----------------------------------------------------------- */
table { color: var(--ink); }
th { color: var(--muted); }
tbody tr { border-color: var(--hairline); }

/* ---- Booking calendar ------------------------------------------------
   A real seven-column calendar rather than a row of cards, because people
   read dates by where they sit in a week: "the Tuesday after next" is a
   position, not the fifteenth item in a list.

   Closed and out-of-range days are drawn rather than omitted. A grid with
   gaps in it is how a reader sees that Sunday is shut, instead of silently
   wondering why it is missing. */
.calwrap { overflow-x: auto; margin-bottom: 4px; }
.calgrid {
  width: 100%; border-collapse: separate; border-spacing: 4px;
  table-layout: fixed; min-width: 320px;
}
.calgrid th {
  padding: 4px 2px; font-size: 12px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted); text-align: center;
}
.calgrid th abbr { text-decoration: none; border: 0; }

.calcell {
  vertical-align: top; padding: 6px 5px; height: 74px;
  border: 1px solid var(--hairline); border-radius: 10px;
  background: var(--surface);
}
/* Outside the two-week window: present for alignment, and quiet. */
.calcell--out { background: transparent; border-color: transparent; }
.calcell--out .calcell__date { opacity: .35; }
/* In range but nothing free — closed, or fully booked. */
.calcell--shut { background: var(--surface-2); }

.calcell__date {
  display: block; font-size: 13px; font-weight: 700;
  color: var(--ink-strong); margin-bottom: 4px;
}
.calcell__month { font-weight: 600; color: var(--muted); font-size: 11.5px; }
.calcell__shut { color: var(--muted); font-size: 13px; }

/* ---- Arrival-window chips -------------------------------------------- */
.slot { display: block; margin-top: 4px; }
.slot input { position: absolute; opacity: 0; pointer-events: none; }
.slot span {
  display: block; border: 1px solid var(--field-border); border-radius: 7px;
  padding: 4px 5px; font-size: 12px; cursor: pointer; text-align: center;
  background: var(--field-bg); color: var(--ink);
  transition: background .15s, border-color .15s;
}
.slot span small { display: block; color: var(--muted); font-size: 10.5px; }
.slot input:checked + span {
  background: var(--accent-soft); border-color: var(--accent); font-weight: 700;
}
.slot input:focus-visible + span { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* Seven columns leave little room on a phone, so the chips say AM and PM
   there and spell it out once there is space. The time range is announced
   either way, so nothing is lost to a screen reader. */
/* Two classes, not one: `.slot span { display: block }` above is 0-1-1 and
   would outrank a bare `.slot__long`, so both labels rendered at once. */
.slot .slot__long,
.calcell .slot span small { display: none; }
.slot .slot__short { display: block; }

@media (min-width: 720px) {
  .calcell { height: 92px; padding: 8px 7px; }
  .calcell__date { font-size: 14px; }
  .slot span { font-size: 12.5px; padding: 5px 6px; }
  .slot .slot__short { display: none; }
  .slot .slot__long { display: block; }
  .calcell .slot span small { display: block; }
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- Forms ----------------------------------------------------------- */
.form-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.field { display: block; }
.field.full { grid-column: 1 / -1; }
/* `display: block` above is an author rule, and the browser's own
   [hidden] { display: none } loses to it — so a hidden field stays on screen.
   Same trap as .chat and .addr-menu further down. The new-job form hides its
   address block this way. */
.field[hidden] { display: none !important; }
.field label { display: block; font-size: 14px; font-weight: 600; margin-bottom: 5px; color: var(--ink-strong); }
.field input, .field select, .field textarea {
  width: 100%; padding: 11px 12px; font: inherit; font-size: 15px;
  border: 1px solid var(--field-border); border-radius: 9px;
  background: var(--field-bg); color: var(--ink);
}
.field input::placeholder, .field textarea::placeholder { color: var(--muted); opacity: .8; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: 2px solid var(--focus-ring); outline-offset: 1px; border-color: var(--focus-ring);
}
.field .hint, .hint { font-size: 13px; color: var(--muted); margin-top: 4px; }
.field .err { font-size: 13px; color: var(--err-ink); margin-top: 4px; }
.field input[aria-invalid="true"], .field textarea[aria-invalid="true"] { border-color: var(--danger); }
.check {
  display: flex; gap: 10px; align-items: flex-start; border: 1px solid var(--hairline);
  border-radius: 10px; padding: 12px 14px; background: var(--surface);
}
.check input { margin-top: 3px; }

.alert { border-radius: 10px; padding: 13px 16px; margin-bottom: 20px; font-size: 15px; }
.alert-ok { background: var(--ok-bg); border: 1px solid var(--ok-border); color: var(--ok-ink); }
.alert-err { background: var(--err-bg); border: 1px solid var(--err-border); color: var(--err-ink); }
.alert-note { background: var(--note-bg); border: 1px solid var(--note-border); color: var(--note-ink); }
.alert a { color: inherit; }

/* ---- Theme switching --------------------------------------------------
   Anything with a colour transition — the booking slots — would otherwise
   cross-fade every time the theme flips, and worse, a transition that never
   gets a frame (a background tab, a throttled renderer) leaves the element
   stuck on the OLD colour: a white slot on a dark page. The switch adds this
   class for one tick so the change is instant. */
:root.theme-switching,
:root.theme-switching *,
:root.theme-switching *::before,
:root.theme-switching *::after {
  transition: none !important;
  animation-duration: .001ms !important;
  animation-delay: 0s !important;
}

/* ---- Status pills ----------------------------------------------------
   Six tones, named for meaning rather than colour, so a status keeps its
   meaning when the theme flips. Light mode keeps the pale-tint look; dark
   mode inverts to a dark tint with a light label, because a pale pill on a
   dark page reads as a lit rectangle. */
.pill {
  display: inline-block; padding: 3px 9px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600; white-space: nowrap;
  background: var(--pill-bg); color: var(--pill-ink);
}
.pill-ok      { --pill-bg: #dcfce7; --pill-ink: #14532d; }
.pill-info    { --pill-bg: #dbeafe; --pill-ink: #1e3a8a; }
.pill-warn    { --pill-bg: #fef3c7; --pill-ink: #78350f; }
.pill-err     { --pill-bg: #fee2e2; --pill-ink: #991b1b; }
.pill-neutral { --pill-bg: #e2e8f0; --pill-ink: #475569; }
.pill-accent  { --pill-bg: #fdf5ee; --pill-ink: #a05a1f; }

:root[data-theme="dark"] .pill-ok      { --pill-bg: #10301f; --pill-ink: #8fe0b0; }
:root[data-theme="dark"] .pill-info    { --pill-bg: #14243f; --pill-ink: #a8c8f5; }
:root[data-theme="dark"] .pill-warn    { --pill-bg: #2e2410; --pill-ink: #f2ce85; }
:root[data-theme="dark"] .pill-err     { --pill-bg: #331518; --pill-ink: #f6a9a9; }
:root[data-theme="dark"] .pill-neutral { --pill-bg: #232f3f; --pill-ink: #b3c3d6; }
:root[data-theme="dark"] .pill-accent  { --pill-bg: #2e2013; --pill-ink: #e8a973; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pill-ok      { --pill-bg: #10301f; --pill-ink: #8fe0b0; }
  :root:not([data-theme="light"]) .pill-info    { --pill-bg: #14243f; --pill-ink: #a8c8f5; }
  :root:not([data-theme="light"]) .pill-warn    { --pill-bg: #2e2410; --pill-ink: #f2ce85; }
  :root:not([data-theme="light"]) .pill-err     { --pill-bg: #331518; --pill-ink: #f6a9a9; }
  :root:not([data-theme="light"]) .pill-neutral { --pill-bg: #232f3f; --pill-ink: #b3c3d6; }
  :root:not([data-theme="light"]) .pill-accent  { --pill-bg: #2e2013; --pill-ink: #e8a973; }
}

/* ---- Footer ---------------------------------------------------------- */
footer.site {
  margin-top: 40px; border-top: 1px solid var(--hairline);
  background: var(--band); color: var(--band-muted);
}
footer.site .wrap { padding-top: 40px; padding-bottom: 40px; }
footer.site .cols { display: grid; gap: 28px; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
footer.site h2 { font-size: 13px; text-transform: uppercase; letter-spacing: .06em; color: var(--band-ink); margin: 0 0 10px; }
footer.site a { color: var(--band-muted); text-decoration: none; }
footer.site a:hover { color: var(--band-accent); }
footer.site ul { list-style: none; margin: 0; padding: 0; }
footer.site li { margin-bottom: 6px; font-size: 15px; }
footer.site .legal { margin-top: 28px; font-size: 13px; color: var(--band-faint); }

@media (min-width: 640px) {
  .hero h1 { font-size: 42px; }
  .hero-in { padding: 80px 0 60px; }
}
@media (prefers-reduced-motion: reduce) {
  .hero .slide { transition: none; }
}

/* A cheque is a physical document. It prints black on white whatever the
   screen is set to, and the MICR line must never be re-coloured. */
@media print {
  :root { color-scheme: light; }
  body { background: #fff; color: #000; }
}

/* ---- Support chat -----------------------------------------------------
   The box in the bottom corner, and the transcript view in the back office.

   Rendered hidden and revealed by chat.js, so a browser that cannot run the
   script shows nothing rather than a button that does not work. Everything
   here uses the semantic tokens, so it follows the theme like the rest of
   the page — a chat panel that stayed white on a dark site would be the
   brightest thing on the screen. */
/* [hidden] comes from the browser's own stylesheet, which loses to any author
   rule — and nearly every block below sets a display. Without this the panel,
   the transcript and the compose box are all on screen before anyone clicks,
   because the hidden attribute they are rendered with does nothing. */
.chat[hidden],
.chat [hidden] { display: none !important; }

.chat {
  position: fixed; right: 16px; bottom: 16px; z-index: 60;
  /* column-reverse, so the launcher — first in the markup, because that is
     the reading and tab order — sits at the bottom and the panel opens
     upwards above it, which is where everyone expects a chat box to be. */
  display: flex; flex-direction: column-reverse; align-items: flex-end; gap: 12px;
}

.chat__launch {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 12px 18px; border: 0; border-radius: 999px;
  background: var(--accent); color: var(--accent-ink);
  font: inherit; font-size: 15px; font-weight: 600; cursor: pointer;
  box-shadow: 0 6px 20px var(--shadow);
}
.chat__launch:hover { background: var(--accent-hover); }
.chat__launch:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }
.chat__launch-icon { font-size: 17px; line-height: 1; }
.chat--open .chat__launch-label { display: none; }

.chat__badge {
  min-width: 20px; padding: 1px 6px; border-radius: 999px;
  background: var(--surface); color: var(--accent-quiet);
  font-size: 12px; font-weight: 700; text-align: center;
}

/* One slow pulse when an answer arrives while the panel is shut. Enough to
   catch an eye, not enough to be a nightclub. */
@keyframes chat-nudge {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}
.chat--nudge .chat__launch { animation: chat-nudge 1.4s ease-in-out 3; }

.chat__panel {
  width: min(370px, calc(100vw - 32px));
  display: flex; flex-direction: column;
  max-height: min(560px, calc(100vh - 120px));
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--hairline); border-radius: 14px;
  box-shadow: 0 18px 44px var(--shadow);
  overflow: hidden;
}

.chat__head {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 12px;
  padding: 14px 16px; background: var(--band); color: var(--band-ink);
}
.chat__title { margin: 0; font-size: 16px; font-weight: 700; }
.chat__sub { margin: 2px 0 0; font-size: 13px; color: var(--band-muted); }
.chat__close {
  border: 0; background: none; color: var(--band-muted);
  font-size: 24px; line-height: 1; cursor: pointer; padding: 0 2px;
}
.chat__close:hover { color: var(--band-ink); }
.chat__close:focus-visible { outline: 2px solid var(--band-accent); outline-offset: 2px; }

.chat__intro { padding: 16px; overflow-y: auto; }
.chat__lede { margin: 0 0 14px; font-size: 14px; color: var(--muted); }
.chat__label { display: block; font-size: 13px; font-weight: 600; margin: 0 0 4px; color: var(--ink-strong); }
.chat__field {
  width: 100%; padding: 9px 11px; margin-bottom: 12px;
  font: inherit; font-size: 15px;
  border: 1px solid var(--field-border); border-radius: 8px;
  background: var(--field-bg); color: var(--ink);
}
.chat__field:focus { outline: 2px solid var(--focus-ring); outline-offset: 1px; border-color: var(--focus-ring); }
.chat__hint { margin: -6px 0 14px; font-size: 12.5px; color: var(--muted); }

/* The honeypot. Off-screen rather than display:none, because some scripts
   skip fields they can see are hidden. */
.chat__trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.chat__error { margin: 0; padding: 10px 14px; font-size: 14px; color: var(--err-ink); background: var(--err-bg); }
.chat__error--foot { border-top: 1px solid var(--err-border); }

.chat__send {
  width: 100%; padding: 11px 16px; border: 0; border-radius: 9px;
  background: var(--accent); color: var(--accent-ink);
  font: inherit; font-size: 15px; font-weight: 600; cursor: pointer;
}
.chat__send:hover { background: var(--accent-hover); }
.chat__send:disabled { opacity: .6; cursor: default; }
.chat__send:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.chat__send--inline { width: auto; padding: 9px 14px; align-self: flex-end; }

.chat__log {
  flex: 1 1 auto; min-height: 180px; overflow-y: auto;
  padding: 14px 16px; display: flex; flex-direction: column; gap: 12px;
}
.chat__row { display: flex; flex-direction: column; align-items: flex-start; max-width: 88%; }
.chat__row--mine { align-self: flex-end; align-items: flex-end; }
.chat__bubble {
  padding: 9px 12px; border-radius: 12px 12px 12px 3px;
  background: var(--band); color: var(--band-ink);
  font-size: 15px; line-height: 1.45;
  /* Somebody's typed newlines are part of what they said. */
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.chat__bubble--mine {
  border-radius: 12px 12px 3px 12px;
  background: var(--accent-soft); color: var(--ink-strong);
  border: 1px solid var(--note-border);
}
.chat__meta { margin: 3px 2px 0; font-size: 11.5px; color: var(--muted); }
.chat__note { margin: 0; text-align: center; font-size: 12.5px; color: var(--muted); font-style: italic; }
.chat__ended {
  margin: 0; padding: 10px 14px; text-align: center; font-size: 12.5px;
  color: var(--muted); border-top: 1px solid var(--hairline);
}
.chat__restart {
  padding: 0; border: 0; background: none; font: inherit;
  color: var(--accent); text-decoration: underline; cursor: pointer;
}
.chat__restart:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

.chat__compose {
  display: flex; gap: 8px; align-items: flex-end;
  padding: 12px 14px; border-top: 1px solid var(--hairline);
}
.chat__input {
  flex: 1 1 auto; resize: none; max-height: 120px;
  padding: 9px 11px; font: inherit; font-size: 15px;
  border: 1px solid var(--field-border); border-radius: 9px;
  background: var(--field-bg); color: var(--ink);
}
.chat__input:focus { outline: 2px solid var(--focus-ring); outline-offset: 1px; border-color: var(--focus-ring); }
.chat__sr {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (max-width: 420px) {
  .chat { right: 10px; bottom: 10px; left: 10px; align-items: stretch; }
  .chat__panel { width: 100%; max-height: calc(100vh - 90px); }
  /* The panel wants the full width; the launcher does not. Stretched, it was
     a full-width bar pinned over the bottom of every page — permanently
     covering a line of content, and shouting louder than "Call (914)
     429-6900", which is the action that actually books a job. Back to a pill
     in the corner. */
  .chat__launch { justify-content: center; align-self: flex-end; }
}

@media (prefers-reduced-motion: reduce) {
  .chat--nudge .chat__launch { animation: none; }
}

/* A printed page is a record of the page, not of the furniture on it. */
@media print { .chat { display: none; } }

/* ---- Support chat, back office --------------------------------------- */
.chatlog {
  display: flex; flex-direction: column; gap: 14px;
  padding: 18px; border: 1px solid var(--hairline); border-radius: 12px;
  background: var(--page);
}
.chatlog__row { display: flex; flex-direction: column; align-items: flex-start; max-width: 78%; }
.chatlog__row--agent { align-self: flex-end; align-items: flex-end; }
.chatlog__bubble {
  padding: 10px 14px; border-radius: 12px 12px 12px 3px;
  background: var(--surface); border: 1px solid var(--hairline);
}
.chatlog__bubble--agent {
  border-radius: 12px 12px 3px 12px;
  background: var(--accent-soft); border-color: var(--note-border);
}
.chatlog__who { margin: 0 0 4px; font-size: 12px; color: var(--muted); }
.chatlog__body { margin: 0; font-size: 15px; line-height: 1.5; overflow-wrap: anywhere; }
.chatlog__note { margin: 0; text-align: center; font-size: 13px; color: var(--muted); font-style: italic; }

/* ---- Legal document (/terms) -----------------------------------------
   A terms page is read in two ways and has to serve both: start to finish
   once, and then jumped into at one clause when an invoice cites it. Hence
   the numbered contents list at the top and the id on every section.

   Measure is held near 68ch. Terms are the last thing anyone reads
   voluntarily, and a 100-character line is how the reading stops. */
.legal-doc__effective {
  margin: -12px 0 28px; font-size: 14px; color: var(--muted);
}

.legal-doc__toc {
  border: 1px solid var(--hairline); border-radius: 12px;
  background: var(--surface-2); padding: 18px 22px; margin-bottom: 8px;
}
.legal-doc__toc h2 {
  margin: 0 0 10px; font-size: 13px; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted);
}
.legal-doc__toc ol {
  margin: 0; padding-left: 22px; columns: 2; column-gap: 32px; font-size: 15px;
}
.legal-doc__toc li { margin-bottom: 5px; break-inside: avoid; }
.legal-doc__toc a { color: var(--link); text-decoration: none; }
.legal-doc__toc a:hover { color: var(--accent-quiet); text-decoration: underline; }

@media (max-width: 560px) {
  .legal-doc__toc ol { columns: 1; }
}

.legal-doc__section { padding-top: 30px; scroll-margin-top: 20px; }
.legal-doc__section h2 {
  margin: 0 0 12px; font-size: 20px; color: var(--ink-strong);
}
/* The number is furniture, not part of the heading, so it is quieter than the
   words and sits outside the text column on a wide screen. */
.legal-doc__num { color: var(--muted); font-weight: 600; margin-right: 6px; }

.legal-doc__section p { max-width: 68ch; margin: 0 0 12px; }
.legal-doc__section ul { max-width: 68ch; margin: 0 0 12px; padding-left: 20px; }
.legal-doc__section li { margin-bottom: 7px; }

.legal-doc__note {
  border-left: 3px solid var(--note-border); background: var(--note-bg);
  color: var(--note-ink); padding: 12px 16px; border-radius: 0 8px 8px 0;
  font-size: 15px;
}

/* Printed, this is the copy that gets stapled to a job file: the contents
   list is dead weight on paper, and a section must not break across pages
   mid-clause. */
@media print {
  .legal-doc__toc { display: none; }
  .legal-doc__section { break-inside: avoid; padding-top: 18px; }
}

/* ---- Address autocomplete ---------------------------------------------
   The dropdown on every field that takes a street line. Anchored to the
   input so the list overlays the rest of the form instead of pushing it
   down the page each time results arrive. */
.addr-wrap { position: relative; }

.addr-menu {
  position: absolute; z-index: 40; left: 0; right: 0; top: calc(100% + 4px);
  margin: 0; padding: 0; list-style: none;
  background: var(--surface); border: 1px solid var(--field-border);
  border-radius: 10px; box-shadow: 0 12px 28px var(--shadow);
  max-height: 300px; overflow-y: auto;
}
/* The browser's own [hidden] rule loses to any author display, and the rows
   below set one. Without this the menu is on screen before anyone types. */
.addr-menu[hidden] { display: none !important; }

.addr-item {
  display: block; padding: 9px 12px; cursor: pointer;
  border-bottom: 1px solid var(--hairline);
  font-size: 15px; color: var(--ink);
}
.addr-item:last-child { border-bottom: 0; }
/* The highlighted row has to be obvious to somebody arrowing through the list
   without touching the mouse. --surface-2 against --surface is barely a tenth
   of a stop apart in dark mode, which is not a state indicator — so the active
   row takes the warm accent tint and a copper edge, which read at a glance in
   both themes. Hover and keyboard selection look identical on purpose:
   hovering sets the same active row, and two different highlights visible at
   once is worse than one. */
.addr-item:hover,
.addr-item[aria-selected="true"] {
  background: var(--accent-soft);
  box-shadow: inset 3px 0 0 var(--accent);
}
.addr-item__line { display: block; }
/* An address already on file is the one worth noticing — it is how a
   duplicate customer gets caught before it is created. */
.addr-item__note {
  display: block; margin-top: 2px; font-size: 12.5px; color: var(--accent-quiet);
}

/* Announced, never seen. A sighted user has the list in front of them. */
.addr-live {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Seen: the address just picked already belongs to somebody. */
.addr-note {
  margin: 4px 0 0; font-size: 13px; font-weight: 600; color: var(--accent-quiet);
}
.addr-note:empty { display: none; }
