/* ==========================================================================
   OPTIMA PRO SERVICE LLC — components.css
   Loaded immediately AFTER style.css. Reads only the semantic tokens defined
   there, so every component inverts automatically inside .section--dark,
   .site-footer and .drawer with no descendant overrides anywhere.

     01 skip link      08 service detail   15 forms
     02 buttons        09 svcnav           16 footer
     03 header + nav   10 stat tile        17 sticky call bar
     04 drawer         11 plate / creds    18 breadcrumb
     05 hero           12 process steps    19 CTA band
     06 page head        + flow chart      20 audience router
     07 cards          13 testimonial      21 before/after slider
                       14 accordion        22 coverage map
     23 UTILITIES   24 MOTION   25 STATE   26 PRINT
     27 FORCED COLORS      28 REDUCED MOTION   <-- must remain last
   ========================================================================== */

/* --- 01 skip link ------------------------------------------------------ */
.skip-link {
  position: absolute;
  inset-inline-start: var(--s-4);
  inset-block-start: -100px;
  z-index: var(--z-skip);
  padding: var(--s-3) var(--s-5);
  background: var(--brand-700);
  color: var(--white);
  font-family: var(--font-ui);
  font-weight: 600;
  text-decoration: none;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  transition: inset-block-start var(--dur-2) var(--ease-out);
}
.skip-link:focus { inset-block-start: 0; color: var(--white); }

/* --- 02 buttons ------------------------------------------------------- */
.btn {
  --btn-bg: var(--btn-primary-bg);
  --btn-fg: var(--btn-primary-fg);
  --btn-bd: var(--btn-primary-bg);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  min-height: 52px;
  padding: 14px 26px;
  font-family: var(--font-ui);
  font-size: 1rem;
  font-weight: 600;
  font-stretch: var(--wd-ui);
  line-height: var(--lh-flat);
  letter-spacing: 0.005em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  border: var(--bw-thick) solid var(--btn-bd);
  border-radius: var(--r-sm);
  background: var(--btn-bg);
  color: var(--btn-fg);
  transition: background-color var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out),
    transform var(--dur-1) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
}
.btn > svg { width: 18px; height: 18px; flex: none; }
@media (hover: hover) {
  .btn:hover {
    --btn-bg: var(--btn-primary-bg-hover);
    --btn-bd: var(--btn-primary-bg-hover);
    transform: translateY(-2px);
    box-shadow: var(--btn-plinth);
  }
}
.btn:active { transform: translateY(1px); box-shadow: none; }
.btn:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
.btn[aria-disabled="true"], .btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}
.btn--secondary {
  --btn-bg: transparent;
  --btn-fg: var(--text-link);
  --btn-bd: var(--text-link);
  --btn-plinth: 0 3px 0 0 var(--line-strong);
}
@media (hover: hover) {
  .btn--secondary:hover {
    --btn-bg: var(--surface-brand);
    --btn-fg: var(--text-link-hover);
    --btn-bd: var(--text-link-hover);
  }
}
.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--text-body);
  --btn-bd: transparent;
  --btn-plinth: none;
  min-height: 44px;
  padding-inline: 8px;
}
@media (hover: hover) {
  .btn--ghost:hover {
    --btn-fg: var(--text-link);
    transform: none;
    text-decoration: underline;
    text-decoration-thickness: 2px;
  }
}
.header__cta { white-space: nowrap; }
.btn--lg { min-height: 58px; padding: 17px 32px; font-size: 1.0625rem; }
.btn--block { width: 100%; }

.arrow-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-ui);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-link);
  text-decoration: none;
}
.arrow-link::after {
  content: "";
  width: 6px;
  height: 7px;
  background: currentColor;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  transition: transform var(--dur-2) var(--ease-out);
}
@media (hover: hover) {
  .arrow-link:hover { text-decoration: underline; text-decoration-thickness: 2px; }
  .arrow-link:hover::after { transform: translateX(4px); }
}

/* --- 03 header + nav -------------------------------------------------- */
.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-header);
  background: var(--surface-0);
  border-block-end: var(--bw-hair) solid transparent;
  transition: box-shadow var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out);
}
.site-header.is-stuck {
  border-block-end-color: var(--line);
  box-shadow: var(--shadow-header);
}
.header__strip {
  background: var(--brand-900);
  color: var(--ink-200);
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.01em;
}
.header__strip .l-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  min-height: var(--strip-h);
}
.header__strip a { color: var(--ink-200); text-decoration: none; }
.header__strip a:hover { color: var(--white); text-decoration: underline; }
.strip__items { display: flex; align-items: center; gap: var(--s-5); }
.strip__items span { display: inline-flex; align-items: center; gap: 7px; }
.strip__items svg { width: 13px; height: 13px; flex: none; opacity: 0.8; }

.header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-6);
  min-height: var(--header-h);
  transition: min-height var(--dur-2) var(--ease-out);
}
.site-header.is-stuck .header__bar { min-height: 60px; }
.site-header.is-stuck .header__strip { display: none; }

.header__logo { display: inline-flex; align-items: center; flex: none; }
.header__logo img { height: 42px; width: auto; }
/* The one thing that cannot follow a colour token: a raster lockup. Both ship
   and --on-light/--on-dark pick one, so this rule never names a theme — the
   OS-preference path and the toggle path both work without a second copy.
   The drawer keeps the dark lockup unconditionally: the drawer is dark in
   both themes. */
.header__logo--light { display: var(--on-light); }
.header__logo--dark  { display: var(--on-dark); }
.header__right { display: flex; align-items: center; gap: clamp(10px, 2vw, 26px); }

/* --- theme toggle ------------------------------------------------------
   Shows the theme you are switching TO, not the one you are in, which is the
   convention most visitors have already learned. The label is set from JS so
   it always states the action; without JS the button is hidden entirely
   rather than sitting there doing nothing. */
.theme-toggle {
  flex: none;
  display: none;
  place-items: center;
  width: 42px;
  height: 42px;
  padding: 0;
  background: none;
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out),
    background-color var(--dur-2) var(--ease-out);
}
.js .theme-toggle { display: grid; }
.theme-toggle svg { width: 19px; height: 19px; grid-area: 1 / 1; }
/* moon while you are on light (press it to go dark), sun while you are on
   dark. Same token switch as the logo, so no theme is named here either. */
