/* tokens.css is linked separately in the HTML head so the two sheets
   download in parallel. An @import here would chain them and delay LCP. */

/* ==========================================================================
   1 · Reset and base
   ========================================================================== */

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text-body);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, picture, svg { display: block; max-width: 100%; }
img { height: auto; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--text);
  margin: 0;
  text-wrap: balance;
}
h1 { font-size: var(--fs-display); font-weight: 800; font-stretch: 108%;
     line-height: var(--lh-tight); letter-spacing: var(--tr-tight); }
h2 { font-size: var(--fs-h2); font-weight: 700; line-height: var(--lh-head);
     letter-spacing: -0.018em; }
h3 { font-size: var(--fs-h3); font-weight: 600; line-height: 1.15;
     letter-spacing: -0.01em; }
h4 { font-size: var(--fs-h4); font-weight: 600; line-height: 1.3; }

p { margin: 0 0 var(--s-4); max-width: var(--measure); }
/* A paragraph directly after a heading needs air, wherever it sits. */
h1 + p, h2 + p, h3 + p { margin-top: var(--s-4); }
p:last-child { margin-bottom: 0; }
strong { color: var(--text); font-weight: 700; }

a { color: var(--accent-type); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--ink); }

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
}
::selection { background: var(--accent); color: var(--on-accent); }

.skip {
  position: absolute; left: var(--s-4); top: -100px; z-index: 999;
  background: var(--ink); color: var(--text-on-dark);
  padding: var(--s-3) var(--s-5); font-family: var(--font-display);
  font-weight: 700; font-size: var(--fs-small); text-decoration: none;
  transition: top var(--t-press) var(--ease-out);
}
.skip:focus { top: var(--s-4); color: var(--text-on-dark); }

.container { width: 100%; max-width: var(--container); margin-inline: auto;
             padding-inline: var(--gutter); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ==========================================================================
   2 · Shared pieces
   ========================================================================== */

.eyebrow {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--accent-type);
  margin: 0 0 var(--s-4);
}
.eyebrow--on-dark { color: var(--text-on-dark); }

.lead { font-size: var(--fs-lead); color: var(--text); max-width: 58ch; }

.section { padding-block: var(--section-y); }
/* The header is sticky at 72px, so an anchor jump has to stop short of it or
   the first line of the section lands underneath. */
main section[id] { scroll-margin-top: 88px; }
.section--alt { background: var(--bg-alt); }
.section--dark { background: var(--bg-dark); color: var(--text-on-dark-2); }
.section--dark h2, .section--dark h3, .section--dark h4 { color: var(--text-on-dark); }

.section-head { margin-bottom: var(--s-8); max-width: 62ch; }
.section-head h2 + p { margin-top: var(--s-4); }

/* A red rule that reads as an accent without ever becoming red type. */
.rule-accent { width: 56px; height: 3px; background: var(--accent); border: 0;
               margin: 0 0 var(--s-5); }

/* ==========================================================================
   3 · Buttons
   ========================================================================== */

.btn {
  --btn-bg: var(--accent);
  --btn-fg: var(--on-accent);
  display: inline-flex; align-items: center; gap: var(--s-3);
  padding: 15px var(--s-6);
  background: var(--btn-bg); color: var(--btn-fg);
  font-family: var(--font-display); font-weight: 700; font-size: 1rem;
  letter-spacing: 0.005em; text-decoration: none; border: 2px solid var(--btn-bg);
  border-radius: var(--radius); cursor: pointer; min-height: 52px;
  transition: background var(--t-press) var(--ease-out),
              border-color var(--t-press) var(--ease-out),
              color var(--t-press) var(--ease-out),
              transform var(--t-press) var(--ease-press);
}
.btn:hover { --btn-bg: var(--brand-red-deep); color: var(--on-accent);
             transform: translateY(-1px); }
.btn:active { transform: translateY(0) scale(0.985); }