.theme-toggle__moon { display: var(--on-light); }
.theme-toggle__sun  { display: var(--on-dark); }
@media (hover: hover) {
  .theme-toggle:hover { color: var(--text-link); border-color: var(--brand-300); }
}

/* the drawer copy has room for words */
.theme-toggle--wide {
  width: 100%;
  height: auto;
  grid-auto-flow: column;
  grid-template-columns: auto 1fr;
  justify-items: start;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  font-family: var(--font-ui);
  font-size: var(--fs-nav);
  font-weight: 600;
  text-align: start;
}
.js .theme-toggle--wide { display: grid; }
.theme-toggle--wide svg { grid-area: auto; }
.theme-toggle__label { grid-column: 2; }

.nav__list {
  display: flex;
  align-items: center;
  gap: clamp(11px, 1.9vw, 28px);
  list-style: none;
}
.nav__link {
  position: relative;
  display: block;
  padding-block: 10px;
  font-family: var(--font-ui);
  font-size: var(--fs-nav);
  font-weight: 500;
  line-height: var(--lh-flat);
  letter-spacing: 0.005em;
  color: var(--text-body);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--dur-1) linear;
}
.nav__link::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: -2px;
  height: var(--bw-rule);
  background: transparent;
  transition: background-color var(--dur-2) var(--ease-out);
}
@media (hover: hover) {
  .nav__link:hover { color: var(--text-strong); }
  .nav__link:hover::after { background: var(--line-strong); }
}
/* The active state is driven by body[data-page] so the header markup stays
   byte-identical across all pages. JS adds aria-current for assistive tech. */
body[data-page="home"]     [data-nav="home"],
body[data-page="about"]    [data-nav="about"],
body[data-page="services"] [data-nav="services"],
body[data-page="contact"]  [data-nav="contact"],
body[data-page="vendor"]   [data-nav="vendor"] {
  color: var(--text-strong);
  font-weight: 600;
}
body[data-page="home"]     [data-nav="home"]::after,
body[data-page="about"]    [data-nav="about"]::after,
body[data-page="services"] [data-nav="services"]::after,
body[data-page="contact"]  [data-nav="contact"]::after,
body[data-page="vendor"]   [data-nav="vendor"]::after {
  background: var(--accent);
}

/* "Become a Vendor" addresses a different audience than the other four links
   (subcontractors looking for work, not clients looking to hire), so it sits
   behind a divider and reads a shade quieter. It stays in the main bar rather
   than the top strip so it survives the sticky collapse on scroll. */
.nav__sep {
  padding-inline-start: clamp(10px, 1.8vw, 26px);
  border-inline-start: var(--bw-hair) solid var(--line);
}
.nav__link--alt { color: var(--text-muted); }
@media (hover: hover) {
  .nav__link--alt:hover { color: var(--text-link); }
  .nav__link--alt:hover::after { background: var(--brand-300); }
}

.header__tel {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-ui);
  font-size: 1.0625rem;
  font-weight: 700;
  font-stretch: 94%;
  color: var(--text-strong);
  text-decoration: none;
  white-space: nowrap;
}
.header__tel svg { width: 17px; height: 17px; color: var(--accent); flex: none; }
@media (hover: hover) { .header__tel:hover { color: var(--text-link); } }

.nav-toggle {
  width: 48px;
  height: 48px;
  display: grid;
  grid-auto-flow: row;
  align-content: center;
  justify-items: center;
  gap: 5px;
  border: var(--bw-hair) solid var(--line-strong);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.nav-toggle__bar {
  display: block;
  width: 20px;
  height: 2px;
  background: var(--text-strong);
  transition: transform var(--dur-2) var(--ease-plate), opacity var(--dur-1) linear;
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 999.98px) {
  /* the compact toggle goes with them — below 1000px the drawer carries the
     labelled copy, and two toggles on one screen is two sources of truth */
  .header__strip, .header__nav, .header__cta, .header__tel,
  .js .header__right > .theme-toggle { display: none; }
}
@media (min-width: 1000px) { .nav-toggle { display: none; } }

/* --- 04 mobile drawer ------------------------------------------------- */
.scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-scrim);
  background: rgba(13, 20, 25, 0.55);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-3) var(--ease-out), visibility var(--dur-3);
}
.scrim.is-open { opacity: 1; visibility: visible; }

.drawer {
  position: fixed;
  inset: 0 0 0 auto;
  z-index: var(--z-drawer);
  width: min(88vw, 360px);
  display: flex;
  flex-direction: column;
  padding: var(--s-6) var(--s-6) calc(var(--s-6) + env(safe-area-inset-bottom, 0px));
  overflow-y: auto;
  overscroll-behavior: contain;
  transform: translateX(100%);
  transition: transform var(--dur-3) var(--ease-plate);
}
.drawer.is-open { transform: translateX(0); }
.drawer__head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-4); }
.drawer__head img { height: 38px; width: auto; }
.drawer__close {
  flex: none;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: var(--bw-hair) solid var(--line-strong);
  border-radius: var(--r-sm);
  color: var(--text-strong);
  cursor: pointer;
}
.drawer__close svg { width: 18px; height: 18px; }
.drawer__list { list-style: none; margin-block-start: var(--s-6); }
.drawer__link {
  display: flex;
  align-items: center;
  min-height: 56px;
  font-family: var(--font-ui);
  font-size: 1.25rem;
  font-weight: 600;
  font-stretch: 96%;
  color: var(--text-strong);
  text-decoration: none;
  border-block-end: var(--bw-hair) solid var(--line);
}
.drawer__link[aria-current="page"] { color: var(--accent); }
.drawer__foot {
  margin-block-start: auto;
  padding-block-start: var(--s-6);
  display: grid;
  gap: var(--s-3);
}
.drawer__tel {
  font-family: var(--font-ui);
  font-size: 1.5rem;
  font-weight: 700;
  font-stretch: 92%;
  color: var(--text-strong);
  text-decoration: none;
}

/* --- 05 hero ---------------------------------------------------------- */
.hero { padding-block: clamp(32px, 5vw, 60px) 0; }
.hero__inner { display: grid; gap: clamp(32px, 4vw, 52px); align-items: center; }
@media (min-width: 1000px) {
  .hero__inner {
    grid-template-columns: minmax(0, 47fr) minmax(0, 53fr);
    gap: clamp(40px, 4vw, 68px);
  }
}
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-block-start: var(--s-7); }
.hero__trust {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-3);
  margin-block-start: var(--s-7);
  padding-block-start: var(--s-5);
  border-block-start: var(--bw-hair) solid var(--line);
}
.hero__caption {
  margin-block-start: var(--s-3);
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  font-weight: 600;
  font-stretch: var(--wd-plate);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: center;
}

/* --- 06 page head (interior pages) ----------------------------------- */
.page-head { padding-block: var(--section-y-sm) 0; }
.page-head__inner { max-inline-size: 780px; }

/* --- 07 cards --------------------------------------------------------- */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: clamp(20px, 2.4vw, 28px);
  background: var(--surface-0);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-md);
  transition: transform var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out), border-color var(--dur-2) var(--ease-out);
}
.card__icon { color: var(--accent); }
.card__icon svg { width: 26px; height: 26px; }
.card p { font-size: var(--fs-small); color: var(--text-muted); }
.card--link { text-decoration: none; }
@media (hover: hover) {
  .card--link:hover {
    transform: translate(-3px, -3px);
    box-shadow: var(--plate-shadow);
    border-color: var(--brand-300);
  }
}

.tile {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: var(--s-2) var(--s-4);
  padding: var(--s-5);
  background: var(--surface-0);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-md);
  text-decoration: none;
  transition: transform var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out), border-color var(--dur-2) var(--ease-out);
}
.tile__icon { color: var(--accent); }
.tile__icon svg { width: 26px; height: 26px; }
.tile__title {
  align-self: center;
  font-family: var(--font-ui);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text-strong);
}
.tile__desc {
  grid-column: 1 / -1;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-muted);
}
@media (hover: hover) {
  .tile:hover {
    transform: translate(-3px, -3px);
    box-shadow: var(--plate-shadow);
    border-color: var(--brand-300);
  }
}

/* --- 08 service detail ------------------------------------------------ */
/* scroll-margin because the sticky header used to be cleared by the sticky
   horizontal subnav sitting above the content. On desktop the rail is beside
   the content now, so each service has to clear the header itself. */
.svc {
  padding-block: var(--section-y);
  border-block-start: var(--bw-hair) solid var(--line);
  scroll-margin-block-start: calc(var(--header-h) + var(--s-6));
}
.svc:first-child { border-block-start: 0; padding-block-start: 0; }
.svc__title { margin-block-end: var(--s-4); }
.svc__title::after {
  content: "";
  display: block;
  width: 34px;
  height: var(--bw-rule);
  margin-block-start: var(--s-4);
  background: var(--accent);
}
.svc__label {
  margin-block-start: var(--s-6);
  margin-block-end: var(--s-4);
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  font-weight: 600;
  font-stretch: var(--wd-plate);
  letter-spacing: var(--ls-plate);
  text-transform: uppercase;
  color: var(--text-muted);
}
.svc__best {
  margin-block-start: var(--s-6);
  padding: var(--s-4) var(--s-5);
  background: var(--surface-1);
  border-inline-start: var(--bw-rule) solid var(--accent);
  font-size: var(--fs-small);
}
.svc__best strong { font-family: var(--font-ui); color: var(--text-strong); }
.svc__actions { display: flex; flex-wrap: wrap; gap: var(--s-4); align-items: center; margin-block-start: var(--s-6); }

/* --- 09 svcnav — the services rail ------------------------------------
   One block of markup, two layouts. Below 1000px it is the sticky
   horizontally-scrolling strip under the header that it has always been --
   thumbs, not hover. At 1000px it becomes the sticky vertical rail in the
   first column of .svc-layout. The horizontal case is the BASE, so the
   phone layout needs no media query to be correct.
   -------------------------------------------------------------------- */
.svc-layout { display: grid; gap: var(--grid-gap); }
/* Grid items get an automatic minimum size of min-content, which the twelve
   nowrap chips blow straight past — the rail then widens the whole page
   instead of scrolling inside itself. This one line is what keeps the phone
   layout from scrolling horizontally. */
.svc-layout > * { min-inline-size: 0; }

.svcnav {
  position: sticky;
  inset-block-start: calc(var(--header-h) - 1px);
  z-index: calc(var(--z-header) - 1);
  /* The nav now sits inside .l-container instead of being its own
     full-bleed <section>, so bleed back out to the viewport edges to keep
     the edge-to-edge bar. Cancelled again at 1000px. */
  margin-inline: calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
  background: var(--surface-1);
  border-block: var(--bw-hair) solid var(--line);
}
.svcnav__title { display: none; }
.svcnav__scroll {
  display: flex;
  gap: var(--s-2);
  overflow-x: auto;
  scroll-snap-type: inline proximity;
  padding-block: var(--s-3);
  -webkit-overflow-scrolling: touch;
}
.svcnav__link {
  position: relative;
  flex: none;
  scroll-snap-align: start;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 9px 14px;
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  font-weight: 600;
  white-space: nowrap;
  color: var(--text-muted);
  text-decoration: none;
  background: var(--surface-0);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-sm);
  transition: color var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out),
    background-color var(--dur-2) var(--ease-out);
}
.svcnav__link svg {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--accent);
  transition: color var(--dur-2) var(--ease-out);
}
@media (hover: hover) {
  .svcnav__link:hover { color: var(--text-link); border-color: var(--brand-300); }
}
.svcnav__link.is-active {
  color: var(--white);
  background: var(--brand-700);
  border-color: var(--brand-700);
}
.svcnav__link.is-active svg { color: var(--white); }