.btn--ghost {
  --btn-bg: transparent; --btn-fg: var(--ink);
  border-color: var(--ink);
}
.btn--ghost:hover { --btn-bg: var(--ink); --btn-fg: var(--surface); color: var(--surface); }

.btn--on-dark { --btn-bg: transparent; --btn-fg: var(--text-on-dark);
                border-color: var(--text-on-dark); }
.btn--on-dark:hover { --btn-bg: var(--surface); --btn-fg: var(--ink); color: var(--ink); }

.btn__icon { width: 18px; height: 18px; flex: none;
             transition: transform var(--t-press) var(--ease-out); }
.btn:hover .btn__icon { transform: translateX(3px); }

/* ==========================================================================
   4 · Header
   ========================================================================== */

.header {
  position: sticky; top: 0; z-index: var(--z-header);
  background: var(--surface);
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-press) var(--ease-out),
              box-shadow var(--t-press) var(--ease-out);
}
.header.is-stuck {
  border-bottom-color: var(--hairline);
  box-shadow: 0 1px 0 rgba(18, 17, 16, 0.04), 0 8px 24px -18px rgba(18, 17, 16, 0.5);
}
.header__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-5); min-height: 72px; padding-block: var(--s-3);
}
.brand { display: flex; align-items: center; gap: var(--s-3); text-decoration: none; }
.brand img { width: auto; height: 42px; }
/* The reverse-out logo only comes out while the menu has turned the bar dark. */
.brand__reverse { display: none; }
.is-menu-open .brand__default { display: none; }
.is-menu-open .brand__reverse { display: block; }

.nav { display: none; }
.nav ul { display: flex; align-items: center; gap: var(--s-6);
          list-style: none; margin: 0; padding: 0; }
.nav a {
  position: relative; font-family: var(--font-display); font-weight: 600;
  font-size: 0.9375rem; color: var(--ink); text-decoration: none; padding-block: 6px;
}
.nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--accent); transform: scaleX(0); transform-origin: left;
  transition: transform var(--t-press) var(--ease-out);
}
.nav a:hover::after, .nav a:focus-visible::after { transform: scaleX(1); }
/* Five items plus the phone number wrap onto two lines right at the point the
   desktop nav appears, so it tightens up until there is room. */
@media (min-width: 760px) and (max-width: 899px) {
  .nav ul { gap: var(--s-4); }
  .nav a { font-size: 0.875rem; }
}

.header__cta { display: flex; align-items: center; gap: var(--s-3); }
.header__phone { display: none; }

/* ---- Menu button (phone and small tablet only) --------------------------- */

.navtoggle {
  display: inline-flex; align-items: center; gap: 10px;
  min-height: 44px; min-width: 44px; padding: 0 var(--s-3) 0 var(--s-4);
  margin-right: calc(var(--s-3) * -1);
  background: none; border: 0; cursor: pointer;
  font-family: var(--font-display); font-weight: 700;
  font-size: var(--fs-label); letter-spacing: var(--tr-label);
  text-transform: uppercase; color: var(--ink);
  transition: color var(--t-press) var(--ease-out);
}
.is-menu-open .navtoggle { color: var(--text-on-dark); }

.navtoggle__box { position: relative; width: 22px; height: 14px; flex: none; }
.navtoggle__bar {
  position: absolute; left: 0; width: 100%; height: 2px;
  background: currentColor;
  transition: transform var(--t-press) var(--ease-out),
              opacity var(--t-fast) var(--ease-out);
}
.navtoggle__bar:nth-child(1) { top: 0; }
.navtoggle__bar:nth-child(2) { top: 6px; }
.navtoggle__bar:nth-child(3) { top: 12px; }
.is-menu-open .navtoggle__bar:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.is-menu-open .navtoggle__bar:nth-child(2) { opacity: 0; }
.is-menu-open .navtoggle__bar:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* ---- Menu sheet ---------------------------------------------------------
   Covers the page from under the sticky bar down. The bar itself stays put
   and turns dark, so the logo and the close control never move. */

.header.is-menu-open,
.header.is-menu-open.is-stuck {
  background: var(--bg-dark); border-bottom-color: transparent; box-shadow: none;
}

.menu {
  position: fixed; inset: 0; z-index: var(--z-menu);
  display: flex; flex-direction: column;
  padding: calc(72px + var(--s-7)) var(--gutter)
           calc(var(--s-7) + env(safe-area-inset-bottom, 0px));
  background: var(--bg-dark); color: var(--text-on-dark-2);
  overflow-y: auto; overscroll-behavior: contain;
  visibility: hidden; opacity: 0;
  transition: opacity var(--t-press) var(--ease-out),
              visibility 0s linear var(--t-press);
}
.menu.is-open {
  visibility: visible; opacity: 1;
  transition: opacity var(--t-press) var(--ease-out), visibility 0s;
}
/* display:flex would otherwise beat the hidden attribute. */
.menu[hidden] { display: none; }

/* The page behind the sheet must not scroll with it. */
body.is-menu-locked { overflow: hidden; }

/* The rows share out whatever height is left, so the sheet fills a tall phone
   without a dead gap above the call button and still fits a short one. */
.menu__mid { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.menu__mid nav { flex: 1; display: flex; }

.menu__nav {
  flex: 1; list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column;
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}
.menu__nav li { flex: 1 1 auto; display: flex;
                border-bottom: 1px solid rgba(255, 255, 255, 0.14); }
.menu__nav a {
  position: relative; flex: 1; display: flex; align-items: center;
  min-height: 62px; padding: var(--s-4) 0 var(--s-4) var(--s-5);
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.5rem, 6.6vw, 2rem); line-height: 1.15;
  letter-spacing: var(--tr-tight); color: var(--text-on-dark); text-decoration: none;
}
/* Red is a fill here, never type: it fails AA as type on this ground. */
.menu__nav a::before {
  content: ""; position: absolute; left: 0; top: 50%; translate: 0 -50%;
  width: 3px; height: 0; background: var(--accent);
  transition: height var(--t-press) var(--ease-out);
}
.menu__nav a:hover::before,
.menu__nav a:focus-visible::before,
.menu__nav a:active::before { height: 60%; }