@media (min-width: 1000px) {
  .svc-layout {
    grid-template-columns: 252px minmax(0, 1fr);
    gap: clamp(32px, 3.6vw, 56px);
    align-items: start;
  }
  .svcnav {
    inset-block-start: calc(var(--header-h) + var(--s-6));
    z-index: auto;
    margin-inline: 0;
    padding-inline: 0;
    background: none;
    border-block: 0;
  }
  .svcnav__title {
    display: block;
    margin-block-end: var(--s-4);
    font-family: var(--font-ui);
    font-size: var(--fs-micro);
    font-weight: 600;
    font-stretch: var(--wd-plate);
    letter-spacing: var(--ls-plate);
    text-transform: uppercase;
    color: var(--text-muted);
  }
  .svcnav__scroll {
    display: grid;
    gap: 0;
    overflow: visible;
    padding-block: 0;
    border-inline-start: var(--bw-hair) solid var(--line);
  }
  .svcnav__link {
    scroll-snap-align: none;
    padding: 11px var(--s-4);
    white-space: normal;
    background: none;
    border: 0;
    border-radius: 0;
  }
  /* The accent bar that marks the active service. It grows out of the rail
     hairline rather than appearing, which is what makes the scroll-spy
     handoff between two adjacent services read as one movement. */
  .svcnav__link::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: -1px;
    width: var(--bw-rule);
    background: var(--accent);
    transform: scaleY(0);
    transition: transform var(--dur-3) var(--ease-plate);
  }
  .svcnav__link.is-active {
    color: var(--text-strong);
    background: var(--surface-1);
  }
  .svcnav__link.is-active::before { transform: scaleY(1); }
  .svcnav__link.is-active svg { color: var(--accent); }
}
@media (min-width: 1000px) and (hover: hover) {
  .svcnav__link:hover { background: var(--surface-1); }
}

/* --- 10 stat tile ----------------------------------------------------- */
.stats { display: grid; gap: var(--grid-gap) var(--s-9); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 900px) { .stats { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* The accent rule is a pseudo-element rather than a border-inline-start so it
   can draw downward as the number counts up. A border cannot be scaled. */
.stat { position: relative; padding-inline-start: var(--s-4); }
.stat::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: var(--bw-rule);
  background: var(--accent);
  transform-origin: top;
  transition: transform var(--dur-4) var(--ease-out);
}
.js .stat.reveal::before { transform: scaleY(0); }
.js .stat.reveal.is-in::before { transform: scaleY(1); }
.stat__num {
  display: block;
  font-family: var(--font-ui);
  font-size: var(--fs-stat);
  font-weight: 800;
  font-stretch: var(--wd-display);
  line-height: 0.92;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
}
.stat__suffix { font-size: 0.5em; font-weight: 700; vertical-align: 0.4em; color: var(--accent); }
.stat__label { margin-block-start: var(--s-2); font-size: var(--fs-small); line-height: 1.4; color: var(--text-muted); }

/* --- 11 plate / credentials ------------------------------------------ */
.plate {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 8px 12px;
  background: var(--surface-0);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-xs);
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  font-weight: 600;
  font-stretch: 104%;
  line-height: var(--lh-flat);
  letter-spacing: var(--ls-badge);
  text-transform: uppercase;
  color: var(--text-body);
}
.plate svg { width: 15px; height: 15px; flex: none; color: var(--accent); }
.plate--strong {
  border-width: var(--bw-thick);
  border-color: var(--brand-200);
  background: var(--surface-brand);
  color: var(--text-link);
}