/* Each row arrives a beat after the one above it. */
.menu.is-open .menu__nav li { animation: menu-row var(--t-enter) var(--ease-out) backwards; }
.menu.is-open .menu__nav li:nth-child(1) { animation-delay:  40ms; }
.menu.is-open .menu__nav li:nth-child(2) { animation-delay:  90ms; }
.menu.is-open .menu__nav li:nth-child(3) { animation-delay: 140ms; }
.menu.is-open .menu__nav li:nth-child(4) { animation-delay: 190ms; }
@keyframes menu-row {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

.menu__where {
  margin: var(--s-6) 0 0; font-size: var(--fs-small);
  color: var(--text-on-dark-2); max-width: 34ch;
}
.menu__where b { color: var(--text-on-dark); font-family: var(--font-display); }

.menu__foot { padding-top: var(--s-7); }
.menu__foot .btn { display: flex; justify-content: center; width: 100%; }
.menu__note { margin: var(--s-4) 0 0; font-size: var(--fs-small);
              color: var(--text-on-dark-2); max-width: 34ch; }
.menu__note b { color: var(--text-on-dark); font-family: var(--font-display); }
.menu__mail { color: var(--text-on-dark); text-decoration: underline;
              text-underline-offset: 3px; }

/* Phone-width call bar. It sits in the thumb zone at the bottom rather than
   fighting the sticky header for the top of the screen. */
.callbar {
  position: fixed; inset-inline: 0; bottom: 0; z-index: var(--z-callbar);
  display: grid; grid-template-columns: 1fr 1fr;
  background: var(--ink);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  box-shadow: 0 -8px 24px -18px rgba(18, 17, 16, 0.9);
}
.callbar a {
  display: flex; align-items: center; justify-content: center; gap: var(--s-2);
  min-height: 54px; padding: var(--s-3);
  font-family: var(--font-display); font-weight: 700; font-size: 0.9375rem;
  text-decoration: none; color: var(--text-on-dark);
  transition: background var(--t-press) var(--ease-out);
}
.callbar a:first-child { background: var(--accent); }
.callbar a:first-child:hover { background: var(--brand-red-deep); color: var(--text-on-dark); }
.callbar a:last-child:hover { background: var(--ink-soft); color: var(--text-on-dark); }
.callbar svg { width: 17px; height: 17px; flex: none; }

/* Room for the fixed call bar so it never covers the end of the page. */
@media (max-width: 759px) {
  body { padding-bottom: calc(54px + env(safe-area-inset-bottom, 0px)); }
}

@media (min-width: 760px) {
  .callbar { display: none; }
  body { padding-bottom: 0; }
  .nav { display: block; }
  .navtoggle, .menu { display: none; }
  .brand img { height: 50px; }
  .header__phone {
    display: inline-flex; align-items: center; gap: var(--s-2);
    font-family: var(--font-display); font-weight: 700; font-size: 1.0625rem;
    color: var(--ink); text-decoration: none;
  }
  .header__phone:hover { color: var(--brand-red-deep); }
  .header__phone svg { width: 17px; height: 17px; }
}

/* ==========================================================================
   5 · Hero
   ========================================================================== */

.hero { padding-block: clamp(40px, 6vw, 88px) clamp(56px, 8vw, 112px); }
.hero__grid { display: grid; gap: clamp(32px, 5vw, 64px); align-items: center; }
.hero h1 { margin-bottom: var(--s-5); }
.hero h1 .line { display: block; }
.hero__sub { font-size: var(--fs-lead); color: var(--text-body); max-width: 46ch;
             margin-bottom: var(--s-7); }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-bottom: var(--s-4); }
.hero__micro { font-size: var(--fs-small); color: var(--text-body); }
.hero__micro strong { color: var(--ink); }

@media (min-width: 900px) {
  .hero__grid { grid-template-columns: 1fr 1fr; gap: clamp(48px, 6vw, 88px); }
}
@media (min-width: 1120px) {
  .hero__grid { grid-template-columns: 1.05fr 1fr; }
}

/* ==========================================================================
   6 · Before / after slider
   ========================================================================== */

.compare { --pos: 50%; max-width: 560px; }
@media (min-width: 900px) { .compare { max-width: none; } }
.compare__frame {
  position: relative; overflow: hidden;
  aspect-ratio: 4 / 5; background: var(--bg-alt);
  border: 1px solid var(--hairline-strong);
  touch-action: pan-y;
  user-select: none; -webkit-user-select: none;
  cursor: ew-resize;
}
.compare__img { position: absolute; inset: 0; width: 100%; height: 100%; }
.compare__img img { width: 100%; height: 100%; object-fit: cover; }
/* The BEFORE photo sits on top, clipped to the left of the divider.
   clip-path is composited, so dragging stays on the GPU. */
.compare__img--before { clip-path: inset(0 calc(100% - var(--pos)) 0 0); }

.compare__divider {
  position: absolute; top: 0; bottom: 0; left: var(--pos);
  width: 3px; margin-left: -1.5px; background: var(--accent);
  pointer-events: none;
}
.compare__handle {
  position: absolute; top: 50%; left: var(--pos);
  transform: translate(-50%, -50%);
  width: 56px; height: 56px; border-radius: 50%;
  display: grid; place-items: center; gap: 0;
  background: var(--surface); border: 3px solid var(--accent);
  color: var(--ink); cursor: grab; padding: 0;
  touch-action: none;
  transition: transform var(--t-press) var(--ease-press),
              background var(--t-press) var(--ease-out);
}
.compare__handle:hover { transform: translate(-50%, -50%) scale(1.06); }
.compare__handle:active { cursor: grabbing; transform: translate(-50%, -50%) scale(0.96); }
.compare__handle svg { width: 26px; height: 26px; pointer-events: none; }
.compare__handle::after {
  content: ""; position: absolute; inset: -3px; border-radius: 50%;
  border: 3px solid var(--accent); opacity: 0; pointer-events: none;
}
.compare.is-sweeping .compare__handle::after { animation: pulse 900ms var(--ease-out) 1; }
@keyframes pulse {
  from { opacity: 0.85; transform: scale(1); }
  to   { opacity: 0;    transform: scale(1.9); }
}

.compare__tag {
  position: absolute; top: var(--s-4);
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-label);
  letter-spacing: var(--tr-label); text-transform: uppercase;
  padding: 7px 11px; pointer-events: none;
  transition: opacity var(--t-press) var(--ease-out);
}
.compare__tag--before { left: var(--s-4); background: var(--ink); color: var(--text-on-dark); }
.compare__tag--after  { right: var(--s-4); background: var(--accent); color: var(--on-accent); }

.compare__caption {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4);
  justify-content: space-between; align-items: baseline;
  margin-top: var(--s-4); font-size: var(--fs-small); color: var(--text-body);
}
.compare__caption b { font-family: var(--font-display); color: var(--ink); font-weight: 700; }

/* ==========================================================================
   7 · Gallery, services, steps
   ========================================================================== */

.split { display: grid; gap: clamp(32px, 5vw, 72px); }
@media (min-width: 900px) { .split { grid-template-columns: 5fr 7fr; } }

/* Two client photos, shown large. The grid is written so a third and fourth
   photo drop straight in without touching this block. */
.gallery {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: clamp(24px, 3.5vw, 48px);
}
@media (min-width: 760px) { .gallery { grid-template-columns: 1fr 1fr; } }

.gallery__item { margin: 0; }

.gallery__frame {
  position: relative; overflow: hidden;
  aspect-ratio: 4 / 5; background: var(--hairline);
  border-radius: var(--radius);
}
.gallery__frame img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform var(--t-slow) var(--ease-out);
}
@media (hover: hover) {
  .gallery__item:hover .gallery__frame img { transform: scale(1.035); }
}

/* Same treatment as the tags on the hero slider, so the two read as one set. */
.gallery__tag {
  position: absolute; top: var(--s-4); left: var(--s-4);
  padding: 6px var(--s-3);
  font-family: var(--font-display); font-weight: 700;
  font-size: var(--fs-label); letter-spacing: var(--tr-label);
  text-transform: uppercase;
}
.gallery__tag--before { background: var(--ink); color: var(--text-on-dark); }
.gallery__tag--after  { background: var(--accent); color: var(--on-accent); }

.gallery figcaption {
  margin-top: var(--s-4); padding-top: var(--s-4); border-top: var(--rule);
  font-size: var(--fs-small); color: var(--text-body);
}
.gallery figcaption b {
  font-family: var(--font-display); color: var(--ink); font-weight: 700;
}

/* ---- Photo gallery ------------------------------------------------------
   Photos only, no captions. Masonry columns so ten frames shot at four
   different shapes keep their own proportions instead of being cropped to
   one ratio. */

.photos {
  list-style: none; margin: 0; padding: 0;
  columns: 1; column-gap: clamp(16px, 2.2vw, 24px);
}
@media (min-width: 700px)  { .photos { columns: 2; } }
@media (min-width: 1000px) { .photos { columns: 3; } }

.photos li { break-inside: avoid; margin-bottom: clamp(16px, 2.2vw, 24px); }
.photos picture {
  display: block; overflow: hidden;
  border-radius: var(--radius); background: var(--hairline);
}
.photos img {
  width: 100%; height: auto; display: block;
  transition: transform var(--t-slow) var(--ease-out);
}
@media (hover: hover) { .photos li:hover img { transform: scale(1.035); } }