.creds { display: grid; border-block-start: var(--bw-hair) solid var(--line); }
.creds > div {
  display: grid;
  gap: var(--s-1);
  padding-block: var(--s-4);
  border-block-end: var(--bw-hair) solid var(--line);
}
@media (min-width: 720px) {
  .creds > div {
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
    gap: var(--s-5);
    align-items: baseline;
  }
}
.creds dt {
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  font-weight: 600;
  font-stretch: var(--wd-plate);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.creds dd { margin: 0; font-size: var(--fs-small); color: var(--text-strong); }

/* --- 12 process steps ------------------------------------------------- */
.steps { display: grid; gap: var(--s-8); }
@media (min-width: 720px) { .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .steps--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.step { display: grid; gap: var(--s-3); align-content: start; }
.step__num {
  position: relative;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  font-family: var(--font-ui);
  font-size: 1.25rem;
  font-weight: 800;
  font-stretch: 90%;
  color: var(--text-strong);
}
/* the logo's ring arc, opened at the bottom */
.step__num::before {
  content: "";
  position: absolute;
  inset: 0;
  border: var(--bw-rule) solid var(--accent);
  border-radius: 50%;
  clip-path: polygon(0 0, 100% 0, 100% 70%, 62% 70%, 62% 100%, 0 100%);
}
.step__num span { position: relative; z-index: 1; }

/* --- 12b flow chart ---------------------------------------------------
   The same five-step process as .steps, drawn as an actual flow: a rail
   with the steps hung off it below 1100px, five columns joined by chevrons
   above it. The point of the component is the .flow__gets plate on each
   node -- "what you get at every step" was previously buried in prose, and
   a deliverable you can name is the only part of a process a client can
   check you against.

   The rail and the chevrons are drawn with transforms rather than width /
   height so nothing reflows while they animate.
   ------------------------------------------------------------------- */
.flow {
  position: relative;
  display: grid;
  gap: var(--s-7);
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: flow;
}
/* the rail: one hairline behind the badge column */
.flow::before {
  content: "";
  position: absolute;
  inset-block: 12px;
  inset-inline-start: 21px;
  width: var(--bw-thick);
  background: var(--line-strong);
  transform-origin: top;
  transition: transform var(--dur-5) var(--ease-out);
}
/* Drawn by default; the undrawn state is scoped to .js, same contract as
   .reveal, so the rail is never invisible when JavaScript is off. */
.js .flow::before { transform: scaleY(0); }
.js .flow.is-in::before { transform: scaleY(1); }

.flow__node {
  position: relative;
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: var(--s-2) var(--s-5);
  align-items: start;
  counter-increment: flow;
}
.flow__badge {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  background: var(--surface-0);
  border: var(--bw-thick) solid var(--accent);
  border-radius: 50%;
  color: var(--accent);
}
.flow__badge svg { width: 20px; height: 20px; }
.flow__num {
  grid-column: 2;
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  font-weight: 800;
  font-stretch: var(--wd-plate);
  letter-spacing: var(--ls-plate);
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}
.flow__node > .h3 { grid-column: 2; }
.flow__node > p { grid-column: 2; }
.flow__gets {
  align-self: start;
  /* grid blockifies the inline-flex .plate, which then stretches the full
     column and reads as an input field rather than a badge */
  justify-self: start;
  margin-block-start: var(--s-2);
  text-transform: none;
  letter-spacing: 0;
  font-stretch: 100%;
  font-size: var(--fs-small);
  text-align: start;
  line-height: 1.35;
}
.flow__gets svg { align-self: start; margin-block-start: 2px; }

@media (min-width: 1100px) {
  .flow {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: var(--s-6);
  }
  /* the rail turns into the horizontal line the chevrons sit on */
  .flow::before {
    inset-block: auto;
    inset-block-start: 21px;
    inset-inline: 22px;
    width: auto;
    height: var(--bw-thick);
    transform-origin: left;
  }
  .js .flow::before { transform: scaleX(0); }
  .js .flow.is-in::before { transform: scaleX(1); }
  .flow__node {
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
    gap: var(--s-3);
  }
  .flow__num, .flow__node > .h3, .flow__node > p { grid-column: auto; }
  /* the connector: the same clip-path triangle as the band pin point */
  .flow__node::after {
    content: "";
    position: absolute;
    inset-block-start: 13px;
    inset-inline-end: calc(var(--s-6) * -1 - 4px);
    width: 18px;
    height: 18px;
    background: var(--accent);
    clip-path: polygon(0 0, 100% 50%, 0 100%);
    transform-origin: left center;
    transition: transform var(--dur-3) var(--ease-plate);
    transition-delay: calc(min(var(--i, 0), 6) * var(--reveal-stagger) + var(--dur-3));
  }
  .flow__node:last-child::after { content: none; }
  .js .flow .flow__node::after { transform: scale(0); }
  .js .flow.is-in .flow__node::after { transform: scale(1); }
}

/* --- 13 testimonial --------------------------------------------------- */
.quote {
  display: grid;
  gap: var(--s-5);
  padding: clamp(22px, 2.6vw, 30px);
  background: var(--surface-1);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-md);
  align-content: start;
}
.quote__mark { width: 22px; height: 26px; color: var(--brand-200); flex: none; }
.quote blockquote { margin: 0; font-size: var(--fs-lead); line-height: 1.55; color: var(--text-strong); text-wrap: pretty; }
.quote__who {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding-block-start: var(--s-4);
  border-block-start: var(--bw-hair) solid var(--line);
}
/* An initials plate, not a stock avatar. Fake headshots read as fake to
   exactly the sceptical audience this site exists to convince. */
.quote__initials {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  background: var(--brand-800);
  color: var(--white);
  border-radius: var(--r-xs);
  font-family: var(--font-ui);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.quote__name {
  display: block;
  font-family: var(--font-ui);
  font-size: var(--fs-small);
  font-weight: 600;
  line-height: 1.3;
  color: var(--text-strong);
}
.quote__role {
  display: block;
  font-size: var(--fs-micro);
  line-height: 1.35;
  color: var(--text-muted);
}

/* --- 14 accordion ----------------------------------------------------- */
.acc__item { border-block-end: var(--bw-hair) solid var(--line); }
.acc__sum {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
  padding-block: var(--s-5);
  cursor: pointer;
  list-style: none;
  font-family: var(--font-ui);
  font-size: var(--fs-h4);
  font-weight: 600;
  line-height: 1.4;
  color: var(--text-strong);
  transition: color var(--dur-1) linear;
}
.acc__sum::-webkit-details-marker { display: none; }
.acc__sum::marker { content: ""; }
@media (hover: hover) { .acc__sum:hover { color: var(--text-link); } }
.acc__sum:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-radius: var(--r-xs); }
/* The #i-gable symbol is drawn as a peak. Collapsed it must read "expand",
   so it starts rotated to point down and returns to the gable when open. */
.acc__icon {
  flex: none;
  width: 20px;
  height: 12px;
  margin-block-start: 0.4em;
  color: var(--accent);
  transform: rotate(180deg);
  transition: transform var(--dur-2) var(--ease-out);
}
[open] > .acc__sum .acc__icon { transform: rotate(0deg); }
.acc__body { padding-block-end: var(--s-5); max-inline-size: 66ch; color: var(--text-body); }
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }
  .acc__item::details-content {
    block-size: 0;
    overflow: hidden;
    transition: block-size var(--dur-3) var(--ease-out),
      content-visibility var(--dur-3) allow-discrete;
  }
  .acc__item[open]::details-content { block-size: auto; }
}

/* --- 15 forms --------------------------------------------------------- */
.form { display: grid; gap: var(--s-5); }
.form__row { display: grid; gap: var(--s-5); }
@media (min-width: 620px) { .form__row--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

fieldset { margin: 0; padding: 0; border: 0; min-inline-size: 0; }
.fset { display: grid; gap: var(--s-5); }
.fset + .fset {
  margin-block-start: var(--s-9);
  padding-block-start: var(--s-8);
  border-block-start: var(--bw-hair) solid var(--line);
}
.fset > legend {
  padding: 0;
  margin-block-end: var(--s-3);
  font-family: var(--font-ui);
  font-size: var(--fs-h4);
  font-weight: 700;
  font-stretch: 94%;
  color: var(--text-strong);
}
.fset__note { font-size: var(--fs-micro); line-height: 1.5; color: var(--text-muted); }

.field { display: grid; gap: 6px; }
.field__label {
  font-family: var(--font-ui);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text-body);
  transition: color var(--dur-1) linear;
}
.field:focus-within .field__label { color: var(--text-link); }
.field__req { font-weight: 400; color: var(--text-muted); }
.field__hint { font-size: var(--fs-micro); line-height: 1.45; color: var(--text-muted); }

.input, .select, .textarea {
  width: 100%;
  min-height: 52px;
  padding: 13px 14px;
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.4;
  color: var(--text-strong);
  background: var(--surface-0);
  border: var(--bw-hair) solid var(--line-strong);
  border-radius: var(--r-sm);
  transition: border-color var(--dur-1) linear, box-shadow var(--dur-1) linear,
    background-color var(--dur-1) linear;
}
.input::placeholder, .textarea::placeholder { color: var(--text-faint); }
@media (hover: hover) {
  .input:hover, .select:hover, .textarea:hover { border-color: var(--ink-400); }
}
.input:focus-visible, .select:focus-visible, .textarea:focus-visible {
  outline: none;
  border-color: var(--brand-700);
  box-shadow: 0 0 0 var(--bw-rule) rgba(11, 81, 162, 0.2);
}
.textarea { min-height: 148px; resize: vertical; }
.select {
  appearance: none;
  padding-inline-end: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='7' fill='none' stroke='%23004dbd' stroke-width='2'%3E%3Cpath d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}

.choices { display: grid; gap: var(--s-2); }
.choices--cols { grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); }
.choice {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  min-height: 44px;
  padding: 10px 12px;
  font-size: var(--fs-small);
  line-height: 1.4;
  background: var(--surface-0);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: border-color var(--dur-1) linear, background-color var(--dur-1) linear;
}
.choice input { flex: none; width: 18px; height: 18px; margin-block-start: 2px; accent-color: var(--brand-700); }
@media (hover: hover) { .choice:hover { border-color: var(--brand-300); background: var(--surface-brand); } }
@supports selector(:has(*)) {
  .choice:has(input:checked) { border-color: var(--brand-700); background: var(--surface-brand); }
  .choice:has(input:focus-visible) { box-shadow: var(--shadow-focus); }
}

.field.has-error .input,
.field.has-error .select,
.field.has-error .textarea { border-color: var(--danger-600); background: var(--danger-50); }
.field.has-error .field__label { color: var(--danger-700); }
.field__error {
  display: none;
  align-items: flex-start;
  gap: 6px;
  font-size: var(--fs-micro);
  font-weight: 600;
  line-height: 1.4;
  color: var(--danger-700);
}
.field.has-error .field__error { display: flex; }
.field__error svg { width: 15px; height: 15px; flex: none; margin-block-start: 1px; }

.notice {
  display: grid;
  gap: 6px;
  padding: var(--s-4) var(--s-5);
  background: var(--surface-1);
  border-inline-start: var(--bw-rule) solid var(--accent);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  font-size: var(--fs-small);
}
.notice--success { background: var(--success-50); border-inline-start-color: var(--success-600); }
.notice--error { background: var(--danger-50); border-inline-start-color: var(--danger-600); }
.notice strong { font-family: var(--font-ui); color: var(--text-strong); }
.notice:empty { display: none; }

/* CSS-hidden honeypot — never type="hidden", bots fill those too */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* --- 16 footer -------------------------------------------------------- */
.site-footer { position: relative; padding-block: var(--section-y) var(--s-6); }
.site-footer::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: clamp(24px, 8vw, 120px);
  width: var(--gable-w);
  height: var(--gable-h);
  background: var(--accent);
  clip-path: polygon(50% 0, 100% 100%, 50% 42%, 0 100%);
}
.footer__grid { display: grid; gap: var(--s-8) var(--s-9); }
@media (min-width: 620px) { .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .footer__grid { grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr)); } }
.footer__logo { height: 52px; width: auto; }
.footer__list { list-style: none; display: grid; gap: 10px; }
.footer__list--2col { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px var(--s-4); }
.footer__link { font-size: var(--fs-small); color: var(--text-muted); text-decoration: none; }
@media (hover: hover) { .footer__link:hover { color: var(--text-strong); text-decoration: underline; } }
.footer__tel {
  font-family: var(--font-ui);
  font-size: 1.375rem;
  font-weight: 700;
  font-stretch: 92%;
  letter-spacing: -0.01em;
  color: var(--text-strong);
  text-decoration: none;
}
.footer__bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--s-2) var(--s-6);
  margin-block-start: var(--s-9);
  padding-block-start: var(--s-5);
  border-block-start: var(--bw-hair) solid var(--line);
  font-size: var(--fs-micro);
  line-height: 1.5;
  color: var(--text-faint);
}
.footer__bar a { color: var(--text-faint); }
.footer__bar nav { display: flex; flex-wrap: wrap; gap: var(--s-4); }

/* --- 17 sticky mobile call bar --------------------------------------- */
.callbar {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: var(--z-callbar);
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: var(--bw-hair);
  background: var(--ink-900);
  border-block-start: var(--bw-hair) solid rgba(255, 255, 255, 0.14);
  padding-block-end: env(safe-area-inset-bottom, 0px);
  transition: transform var(--dur-3) var(--ease-plate);
}
.callbar.is-hidden { transform: translateY(110%); }
.callbar a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: var(--callbar-h);
  font-family: var(--font-ui);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.01em;
  text-decoration: none;
}
.callbar a svg { width: 17px; height: 17px; }
.callbar a:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 3px var(--ink-900), inset 0 0 0 6px var(--signal-400);
}
.callbar__call { background: var(--signal-500); color: var(--black-ink); }
.callbar__quote { background: transparent; color: var(--white); }
@media (min-width: 1000px) { .callbar { display: none; } }
@media (max-width: 999.98px) {
  body { padding-block-end: calc(var(--callbar-h) + env(safe-area-inset-bottom, 0px)); }
}

/* --- 18 breadcrumb --------------------------------------------------- */
.breadcrumb { background: var(--surface-1); border-block-end: var(--bw-hair) solid var(--line); }
.breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 8px;
  list-style: none;
  padding-block: var(--s-3);
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  font-weight: 500;
  line-height: 1.4;
  color: var(--text-muted);
}
.breadcrumb a { color: var(--text-muted); text-decoration: none; }
@media (hover: hover) { .breadcrumb a:hover { color: var(--text-link); text-decoration: underline; } }
.breadcrumb li + li::before {
  content: "";
  display: inline-block;
  width: 5px;
  height: 6px;
  margin-inline-end: 8px;
  vertical-align: 1px;
  background: var(--ink-400);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}
.breadcrumb [aria-current="page"] { color: var(--text-strong); font-weight: 600; }

/* --- 19 CTA band ----------------------------------------------------- */
.cta-band__inner { display: grid; gap: var(--s-6); align-items: center; }
@media (min-width: 900px) {
  .cta-band__inner { grid-template-columns: minmax(0, 1fr) auto; gap: var(--s-10); }
}
.cta-band__actions { display: flex; flex-wrap: wrap; gap: var(--s-3); }

/* A photo behind the band. The wash is not decoration — 0.72 is the lightest
   the thin end can go and still keep white body copy above 7:1 over a mid-tone
   photo, so do not lighten it without re-checking the type. The photo layer
   sits at z-index 0 rather than -1 because .section--dark paints an opaque
   background-color that a negative index would hide behind. */
.cta-band--photo { position: relative; isolation: isolate; }
.cta-band--photo > .cta-band__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}
/* `display: block` is load-bearing. The markup carries .ph--flat to switch off
   the standard .ph::after multiply wash, because this band needs its own much
   heavier one — but .ph--flat does that with `display: none` on the SAME
   pseudo-element this rule uses. Setting background here does not undo that;
   only re-declaring display does. Without this line the scrim silently never
   paints and the heading sits unreadable on a bright photo. */