.services { list-style: none; margin: 0; padding: 0; border-top: 2px solid var(--ink); }
.services li { border-bottom: var(--rule); }
.services__row {
  display: grid; gap: var(--s-2); align-items: baseline;
  padding: var(--s-5) 0;
  transition: padding-left var(--t-press) var(--ease-out);
}
@media (min-width: 760px) {
  .services__row { grid-template-columns: 1fr 1.35fr; gap: var(--s-6); }
  .services li:hover .services__row { padding-left: var(--s-3); }
}
.services__row h3 { font-size: var(--fs-h3); }
.services__row p { margin: 0; }
.services__lead h3 { color: var(--accent-type); }

.steps { list-style: none; margin: 0; padding: 0; position: relative; }
.steps::before {
  content: ""; position: absolute; left: 15px; top: 8px; bottom: 8px; width: 2px;
  background: var(--hairline); transform: scaleY(0); transform-origin: top;
  transition: transform 700ms var(--ease-inout);
}
.is-revealed .steps::before { transform: scaleY(1); }
.steps li { position: relative; padding: 0 0 var(--s-7) 56px; }
.steps li:last-child { padding-bottom: 0; }
.steps__num {
  position: absolute; left: 0; top: 0;
  width: 32px; height: 32px; display: grid; place-items: center;
  background: var(--accent); color: var(--on-accent);
  font-family: var(--font-display); font-weight: 700; font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
}
.steps h3 { margin-bottom: var(--s-2); }
.steps p { margin: 0; }

/* ==========================================================================
   8 · Review
   ========================================================================== */

.stars { display: flex; gap: 3px; margin-bottom: var(--s-4); }
.stars svg { width: 22px; height: 22px; color: var(--accent);
             opacity: 0; transform: scale(0.6); }
.is-revealed .stars svg { animation: star-in 380ms var(--ease-press) forwards; }
.stars svg:nth-child(1) { animation-delay: 60ms; }
.stars svg:nth-child(2) { animation-delay: 130ms; }
.stars svg:nth-child(3) { animation-delay: 200ms; }
.stars svg:nth-child(4) { animation-delay: 270ms; }
.stars svg:nth-child(5) { animation-delay: 340ms; }
@keyframes star-in { to { opacity: 1; transform: scale(1); } }

/* Cards inside the marquee never cross a reveal threshold, so their stars have
   to start visible rather than waiting for .is-revealed. */
.stars--static svg { opacity: 1; transform: none; animation: none; }

/* ---- Review marquee -----------------------------------------------------
   The cards run right to left on one linear loop. The track holds the same
   two reviews twice and shifts by exactly half its width, so the seam lands
   where the first set began and never shows. */

.section--marquee { padding-bottom: clamp(48px, 6vw, 88px); }
.section--marquee .section-head { margin-bottom: clamp(32px, 4vw, 56px); }

.marquee {
  overflow: hidden;
  /* A fixed 48px softener at each edge, so cards enter and leave rather than
     being chopped. In px, not a percentage: a percentage ramp gets wide enough
     on a desktop to dim a whole card. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 48px,
                        #000 calc(100% - 48px), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 48px,
                        #000 calc(100% - 48px), transparent 100%);
}
/* The duration is rewritten by app.js so the cards travel at the same speed on
   a phone as on a desktop. This value is the fallback if the script is off. */
.marquee__track {
  display: flex; width: max-content;
  animation: marquee-left var(--marquee-duration, 30s) linear infinite;
}
@keyframes marquee-left {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
/* Hovering or tabbing into a card holds it still long enough to read. */
.marquee:hover .marquee__track,
.marquee:focus-within .marquee__track { animation-play-state: paused; }

.marquee__set {
  list-style: none; margin: 0; padding: 0 0 0 var(--gutter);
  display: flex; gap: var(--gutter);
}

.rcard {
  flex: none; width: min(560px, 84vw);
  padding: var(--s-6);
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(255, 255, 255, 0.03);
  border-radius: var(--radius);
}
.rcard blockquote { margin: 0; display: flex; flex-direction: column; height: 100%; }
.rcard p {
  font-family: var(--font-display); font-weight: 500;
  font-size: 1.0625rem; line-height: 1.5; color: var(--text-on-dark);
  max-width: none; margin: 0 0 var(--s-4);
}
.rcard footer {
  margin-top: auto; padding-top: var(--s-5);
  border-top: 3px solid var(--accent);
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-label);
  letter-spacing: var(--tr-label); text-transform: uppercase;
  color: var(--text-on-dark-2); align-self: flex-start;
}
.rcard footer b { color: var(--text-on-dark); }

@media (min-width: 900px) { .rcard p { font-size: 1.125rem; } }

.why { list-style: none; margin: 0; padding: 0; display: grid; gap: 0;
       border-top: var(--rule); }
@media (min-width: 760px) { .why { grid-template-columns: 1fr 1fr; column-gap: var(--s-8); } }
.why li { padding: var(--s-6) 0; border-bottom: var(--rule); }
.why h3 { margin-bottom: var(--s-2); }
.why p { margin: 0; }

/* ==========================================================================
   9 · Service area
   ========================================================================== */

.area__list {
  list-style: none; margin: var(--s-6) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-3);
}
.area__list li {
  font-family: var(--font-display); font-weight: 600; font-size: 0.9375rem;
  padding: 9px var(--s-4); border: 1px solid var(--hairline-strong);
  border-radius: var(--radius); color: var(--ink);
}

/* ==========================================================================
   10 · Form
   ========================================================================== */

.form__grid { display: grid; gap: clamp(32px, 5vw, 72px); align-items: start; }
@media (min-width: 900px) { .form__grid { grid-template-columns: 5fr 7fr; } }

.field { display: grid; gap: var(--s-2); margin-bottom: var(--s-5); }
.field label {
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-label);
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--ink);
}
.field .hint { font-size: var(--fs-small); color: var(--text-body); }
.field input, .field select, .field textarea {
  width: 100%; padding: 14px var(--s-4);
  font-family: var(--font-body); font-size: 1rem; color: var(--ink);
  background: var(--surface); border: 1px solid var(--hairline-strong);
  border-radius: var(--radius); min-height: 52px;
  transition: border-color var(--t-fast) var(--ease-out),
              box-shadow var(--t-fast) var(--ease-out);
}
.field textarea { min-height: 132px; resize: vertical; line-height: 1.55; }
.field select { appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%234F5159' stroke-width='1.6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 18px center;
  background-size: 12px; padding-right: 44px; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--steel); }
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink); outline-offset: 2px;
}
.field .error { font-size: var(--fs-small); color: var(--error); font-weight: 500; min-height: 0; }
.field[data-invalid="true"] input,
.field[data-invalid="true"] select,
.field[data-invalid="true"] textarea { border-color: var(--error); box-shadow: inset 0 0 0 1px var(--error); }

.form__foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4); }
.form__foot .or { font-size: var(--fs-small); }
/* Phone numbers written into a sentence still deserve a real hit area. */
.form__foot .or a, .footer__qr a { display: inline-block; padding-block: 6px; }
.form__status { margin-top: var(--s-5); }
.form__status:empty { margin-top: 0; }
.notice { padding: var(--s-4) var(--s-5); border-left: 4px solid var(--accent);
          background: var(--bg-alt); font-size: var(--fs-small); }
.notice--ok { border-left-color: var(--success-fg); background: var(--success-bg);
              color: var(--success-fg); }
.notice--ok b { color: var(--success-fg); }

.contact-card { border-top: 2px solid var(--ink); margin-top: var(--s-7); }
.contact-card dl { margin: 0; }
.contact-card div { padding: var(--s-5) 0; border-bottom: var(--rule); }
.contact-card dt {
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-label);
  letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--text-body);
  margin-bottom: var(--s-2);
}
.contact-card dd { margin: 0; font-family: var(--font-display); font-weight: 700;
                   font-size: var(--fs-h3); }