.cta-band--photo > .cta-band__bg::after {
  content: "";
  display: block;
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(96deg, rgb(9 20 30 / 0.95) 0%, rgb(9 20 30 / 0.9) 46%,
    rgb(9 20 30 / 0.72) 100%);
}
.cta-band--photo > .l-container { position: relative; z-index: 1; }

/* --- 20 audience router ---------------------------------------------- */
.router { display: grid; gap: var(--grid-gap); }
@media (min-width: 760px) { .router { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.router__card {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: clamp(22px, 2.6vw, 30px);
  background: var(--surface-0);
  border: var(--bw-hair) solid var(--line);
  border-block-start: var(--bw-rule) solid var(--accent);
  border-radius: var(--r-md);
  transition: transform var(--dur-2) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
}
.router__card p { font-size: var(--fs-small); color: var(--text-muted); }
.router__card > .arrow-link { margin-block-start: auto; padding-block-start: var(--s-4); }
@media (hover: hover) {
  .router__card:hover { transform: translate(-3px, -3px); box-shadow: var(--plate-shadow); }
}

/* --- narrow-viewport refinements ------------------------------------- */
@media (max-width: 479.98px) {
  /* Side-by-side CTAs at 390px leave both buttons awkwardly short and give
     the phone number a smaller tap target than the primary action. */
  .hero__actions .btn,
  .cta-band__actions .btn,
  .svc__actions .btn { width: 100%; }
  .hero__trust .plate { width: 100%; }
  .footer__list--2col { grid-template-columns: 1fr; }
}

/* ==========================================================================
   21 · BEFORE / AFTER SLIDER
   One custom property drives everything, so dragging changes a clip-path and
   two translations and nothing else -- no layout, no reflow.

   The control is a real <input type="range"> stretched over the whole image,
   which buys click-to-position, pointer drag and arrow keys from the browser
   instead of from us. Its thumb is invisible; the visible divider is drawn
   separately and follows --ba-pos. Both panes MUST use the same .ph--* aspect
   modifier or the two halves do not line up.
   ========================================================================== */
@property --ba-pos {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

.ba {
  position: relative;
  --ba-pos: 50%;
  isolation: isolate;
  border: var(--bw-hair) solid var(--line);
  background: var(--surface-2);
}
.ba__pane { border: 0; }
/* the "after" pane is in flow and sets the height; "before" lies on top and
   is revealed from the inline start edge */
.ba__pane--before {
  position: absolute;
  inset: 0;
  clip-path: inset(0 calc(100% - var(--ba-pos)) 0 0);
}
.ba__divider {
  position: absolute;
  inset-block: 0;
  inset-inline-start: var(--ba-pos);
  z-index: 2;
  width: var(--bw-rule);
  margin-inline-start: calc(var(--bw-rule) / -2);
  background: var(--white);
  pointer-events: none;
}
.ba__grip {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
  background: var(--white);
  border-radius: 50%;
  box-shadow: 0 2px 10px rgb(9 20 30 / 0.35);
  color: var(--brand-800);
  transition: box-shadow var(--dur-2) var(--ease-out);
}
.ba__grip svg { width: 22px; height: 22px; }
.ba__range {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  margin: 0;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  cursor: ew-resize;
}
.ba__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 44px;
  height: 44px;
  background: transparent;
  border: 0;
  cursor: ew-resize;
}
.ba__range::-moz-range-thumb {
  width: 44px;
  height: 44px;
  background: transparent;
  border: 0;
  cursor: ew-resize;
}
.ba__range::-moz-range-track { background: transparent; border: 0; }
.ba__range:focus { outline: none; }
.ba:has(.ba__range:focus-visible) .ba__grip {
  box-shadow: 0 0 0 3px var(--focus), 0 2px 10px rgb(9 20 30 / 0.35);
}
.ba__tag {
  position: absolute;
  inset-block-end: var(--s-3);
  z-index: 2;
  padding: 5px 9px;
  background: rgb(9 20 30 / 0.72);
  color: var(--white);
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  font-weight: 600;
  font-stretch: var(--wd-plate);
  letter-spacing: var(--ls-badge);
  text-transform: uppercase;
  line-height: var(--lh-flat);
  border-radius: var(--r-xs);
  pointer-events: none;
}
.ba__tag--before { inset-inline-start: var(--s-3); }
.ba__tag--after  { inset-inline-end: var(--s-3); }
/* the one-shot sweep that tells a first-time visitor the divider moves */
.ba.is-sweeping { transition: --ba-pos var(--dur-5) var(--ease-out); }
.ba__caption {
  margin-block-start: var(--s-3);
  font-size: var(--fs-small);
  color: var(--text-muted);
}

/* ==========================================================================
   22 · COVERAGE MAP
   Generated by tools/make_map.py. Every colour comes from a token, so the
   map inverts inside .section--dark like everything else.
   ========================================================================== */
.map { position: relative; }
.map svg { display: block; width: 100%; height: auto; }
.map__state {
  fill: var(--surface-1);
  stroke: var(--line);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.map__state.is-covered {
  fill: var(--accent);
  stroke: var(--surface-0);
  transform-box: fill-box;
  transform-origin: center;
  transition: opacity var(--dur-4) var(--ease-out), transform var(--dur-4) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.js .map:not(.is-in) .map__state.is-covered { opacity: 0; transform: scale(0.9); }
/* 21px in a ~950-unit viewBox lands around 13px on screen at the widths this
   renders at. Labels sit ON the filled state, so they take the invert colour;
   the ones nudged off their shape (--out) sit on the page background instead
   and have to take the normal text colour. */
.map__label {
  fill: var(--white);
  font-family: var(--font-ui);
  font-size: 21px;
  font-weight: 700;
  font-stretch: var(--wd-plate);
  letter-spacing: 0.02em;
  text-anchor: middle;
  transition: opacity var(--dur-4) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 70ms + 120ms);
}
.map__label--out { fill: var(--text-strong); }
.map__leader {
  stroke: var(--accent);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  transition: opacity var(--dur-4) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 70ms + 120ms);
}
.js .map:not(.is-in) .map__label,
.js .map:not(.is-in) .map__leader { opacity: 0; }

/* ==========================================================================
   23 · UTILITIES
   ========================================================================== */
.u-visually-hidden {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip-path: inset(50%) !important;
  white-space: nowrap !important;
  border: 0 !important;
}
.u-no-wrap { white-space: nowrap; }
.u-center { text-align: center; }
.u-mt-4 { margin-block-start: var(--s-4); }
.u-mt-6 { margin-block-start: var(--s-6); }
.u-mt-8 { margin-block-start: var(--s-8); }
.u-mt-10 { margin-block-start: var(--s-10); }
.u-full { grid-column: 1 / -1; }

/* ==========================================================================
   24 · MOTION
   The hidden state is scoped to .js (added by an inline script in <head>) so
   content stays visible when JavaScript is off or fails to load.
   ========================================================================== */
.js .reveal {
  opacity: 0;
  transform: translateY(var(--reveal-y));
  transition: opacity var(--dur-4) var(--ease-out), transform var(--dur-4) var(--ease-out);
  transition-delay: calc(min(var(--i, 0), 6) * var(--reveal-stagger));
}
.js .reveal.is-in { opacity: 1; transform: none; }

/* Directional variants. Used on the two halves of a .l-split so paired
   columns arrive from opposite sides instead of both sliding up.

   These translate an element that already reaches the edge of the layout, so
   in their pre-reveal state they stick out past the viewport. body has
   overflow-x: clip for exactly this (see 25 · STATE) -- clip rather than
   hidden, because hidden would make body a scroll container and break every
   position: sticky inside it. */
.js .reveal--left  { transform: translateX(calc(var(--reveal-y) * -1.15)); }
.js .reveal--right { transform: translateX(calc(var(--reveal-y) * 1.15)); }
.js .reveal--scale { transform: scale(0.97); }

/* .reveal-group hands its children the stagger index, so the markup does not
   have to carry an inline --i on every single element. The group itself also
   takes .is-in, which is what the .flow rail and the coverage map key off. */
.reveal-group > :nth-child(2) { --i: 1; }
.reveal-group > :nth-child(3) { --i: 2; }
.reveal-group > :nth-child(4) { --i: 3; }
.reveal-group > :nth-child(5) { --i: 4; }
.reveal-group > :nth-child(6) { --i: 5; }
.reveal-group > :nth-child(n + 7) { --i: 6; }

/* Photos settle out of a slight push-in. Reuses the transform transition
   already declared on .ph img in style.css. */
.js .ph.reveal img { transform: scale(1.06); }
.js .ph.reveal.is-in img { transform: none; }

/* The hero pane grid deals itself in on load. One-shot, not scroll-driven --
   it is above the fold, so there is nothing to reveal on. */
@media (prefers-reduced-motion: no-preference) {
  .js .panes > .ph {
    animation: pane-in var(--dur-5) var(--ease-plate) backwards;
  }
  .js .panes > .ph:nth-child(2) { animation-delay: 90ms; }
  .js .panes > .ph:nth-child(3) { animation-delay: 180ms; }
  .js .panes > .ph:nth-child(4) { animation-delay: 270ms; }
}
@keyframes pane-in {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: none; }
}

/* ==========================================================================
   25 · STATE
   ========================================================================== */
body.is-locked { overflow: hidden; }

/* Guard for the transform-based reveals in 24 · MOTION: .reveal--right starts
   its element translated past the right edge of the layout, which would give
   the page a horizontal scrollbar for the ~400ms before it animates in.
   `clip`, never `hidden` -- hidden makes body a scroll container, which kills
   position: sticky on the header, the call bar and the services rail. */
body { overflow-x: clip; }

/* ==========================================================================
   26 · PRINT — property managers really do print these pages
   ========================================================================== */
@media print {
  .header__strip, .header__right, .nav-toggle, .callbar, .drawer, .scrim,
  .svcnav, .skip-link, .ba { display: none !important; }
  .site-header { position: static; box-shadow: none; border-block-end: 1px solid #ccc; }
  .section--dark, .site-footer {
    background: #fff !important;
    --surface-0: #fff;
    --surface-1: #fff;
    --text-strong: #000;
    --text-body: #222;
    --text-muted: #444;
    --text-faint: #555;
    --accent: #004dbd;
    --line: #ccc;
    color: #222 !important;
  }
  .site-footer::before, .has-point::after { display: none !important; }
  .js .reveal { opacity: 1 !important; transform: none !important; }
  .js .flow::before, .js .flow .flow__node::after { transform: none !important; }
  .js .map .map__state.is-covered, .js .map .map__label { opacity: 1 !important; transform: none !important; }
  .card, .tile, .quote, .svc, .step, .flow__node { break-inside: avoid; }
  .flow { break-inside: auto; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.75em; word-break: break-all; }
  .ph, .panes-frame { display: none; }
}

/* ==========================================================================
   27 · FORCED COLORS
   ========================================================================== */
@media (forced-colors: active) {
  .btn { border: 2px solid ButtonText; }
  .tile, .card, .quote, .plate, .router__card, .input, .select, .textarea,
  .ba, .flow__badge {
    border: 1px solid CanvasText;
  }
  .eyebrow::before, .ticks li::before, .stat::before, .step__num::before,
  .flow::before, .flow__node::after, .svcnav__link::before { forced-color-adjust: none; }
  /* the map degrades to outlines only -- fill colour carries no meaning that
     the visible state labels do not already carry */
  .map__state.is-covered { fill: Highlight; }
  .ba__divider { background: CanvasText; }
}

/* ==========================================================================
   28 · REDUCED MOTION — must remain the last block in the last stylesheet
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
  .js .reveal { opacity: 1 !important; transform: none !important; }
  .ph img { transform: none !important; }
  .btn:hover, .tile:hover, .card--link:hover, .router__card:hover { transform: none !important; }
  /* Everything below draws itself in with a transform. With motion off they
     have to start finished, not start hidden and snap. */
  .js .flow::before { transform: none !important; }
  .js .flow .flow__node::after { transform: scale(1) !important; }
  .js .stat.reveal::before { transform: none !important; }
  .js .map .map__state.is-covered, .js .map .map__label {
    opacity: 1 !important;
    transform: none !important;
  }
  .svcnav__link.is-active::before { transform: scaleY(1) !important; }
  .ba.is-sweeping { transition: none !important; }
}