.contact-card dd a { color: var(--ink); text-decoration: none;
                     display: inline-block; padding-block: 4px; }
.contact-card dd a:hover { color: var(--brand-red-deep); }
.contact-card dd.small { font-size: 1.0625rem; font-weight: 600; }

/* ==========================================================================
   11 · Footer
   ========================================================================== */

.footer { background: var(--ink); color: var(--text-on-dark-2); padding-block: var(--s-10) var(--s-7); }
.footer a { color: var(--text-on-dark); }
.footer a:hover { color: var(--text-on-dark-2); }
.footer__grid { display: grid; gap: var(--s-8); }
@media (min-width: 760px) { .footer__grid { grid-template-columns: 1.4fr 1fr 1fr; } }
/* The footer uses a reverse-out version of the mark, so it sits straight on
   the ink with no white chip behind it. */
.footer__logo { display: inline-block; }
.footer__logo img { height: 72px; width: auto; }
.footer h3 { color: var(--text-on-dark); font-size: var(--fs-label);
             letter-spacing: var(--tr-label); text-transform: uppercase;
             font-weight: 700; margin-bottom: var(--s-4); }
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-3); }
.footer ul a, .footer__base a { display: inline-block; padding-block: 4px; }

/* On a phone these become real thumb targets rather than thin text links. */
@media (max-width: 759px) {
  .footer ul { gap: var(--s-1); }
  .footer ul a { display: block; padding-block: 11px; }
  .footer__base a { padding-block: 10px; }
}
.footer__qr { display: flex; gap: var(--s-4); align-items: flex-start; margin-top: var(--s-6); }
.footer__qr img { width: 128px; height: 128px; background: var(--surface); padding: 6px; }
.footer__qr div { font-size: var(--fs-small); max-width: 30ch; }
/* The number sits on its own line at every width, so it never runs to the edge
   of the measure on desktop. */
.footer__qr strong { display: block; }
.footer__base {
  margin-top: var(--s-9); padding-top: var(--s-5);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-5);
  justify-content: space-between; font-size: var(--fs-small);
}

/* ==========================================================================
   12 · Motion · reveals
   ========================================================================== */

.reveal { opacity: 0; transform: translateY(22px); }
.reveal.is-revealed {
  opacity: 1; transform: none;
  transition: opacity var(--t-enter) var(--ease-out),
              transform var(--t-enter) var(--ease-out);
  transition-delay: var(--delay, 0ms);
}

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal.is-revealed { opacity: 1; transform: none; transition: none; }
  .steps::before { transform: scaleY(1); transition: none; }
  .gallery__frame img { transition: none; }
  .gallery__item:hover .gallery__frame img { transform: none; }
  .photos img { transition: none; }
  .photos li:hover img { transform: none; }
  .stars svg { opacity: 1; transform: none; animation: none; }
  /* No auto-scroll. The reviews become a row you push yourself, and the
     duplicate set goes away so nothing reads twice. */
  .marquee { overflow-x: auto; -webkit-mask-image: none; mask-image: none;
             scroll-snap-type: x proximity; }
  .marquee__track { animation: none; width: auto; }
  .marquee__set[aria-hidden="true"] { display: none; }
  .marquee__set { padding-right: var(--gutter); }
  .rcard { scroll-snap-align: start; }
  .menu, .menu.is-open { transition: none; }
  .menu.is-open .menu__nav li { animation: none; }
  .navtoggle__bar { transition: none; }
  .compare.is-sweeping .compare__handle::after { animation: none; }
  .btn, .btn__icon, .compare__handle, .nav a::after, .services__row { transition: none; }
  .btn:hover, .btn:active, .compare__handle:hover, .compare__handle:active { transform: none; }
  .compare__handle:active { transform: translate(-50%, -50%); }
  .compare__handle, .compare__handle:hover { transform: translate(-50%, -50%); }
}
