:root {
  /* chassis contract */
  --cx-fg: #1c2420; --cx-bg: #f4f2ec; --cx-accent: #2f6b4f; --cx-line: #d6d5cf;
  --cx-font-body: 'Public Sans', sans-serif; --cx-font-display: 'Archivo Black', sans-serif;
  /* Type in rem (audit F53): identical at the default 16px, and it follows a visitor who set a larger
     default font size, which px ignored. The vw term only moves within the rem bounds. */
  --cx-body: clamp(1rem, 1.05vw, 1.125rem);
  --cx-h1: clamp(2.375rem, 6.4vw, 5.25rem); --cx-h2: clamp(1.75rem, 3.6vw, 3rem); --cx-h3: clamp(1.1875rem, 1.6vw, 1.5rem);
  --cx-gap: 24px; --cx-wrap: 1240px; --cx-measure: 32em;
  --sp-gutter: clamp(16px, 12px + 2.2vw, 64px);
  --sp-section-compact: clamp(32px, 20.11px + 3.0476vw, 64px);
  --sp-section-standard: clamp(48px, 30.17px + 4.5714vw, 96px);
  --sp-section-generous: clamp(64px, 40.23px + 6.0952vw, 128px);
  --sp-eyebrow: clamp(8px, 5.77px + 0.5714vw, 14px);
  --sp-head-intro: clamp(14px, 11.03px + 0.7619vw, 22px);
  --sp-intro-content: clamp(28px, 22.06px + 1.5238vw, 44px);
  --sp-para: clamp(14px, 12.51px + 0.381vw, 18px);
  --sp-text-buttons: clamp(22px, 19.03px + 0.7619vw, 30px);
  --sp-buttons: clamp(12px, 11.26px + 0.1905vw, 14px);
  --sp-card-gap: clamp(18px, 14.29px + 0.9524vw, 28px);
  --sp-card-inset: clamp(20px, 17.03px + 0.7619vw, 28px);
  --sp-columns: clamp(28px, 17.6px + 2.6667vw, 56px);
  --sp-caption: 10px;
  --sp-form-label: 7px;
  --sp-form-group: 22px;
  --cx-band: var(--sp-section-standard);
  --cx-radius: 2px; --cx-radius-media: 6px;
  --cx-head-h: 74px; --cx-bar-h: 64px;
  /* renderer */
  --r-accent: #2f6b4f; --r-on-accent: #ffffff;
  --r-ground: #f4f2ec; --r-ink: #1c2420;
  --r-inverse-bg: #1c2420; --r-inverse-fg: #ffffff; --r-inverse-muted: #a9acaa; --r-inverse-line: #3c433f; --r-inverse-accent: #4e8169;
  --r-inverse-accent-text: #7aa18f;
  --r-display: 'Archivo Black', sans-serif; --r-body: 'Public Sans', sans-serif;
  --r-display-weight: 400; --r-display-tracking: 0.005em;
  --r-eyebrow: .8125rem; --r-micro: .75rem;
  --r-case-display: none; --r-case-label: uppercase;
  --r-bg: #f4f2ec; --r-surface: #ebeae4; --r-fg: #1c2420; --r-muted: #666a66; --r-line: #d6d5cf; --r-accent: #2f6b4f; --r-on-accent: #ffffff; --r-accent-text: #2f6b4f;
}
[data-theme="light"] {
  --r-bg: #f4f2ec; --r-surface: #ebeae4; --r-fg: #1c2420; --r-muted: #666a66; --r-line: #d6d5cf; --r-accent: #2f6b4f; --r-on-accent: #ffffff; --r-accent-text: #2f6b4f;
}
[data-theme="dark"] {
  --r-bg: #1c2420; --r-surface: #252d29; --r-fg: #ffffff; --r-muted: #a9acaa; --r-line: #3c433f; --r-accent: #4e8169; --r-on-accent: #ffffff; --r-accent-text: #7aa18f;
}
[data-theme="brand"] {
  --r-bg: #1c2420; --r-surface: #252d29; --r-fg: #ffffff; --r-muted: #a9acaa; --r-line: #3c433f; --r-accent: #4e8169; --r-on-accent: #ffffff; --r-accent-text: #7aa18f;
}
[data-theme="accent"] {
  --r-bg: #2f6b4f; --r-surface: #2f6b4f; --r-fg: #ffffff; --r-muted: #ffffff; --r-line: #ffffff; --r-accent-text: #ffffff;
}

@font-face { font-family: 'Archivo Black'; font-style: normal; font-weight: 400; font-display: swap; src: url('/assets/fonts/archivo-black/archivo-black-400.woff2') format('woff2'); }
@font-face { font-family: 'Public Sans'; font-style: normal; font-weight: 300 800; font-display: swap; src: url('/assets/fonts/public-sans/public-sans-300-800.woff2') format('woff2'); }


.r-cols-1, .r-cols-2, .r-cols-3, .r-cols-4 { display: grid; }
@media (max-width: 719px) { .r-cols-1, .r-cols-2, .r-cols-3, .r-cols-4 { grid-template-columns: minmax(0, 1fr); } }
@media (min-width: 720px) {
  .r-cols-1 { grid-template-columns: minmax(0, 1fr); }
  .r-cols-2, .r-cols-3, .r-cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Three or nine cards in two columns leave a hole beside the last one (audit F46: measured on both
   sites between 720 and 999px). On that tier the odd last card takes the whole row, which reads as a
   choice; the bare half-row never did. */
@media (min-width: 720px) and (max-width: 999px) {
  .r-cols-3 > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (min-width: 1000px) {
  .r-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* Four across, on ONE row. Four is a divisor like any other, and leaving it out of the list sent four
     steps into a two-by-two block that looked right and was not: a skin removes the right border from
     the LAST card because in a single row that edge is the section's own edge, and in two rows the last
     card sits at the right-hand end of the second row with its box left open. The idiom is the skin's
     to write; the row count is the renderer's to choose, and choosing two rows for four cards broke it. */
  .r-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* No divisor: a flex row whose last line grows into whatever is left, so there is never bare ground
   under the cards. Wider cards on the last line read as deliberate; a hole never does. */
.r-cols-fill { display: flex; flex-wrap: wrap; }
.r-cols-fill > * { flex: 1 1 320px; min-width: 0; }

/* ---- shared components (renderer) ---- */
.r-section { padding-block: var(--cx-band); background: var(--r-bg); color: var(--r-fg); }
/* Per-section density (spec section.density): the band is redefined on the section itself, so its own
   padding and anything inside that reads --cx-band move together. */
section[data-density="tight"] { --cx-band: var(--sp-section-compact); }
section[data-density="open"] { --cx-band: var(--sp-section-generous); }
/* One owner for the gap between two sections on the same ground (the owner's rule 3). Two full insets
   meet there with nothing to separate them, so the space reads as a hole rather than a pause: the second
   section starts at half its inset, and the seam is one and a half insets. A change of ground is its own
   separation and keeps both. Which joins share a ground is MEASURED after the skin is applied
   (studio/tools/seams.mjs marks them), because a skin paints its own grounds and the theme attribute
   cannot tell white from pale blue. */
.r-section[data-seam="joined"] { padding-top: calc(var(--cx-band) * .5); }
/* The join was measured with an optional section hidden (no reviews yet). Once it shows, it stands
   between the two again and the section after it takes its full inset back. */
:is(.r-reviews--optional, .r-rail--optional):not(:has([data-skyhq="testimonials"]:empty)) + .r-section[data-seam="joined"] { padding-top: var(--cx-band); }
/* A flush section means its own content reaches the band's edges, not that the band has no
   rhythm: with padding-block 0 the services ledger sat at half the vertical space of every other
   section on the site and the page read as a different document. The band keeps the site's rhythm;
   what is flush is the content inside it. */
.r-section--flush { padding-block: var(--cx-section-pad, clamp(52px, 7vw, 100px)); }
.r-eyebrow { display: inline-flex; align-items: center; gap: 12px; margin: 0 0 var(--sp-eyebrow, 12px); font-size: var(--r-eyebrow); font-weight: 700; letter-spacing: .22em; text-transform: var(--r-case-label, uppercase); color: var(--r-accent-text); max-width: none; }
/* overflow hidden and flex none: skins draw the rule as an ::after, sometimes wider than the span, and
   it spilled over the first letters of the eyebrow on three builds. A pseudo now clips to the box. */
.r-eyebrow-rule { width: 28px; height: 2px; flex: none; overflow: hidden; background: var(--r-accent); }
/* The head group, one owner per gap: eyebrow to heading (the eyebrow's margin), heading to introduction
   (the heading's margin), introduction to the section's content (the head's margin). */
.r-head { margin-bottom: var(--sp-intro-content, clamp(32px, 4vw, 48px)); }
.r-head h2 { margin: 0 0 var(--sp-head-intro, .5em); }
.r-head > p:last-child, .r-head > .r-lead:last-child { margin-bottom: 0; }
.r-head h2 { font-family: var(--r-display); font-weight: var(--r-display-weight); letter-spacing: var(--r-display-tracking); line-height: 1.02; color: var(--r-fg); }
.r-head--center { text-align: center; margin-inline: auto; }
.r-head--center > :is(h1, h2, h3) { margin-inline: auto; }
.r-head--center .r-eyebrow { justify-content: center; }
.r-head--center .r-eyebrow-rule { display: none; }
.r-head--center p { margin-inline: auto; }
.r-lead { font-size: 1.06em; color: var(--r-muted); }
/* line-height is declared because the same class lands on an <a> and on the form's <button>, and the
   two inherit differently: an anchor takes the body's, a button takes the UA's "normal". That is a 5px
   difference in height between the site's buttons and its submit, on every page that carries a form. */
.r-btn { line-height: 1.62; display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-height: 48px; padding: 0 22px; border-radius: var(--cx-radius); font-size: 0.875rem; font-weight: 800; letter-spacing: .1em; text-transform: var(--r-case-label, uppercase); text-decoration: none; border: 2px solid transparent; transition: transform .2s ease, background .2s ease, color .2s ease; }
.r-btn--solid { background: var(--r-fg); color: var(--r-bg); }
.r-btn--solid:hover { transform: translateY(-1px); }
.r-btn--accent { background: var(--r-accent); color: var(--r-on-accent); }
.r-btn--ghost { background: transparent; color: var(--r-fg); border-color: var(--r-line); }
.r-btn--ghost:hover { border-color: var(--r-fg); }
.r-btn--outline { background: transparent; color: var(--r-fg); border-color: var(--r-fg); }
.r-btn--outline:hover { background: var(--r-fg); color: var(--r-bg); }
.r-btns { display: flex; flex-wrap: wrap; gap: var(--sp-buttons, 14px); }
/* Text to the button group it leads to: the group owns the gap, so the paragraph above gives up its own. */
:is(p, ul, ol):has(+ .r-btns) { margin-bottom: 0; }
:is(p, ul, ol) + .r-btns { margin-top: var(--sp-text-buttons, 24px); }
.r-placeholder { display: grid; place-items: center; min-height: 240px; height: 100%; background: repeating-linear-gradient(135deg, var(--r-surface) 0 12px, var(--r-bg) 12px 24px); border: 1px dashed var(--r-line); border-radius: var(--cx-radius-media); color: var(--r-muted); font-size: 0.875rem; text-align: center; padding: 24px; }
.r-placeholder span { max-width: 26ch; }
/* The shot description reads as a request, never as card copy (audit F16: five service cards showed
   "Pond Construction & Repair in progress, the crew and the equipment in frame" where copy would be).
   12px, the page gate's label floor is 11.5px; 11px here failed every page with a placeholder. */
.r-ph-k { display: block; margin-bottom: 4px; font-size: 0.75rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; }
.r-muted { color: var(--r-muted); }
.r-display { font-family: var(--r-display); font-weight: var(--r-display-weight); letter-spacing: var(--r-display-tracking); }
.r-grid { display: grid; gap: var(--cx-gap); }
.r-grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); }
.r-grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); }
.r-grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); }
.r-hairline { border-top: 1px solid var(--r-line); }
/* Utility pages (404, privacy) have no variant CSS: give their links and footer the site's own colors,
   or a browser-default blue link sits on a dark ground and fails AA. */
.cx-util-head, .cx-util, .cx-foot { color: var(--r-fg); }
.cx-util-head a, .cx-util a, .cx-foot a { color: var(--r-fg); }
.cx-util-head .cx-brand { font-family: var(--r-display); font-weight: var(--r-display-weight); text-decoration: none; }
.cx-foot { color: var(--r-muted); border-top: 1px solid var(--r-line); }
.cx-foot address { font-style: normal; }
/* Below-the-fold sections skip layout and paint until they are near the viewport. Measured on the
   first answer key: the hero's largest paint went from 3.6s to 2.7s on a throttled phone (Lighthouse
   mobile 90 → 96) with no other change; the cost of a long page's first render was the delay. */
main > section:not(:first-child), main > div, footer { content-visibility: auto; contain-intrinsic-size: auto 700px; }
/* Focus: the chassis covers :focus-visible; programmatic focus (what the a11y gate does) must show too. */
a:focus, button:focus, input:focus, select:focus, textarea:focus, summary:focus { outline: 2px solid var(--r-accent); outline-offset: 2px; }
/* The tier motion pass (motion.md M2): a reveal on scroll. The hidden state exists only with JS on
   and only when motion is not reduced, so a crawler, a JS-off render and a reduced-motion visitor all
   get the finished page. Only opacity and transform animate. */
@media (prefers-reduced-motion: no-preference) {
  html.js .r-reveal { opacity: 0; transform: translateY(18px); transition: opacity .6s ease, transform .6s ease; }
  html.js .r-reveal.is-in { opacity: 1; transform: none; }
}
/* The phone bar's clearance under the first screen is NOT here any more: it is a floor (skin-normalize.mjs,
   floorsCss), loaded after the skin so a skin's own hero padding cannot remove it, and scoped to the one
   first screen that is sized to the viewport with the bar visible (the anchored hero between 641 and
   900px). A first version reserved it here on the first section AND on its wrap as a fallback; padding on
   two elements adds, so every phone page carried it twice (164px of dark hero under the stats on the
   third acceptance build, which the look read as content that failed to render). */
/* the mobile action bar: two cells, call and quote, opaque, above everything */
/* min-height, never height: under 200% text or a spacing override the labels wrap, and a fixed 64px clipped
   them. The safe-area inset keeps the bar above a phone's home indicator (the viewport carries
   viewport-fit=cover, without which the inset reads 0). With script the bar stays out of the way until the
   first section has scrolled off (owner ruling 2026-08-28): at rest it covered the hero's last line and
   doubled the hero's own two buttons on the first screen. Hidden means visibility:hidden too, so its links
   cannot take focus while nobody can see them. */
.cx-bar { position: fixed; inset: auto 0 0 0; z-index: 60; display: none; grid-template-columns: 1fr 1fr; min-height: var(--cx-bar-h); padding-bottom: env(safe-area-inset-bottom, 0px); background: var(--r-inverse-bg); color: var(--r-inverse-fg); border-top: 1px solid var(--r-inverse-line); transition: transform .2s ease, visibility .2s; }
.cx-bar a { text-decoration: none; font-weight: 800; letter-spacing: .08em; text-transform: var(--r-case-label, uppercase); font-size: 0.875rem; color: inherit; }
.cx-bar a + a { background: var(--r-accent); color: var(--r-on-accent); }
.cx-bar--one { grid-template-columns: 1fr; }
@media (max-width: 900px) { .cx-bar { display: grid; } html.js .cx-bar:not(.is-shown) { transform: translateY(100%); visibility: hidden; } }

/* ---- hero (shared) ---- */

.r-hero-stats { display: flex; flex-wrap: wrap; gap: 28px; margin-top: 44px; padding-top: 28px; border-top: 1px solid var(--r-line); }
/* flex: 1 1 180px so two stats SHARE the row instead of wrapping out of it. At their natural widths a
   pair ran 643px inside a 592px hero column, so the second dropped to a line of its own carrying the
   border-left a skin uses as the divider BETWEEN them: a stray vertical rule with nothing on its left,
   and a stat that reads as indented for no reason. A basis wide enough to be worth reading still wraps
   on a phone, where one stat to a line is right. */
.r-hero-stat { display: flex; flex-direction: column; gap: 6px; flex: 1 1 180px; min-width: 0; }
.r-hero-stat-n { font-family: var(--r-display); font-size: 1.875rem; line-height: 1; color: var(--r-fg); }
.r-hero-stat-l { font-size: var(--r-micro); font-weight: 700; letter-spacing: .16em; text-transform: var(--r-case-label, uppercase); color: var(--r-muted); }
.r-hero-stat-div { width: 1px; background: var(--r-line); }
@media (max-width: 640px) { .r-hero-stat-div { display: none; } .r-hero-stats { gap: 18px 28px; } }

/* ---- hero (shared) ---- */

.r-claim { position: relative; overflow: hidden; background: var(--r-bg); color: var(--r-fg); }
.r-claim-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 70%; }
.r-placeholder.r-claim-img { position: absolute; inset: 0; border-radius: 0; min-height: 0; height: 100%; place-items: start start; padding: 16px; }
.r-placeholder.r-claim-img span { background: color-mix(in srgb, var(--r-bg) 85%, transparent); padding: 8px 12px; border-radius: var(--cx-radius); text-align: left; }
/* A commanded placeholder carries its label in the top-left corner; on a narrow screen the copy starts under it. */
@media (max-width: 980px) { .r-claim:has(.r-placeholder.r-claim-img) .r-claim-in { padding-top: 104px; } }
.r-claim-copy { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; }
.r-claim-eyebrow { margin-bottom: 18px; }
.r-claim-h1 { font-family: var(--r-display); font-weight: var(--r-display-weight); letter-spacing: var(--r-display-tracking); font-size: clamp(2.625rem, 5.5vw, 4.25rem); line-height: 1.02; text-transform: var(--r-case-display, uppercase); color: var(--r-fg); margin: 0; max-width: 15ch; }
.r-claim-sub { font-size: clamp(1.0625rem, 1.4vw, 1.1875rem); line-height: 1.6; color: var(--r-muted); max-width: 54ch; margin: 22px 0 0; }
.r-claim-btns { margin-top: 30px; }
/* The stops hold near-full strength across the copy column and only then open onto the picture. The
   first cut thinned from 42% of the width, and the subhead's measure runs to about half of it, so
   the end of every line lay on the bright side of the ramp: 3.4:1 where body text needs 4.5. */
.r-claim-scrim { position: absolute; inset: 0; pointer-events: none; background: linear-gradient(100deg, color-mix(in srgb, var(--r-bg) 93%, transparent) 0%, color-mix(in srgb, var(--r-bg) 88%, transparent) 55%, color-mix(in srgb, var(--r-bg) 28%, transparent) 100%); }
/* The ramp runs left to right because the desktop layout puts the words on the left and lets the
   photograph's subject breathe on the right, where the scrim thins to a quarter. Below the stack
   point the copy is FULL WIDTH, so the end of every line lands on that quarter and sits on bare
   photograph: a grey paragraph over a skid steer and foliage, unreadable from about the middle of
   each line, on nine pages of the first acceptance build. Stacked, the ramp turns vertical instead:
   strong through the whole band of text, opening only below it where nothing is being read. */
@media (max-width: 980px) {
  .r-claim-scrim { background: linear-gradient(180deg, color-mix(in srgb, var(--r-bg) 93%, transparent) 0%, color-mix(in srgb, var(--r-bg) 90%, transparent) 62%, color-mix(in srgb, var(--r-bg) 62%, transparent) 100%); }
}
.r-claim-in { position: relative; z-index: 2; }

/* ---- split (shared) ---- */

.r-split { position: relative; }
.r-split-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: var(--sp-columns); align-items: center; }
.r-split--flip .r-split-media { order: -1; }
.r-split-text .r-head { margin-bottom: 20px; }
.r-split-text p { font-size: 1.0625rem; line-height: 1.7; color: var(--r-muted); }
.r-split-media { position: relative; }
.r-split-img { width: 100%; aspect-ratio: 4 / 3.4; object-fit: cover; }

/* ---- header/topbar-stacked ---- */

/* 88px, the top of the 64 to 88 range (audit F38): the two-row right column fits a 22px number over a
   44px nav row with 8px of padding, and a taller header only comes off every first screen. */
:root { --cx-head-h: 88px; }
.r-topbar { background: var(--r-bg); color: var(--r-fg); }
.r-topbar-in { margin: 0 auto; max-width: var(--cx-wrap); display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 0; padding-block: 8px; font-size: var(--r-eyebrow); font-weight: 700; letter-spacing: .12em; text-transform: var(--r-case-label, uppercase); text-align: center; line-height: 1.4; }
.r-topbar-item { display: inline-flex; align-items: center; }
.r-topbar-item + .r-topbar-item::before { content: '|'; opacity: .45; margin: 0 14px; }
.r-hdr2 { background: var(--r-bg); color: var(--r-fg); border-bottom: 1px solid var(--r-line); box-shadow: 0 10px 28px -22px rgba(0, 0, 0, .5); }
.r-hdr2-in { display: flex; align-items: center; column-gap: clamp(16px, 3vw, 40px); row-gap: 8px; min-height: var(--cx-head-h); padding-block: 8px; flex-wrap: wrap; }
.r-hdr2-brand { display: inline-flex; align-items: center; text-decoration: none; color: inherit; }
.r-hdr2-brand--word { font-family: var(--r-display); font-weight: var(--r-display-weight); font-size: 1.625rem; letter-spacing: .02em; text-transform: var(--r-case-display, uppercase); }
.r-hdr2-logo { height: 52px; width: auto; max-width: 230px; object-fit: contain; }
.r-hdr2-right { margin-left: auto; display: flex; flex-direction: column; align-items: flex-end; gap: 0; }
.r-hdr2-tel { margin: 0; max-width: none; display: inline-flex; align-items: baseline; gap: 10px; }
.r-hdr2-kicker { font-size: var(--r-micro); font-weight: 700; letter-spacing: .18em; text-transform: var(--r-case-label, uppercase); color: var(--r-muted); }
.r-hdr2-num { font-family: var(--r-display); font-weight: var(--r-display-weight); font-size: 1.375rem; letter-spacing: .01em; color: var(--r-fg); text-decoration: none; display: inline-flex; align-items: center; }
.r-hdr2-row { display: flex; align-items: center; gap: 24px; }
.r-hdr2 .cx-nav ul { gap: 20px; }
.r-hdr2 .cx-nav a { font-size: 0.875rem; font-weight: 700; letter-spacing: .06em; text-transform: var(--r-case-label, uppercase); color: var(--r-fg); padding: 6px 0; display: inline-flex; align-items: center; }
.r-hdr2 .cx-nav a[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--r-accent); }
.r-hdr2 .cx-nav-tel { display: none; }
.r-hdr2-cta { padding-inline: 18px; min-height: 48px; }
/* The desktop row does not wrap: the call to action stays at the far right of the header (owner's
   standing rule). The nav is the one thing that gives, by shrinking and then wrapping its own list.
   This block comes AFTER the base rule, which also sets flex-wrap at the same specificity: it came first,
   so the base rule won and the desktop row wrapped (layout stress set, 2026-11-04; the masthead's Test D bug). */
@media (min-width: 901px) {
  .r-hdr2-in { flex-wrap: nowrap; }
  .r-hdr2-brand, .r-hdr2-right { flex: 0 0 auto; }
  .r-hdr2 .cx-nav { min-width: 0; }
  .r-hdr2 .cx-nav ul { flex-wrap: wrap; row-gap: 0; justify-content: flex-end; }
  /* Desktop only: the phone line over the nav is a 28px target (WCAG 2.5.8 AA asks 24px of a pointer
     target; 44px is the touch floor, and on a phone this line is hidden and the bar dials instead). Two
     stacked 44px targets made this header 114px; 28 + 48 + 12 of padding is the 88px it declares. */
  .r-hdr2 .r-hdr2-in { padding-block: 6px; }
  .r-hdr2 .r-hdr2-tel { line-height: 1; }
  .r-hdr2 .r-hdr2-num { min-height: 28px; }
  .r-hdr2 .r-hdr2-row { min-height: 48px; }
  .r-hdr2 .r-hdr2-row .r-hdr2-cta { min-height: 48px; height: 48px; padding-block: 0; }
}
@media (max-width: 1100px) { .r-hdr2 .cx-nav ul { gap: 14px; } .r-hdr2 .cx-nav a { letter-spacing: .03em; } }
@media (max-width: 900px) {
  :root { --cx-head-h: 64px; }
  .r-topbar-item--3 { display: none; }
  .r-hdr2-in { min-height: 64px; padding-block: 8px; }
  .r-hdr2-logo { height: 48px; max-width: 170px; }
  .r-hdr2-right, .r-hdr2-row { display: contents; }
  .r-hdr2-tel, .r-hdr2-cta { display: none; }
  .r-hdr2 .cx-nav { margin: 0; border-top: 1px solid var(--r-line); padding-block: 8px; }
  .r-hdr2 .cx-nav-tel { display: block; }
  .r-hdr2 .cx-nav a { font-size: 0.9375rem; letter-spacing: .04em; }
}
@media (max-width: 720px) { .r-topbar-item:not(:first-child) { display: none; } }
.r-topbar-where { display: none; }
.r-topbar--where-only { display: none; }
@media (max-width: 720px) {
  .r-topbar--where-only { display: block; }
  .r-topbar--where .r-topbar-item { display: none; }
  .r-topbar--where .r-topbar-where { display: inline-flex; align-items: center; font-size: 0.875rem; letter-spacing: .08em; }
}

/* ---- footer/columns ---- */

.r-foot { background: var(--r-bg); color: var(--r-muted); padding-block: var(--cx-band) 0; border-top: 1px solid var(--r-line); }
.r-foot-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: var(--sp-columns); padding-bottom: var(--cx-band); }
.r-foot-brand { grid-column: span 1; }
.r-foot-logo { height: 44px; width: auto; max-width: 200px; object-fit: contain; margin-bottom: 14px; }
.r-foot-word { font-family: var(--r-display); font-weight: var(--r-display-weight); font-size: 1.5rem; color: var(--r-fg); text-transform: var(--r-case-display, uppercase); display: block; margin-bottom: 12px; }
.r-foot-tag { color: var(--r-fg); font-weight: 600; margin-bottom: 10px; }
/* The blurb sits INSIDE the brand block, so whatever a skin does to the brand name it did to the
   paragraph too: two different generated skins styled .r-foot-brand as the wordmark (display face,
   capitals) and a 143-character paragraph inherited both and ran four lines of Archivo Black caps.
   A declaration on the element beats anything it would inherit, so the paragraph states its own
   case and face; a skin that wants to style the blurb names it, and the page gate judges that. */
.r-foot-blurb { font-size: 0.9375rem; text-transform: none; letter-spacing: normal; font-family: var(--cx-font-body, inherit); font-weight: 400; line-height: 1.55; }
.cx-fh { font-size: var(--r-eyebrow); font-weight: 700; letter-spacing: .2em; text-transform: var(--r-case-label, uppercase); color: var(--r-fg); margin: 0 0 14px; }
.cx-fcol ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.cx-fcol a { color: var(--r-muted); text-decoration: none; }
.cx-fcol a:hover { color: var(--r-fg); }
.cx-fcol address { font-style: normal; line-height: 1.7; }
.cx-fcol p { margin: 10px 0 0; }
.r-foot-sub { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px 24px; padding-block: 18px; border-top: 1px solid var(--r-line); font-size: 0.875rem; }
.r-foot-sub p { margin: 0; }
.r-foot-sub a { color: inherit; }

/* ---- hero/statement ---- */

.r-hero--statement { padding-block: clamp(56px, 9vw, 120px); }
/* The family root and the column are declared here as well as in photo-anchored: a site that uses
   only the statement hero shipped both classes with no rule, which the css gate flags as dead markup. */
.r-hero.r-hero--statement { position: relative; }
.r-hero--statement .r-hero-col { min-width: 0; }
.r-hero-grid { display: grid; gap: var(--sp-columns); align-items: center; }
.r-hero-grid--photo { grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); }
.r-statement-h1 { font-family: var(--r-display); font-weight: var(--r-display-weight); letter-spacing: var(--r-display-tracking); font-size: clamp(2.375rem, 5.6vw, 4.75rem); line-height: 1; color: var(--r-fg); margin: 0; }
.r-hero--statement .r-hero-sub { font-size: clamp(1.0625rem, 1.5vw, 1.25rem); color: var(--r-muted); max-width: 56ch; margin-top: 22px; }
.r-hero--statement .r-hero-btns { margin-top: 30px; }
.r-hero-side { min-width: 0; }
.r-hero-side-img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

/* ---- services/image-tiles ---- */

.r-tiles { position: relative; }
.r-tiles-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 24px; flex-wrap: wrap; margin-bottom: 36px; }
.r-tiles-head h2 { font-family: var(--r-display); font-weight: var(--r-display-weight); letter-spacing: var(--r-display-tracking); line-height: 1.02; margin: 0; text-transform: var(--r-case-display, uppercase); }
.r-tiles-all { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; color: var(--r-fg); font-weight: 700; text-decoration: none; border-bottom: 2px solid var(--r-accent); padding-bottom: 2px; }
.r-tiles-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-card-gap); }
/* A minimum, not a height (the owner's rule 7): the caption sits in flow at the tile's foot, so a longer
   service name or enlarged text grows the tile instead of being cut off by overflow: hidden. */
.r-tile2 { position: relative; display: flex; flex-direction: column; justify-content: flex-end; min-height: 330px; overflow: hidden; border-radius: var(--cx-radius); text-decoration: none; color: var(--r-inverse-fg); background: var(--r-inverse-bg); }
.r-tile2-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform .4s ease; }
.r-placeholder.r-tile2-img { border-radius: 0; border: 0; min-height: 0; padding-bottom: 110px; }
.r-tile2:hover .r-tile2-img { transform: scale(1.05); }
.r-tile2-scrim { position: absolute; inset: 0; background: linear-gradient(180deg, transparent 38%, color-mix(in srgb, var(--r-inverse-bg) 90%, transparent) 100%); }
.r-tile2-cap { position: relative; z-index: 1; padding: 64px 20px 20px; display: grid; gap: 6px; background: linear-gradient(180deg, transparent 0, rgba(0,0,0,.62) 44px, rgba(0,0,0,.78) 100%); text-shadow: 0 1px 2px rgba(0,0,0,.55); }
.r-tile2-title { font-family: var(--r-display); font-weight: var(--r-display-weight); letter-spacing: var(--r-display-tracking); font-size: 1.4375rem; line-height: 1.05; text-transform: var(--r-case-display, uppercase); margin: 0; color: var(--r-inverse-fg); }
.r-tile2-line { font-size: var(--r-micro); font-weight: 700; letter-spacing: .12em; text-transform: var(--r-case-label, uppercase); color: var(--r-inverse-accent-text); }
.r-tiles-tail { text-align: center; max-width: 62ch; margin: 30px auto 0; color: var(--r-muted); font-size: 1rem; line-height: 1.6; }
.r-tiles-tail a { color: var(--r-fg); font-weight: 700; text-decoration: none; border-bottom: 2px solid var(--r-accent); }
@media (max-width: 980px) { .r-tiles-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .r-tiles-grid { grid-template-columns: 1fr; } .r-tile2 { min-height: 260px; } }

/* ---- split/heritage-numeral ---- */

.r-heritage { position: relative; background: var(--r-surface); }
.r-heritage-grid { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-columns); align-items: stretch; }
.r-heritage-figure { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; }
.r-heritage-value { display: inline-flex; align-items: flex-start; font-family: var(--r-display); font-weight: var(--r-display-weight); font-size: clamp(6rem, 12vw, 10.625rem); line-height: .9; letter-spacing: -.01em; color: var(--r-fg); }
.r-heritage-suffix { color: var(--r-accent-text); font-size: .55em; line-height: 1; margin: .12em 0 0 4px; }
.r-heritage-cap { margin-top: 12px; font-size: var(--r-micro); font-weight: 700; letter-spacing: .18em; text-transform: var(--r-case-label, uppercase); color: var(--r-muted); }
.r-heritage-text { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; }
.r-heritage-text h2 { font-family: var(--r-display); font-weight: var(--r-display-weight); letter-spacing: var(--r-display-tracking); line-height: 1.02; text-transform: var(--r-case-display, uppercase); margin: 0 0 14px; }
.r-heritage-text .r-lead { max-width: 60ch; margin: 0 0 22px; }
.r-heritage-chips { list-style: none; margin: 0 0 24px; padding: 0; display: flex; flex-wrap: wrap; gap: 10px; }
.r-heritage-chips li { display: inline-flex; align-items: center; gap: 8px; min-height: 38px; padding: 0 14px; border-radius: 999px; background: var(--r-bg); border: 1px solid var(--r-line); font-size: 0.875rem; font-weight: 600; line-height: 1.3; }
.r-heritage-check { color: var(--r-accent-text); font-weight: 700; }
.r-heritage-link { display: inline-flex; align-items: center; gap: 10px; min-height: 44px; color: var(--r-fg); text-decoration: none; font-size: 0.875rem; font-weight: 800; letter-spacing: .14em; text-transform: var(--r-case-label, uppercase); border-bottom: 2px solid var(--r-accent); }
.r-heritage-link::after { content: '\2192'; transition: transform .2s ease; }
.r-heritage-link:hover::after { transform: translateX(4px); }
/* The numeral scales with the screen instead of sitting at a flat 96px, which is a third of the width
   of a small phone and, on a page whose hero runs four lines, pushed its own tracked label down into
   the fixed call bar: the bar's top edge crossed the label a pixel above its baseline and read as a
   line struck through the words. A viewport-relative cap keeps the numeral the largest thing on the
   page and gives the pair back the room it needs to clear the bar. */
@media (max-width: 760px) { .r-heritage-grid { grid-template-columns: 1fr; gap: 28px; } .r-heritage-value { font-size: min(6rem, 20vw); } }

/* ---- split/sticky-reasons ---- */

.r-why { position: relative; }
.r-why-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: var(--sp-columns); align-items: start; }
.r-why-rail { position: sticky; top: calc(var(--cx-head-h) + 30px); }
.r-why-rail .r-head { margin-bottom: 24px; }
.r-why-list { list-style: none; margin: 0; padding: 0; }
.r-why-row { display: grid; grid-template-columns: 34px 1fr; gap: 18px; padding: 22px 0; border-top: 1px solid var(--r-line); }
.r-why-row:last-child { border-bottom: 1px solid var(--r-line); }
.r-why-n { font-family: var(--r-display); font-size: 1.375rem; color: var(--r-accent-text); line-height: 1.2; }
.r-why-row h3 { font-size: 1.125rem; font-weight: 700; margin-bottom: 6px; }
.r-why-row p { font-size: 0.9375rem; color: var(--r-muted); margin: 0; }
@media (max-width: 900px) { .r-why-rail { position: static; } }

/* ---- reviews/mount-cards ---- */

/* A reviews section with no reviews is a heading promising something the page does not have: the
   Splash Pros homepage spent a full band on "Reviews from Splash Pros customers" over one line saying
   none had come in yet, and a second line saying the same (owner, 2026-09-24). The section now shows
   only once the snippet has put a review in the mount. The feed is live (Phase 3), so the first
   published review brings the section back without a re-upload; the mount starts empty, and an empty
   feed leaves it empty, so both states hide it. Below the first screen, so its arrival shifts nothing
   a visitor is looking at. A page whose whole subject is reviews keeps its honest empty state. */
.r-reviews--optional:has(.r-reviews-mount:empty) { display: none; }
.r-reviews { position: relative; }
.r-reviews-mount { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: var(--cx-gap); min-height: 120px; }
.r-reviews-mount:empty { min-height: 0; }
/* The note follows the section's alignment (Test B: a left-aligned head over a centered note read as unfinished). */
.r-reviews-note { text-align: inherit; color: var(--r-muted); margin: 24px 0 0; font-size: 0.9375rem; }
.r-head--center ~ .r-reviews-note { margin-inline: auto; text-align: center; }
.r-reviews-links { display: flex; justify-content: center; gap: 14px; flex-wrap: wrap; margin: 24px 0 0; max-width: none; }

/* ---- content/faq ---- */

.r-faq { position: relative; }
.r-faq-in { max-width: 820px; }
.r-faq-list { border-top: 1px solid var(--r-line); }
.r-faq-item { border-bottom: 1px solid var(--r-line); }
.r-faq-item summary { list-style: none; cursor: pointer; padding: 18px 44px 18px 0; position: relative; min-height: 44px; display: flex; align-items: center; }
.r-faq-item summary::-webkit-details-marker { display: none; }
.r-faq-item summary::after { content: '+'; position: absolute; right: 8px; font-family: var(--r-display); font-size: 1.625rem; color: var(--r-accent-text); line-height: 1; }
.r-faq-item[open] summary::after { content: '\2212'; }
.r-faq-item h3 { font-size: 1.125rem; font-weight: 700; margin: 0; }
.r-faq-item p { color: var(--r-muted); padding-bottom: 18px; margin: 0; }

/* ---- contact/split-form ---- */

.r-contact, .r-contact--split { position: relative; }
.r-contact-pitch { min-width: 0; }
.r-contact-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: var(--sp-columns); align-items: start; }
.r-contact-tel { margin: 0 0 12px; max-width: none; }
.r-contact-num { font-family: var(--r-display); font-size: clamp(1.625rem, 3vw, 2.5rem); color: var(--r-fg); text-decoration: none; display: inline-flex; align-items: center; letter-spacing: .01em; }
.r-contact-addr { font-style: normal; color: var(--r-muted); line-height: 1.6; margin-bottom: 8px; }
.r-contact-hours { color: var(--r-muted); }
.r-contact-expect { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 10px; }
.r-contact-expect li { padding-left: 22px; position: relative; color: var(--r-muted); }
.r-contact-expect li::before { content: ''; position: absolute; left: 0; top: .7em; width: 10px; height: 2px; background: var(--r-accent); }
.r-contact-form { background: var(--r-surface); border: 1px solid var(--r-line); border-radius: var(--cx-radius-media); padding: clamp(20px, 3vw, 32px); }
.r-contact-form .cx-form { display: grid; gap: var(--sp-form-group, 22px); }
.r-contact-form .cx-form > .cx-field { margin: 0; }
.r-contact-form .cx-form input, .r-contact-form .cx-form select, .r-contact-form .cx-form textarea { background-color: var(--r-bg); color: var(--r-fg); border-color: var(--r-line); }
.r-contact-form .cx-actions { margin: 6px 0 0; }
.booking-fallback { font-size: 0.875rem; color: var(--r-muted); }

/* ---- hero/photo-band ---- */

.r-claim--band .r-claim-in { padding-top: 68px; padding-bottom: 72px; }
.r-claim-copy--band { max-width: 780px; }
/* Every interior page opened with this band, and on a desktop each one read as the same dark block:
   the photograph lay under a scrim across the whole width, so a close-up of a dark car turned the right
   half into empty navy, and a page with no photograph had the right half actually empty (Splash Pros,
   2026-09-24). On a wide screen the photograph now OWNS the right half, uncovered, and meets the copy
   through a short fade; the copy sits on the band's own ground, and ends a column gap short of the photograph's edge. With no photograph the band centres
   what it holds, so no half of it is blank. Stacked (a phone) is unchanged: full-bleed under a
   vertical scrim, which is what keeps the words readable there. */
/* On a phone the interior head is its words on the band's own ground, with no photograph (owner,
   2026-09-28). Under the stacked scrim the picture was barely visible, yet it was the heaviest thing on
   the page and its slowest paint: Test C's gallery measured LCP 2.9s on a 146KB photograph nobody could
   see. The head's photograph lives on a wide screen, where it owns the right half. */
@media (max-width: 980px) {
  .r-claim--band .r-claim-img, .r-claim--band .r-claim-scrim { display: none; }
}
@media (min-width: 981px) {
  .r-claim--band .r-claim-img { inset: 0 0 0 50%; width: 50%; }
  .r-claim--band .r-claim-scrim { background: linear-gradient(90deg, var(--r-bg) 0%, var(--r-bg) 50%, color-mix(in srgb, var(--r-bg) 0%, transparent) 60%); }
  .r-claim--band:has(.r-claim-img) .r-claim-copy--band { max-width: min(780px, calc(50vw - (100vw - min(100vw - var(--sp-gutter, var(--cx-gap)) * 2, var(--cx-wrap))) / 2 - var(--sp-columns, 48px))); }
  .r-claim--band:not(:has(.r-claim-img)) .r-claim-copy--band { max-width: 860px; margin-inline: auto; align-items: center; text-align: center; }
  .r-claim--band:not(:has(.r-claim-img)) .r-claim-h1--band,
  .r-claim--band:not(:has(.r-claim-img)) .r-claim-sub { margin-inline: auto; }
  .r-claim--band:not(:has(.r-claim-img)) .r-claim-btns { justify-content: center; }
}
.r-claim-h1--band { font-size: clamp(2.375rem, 5vw, 3.5rem); max-width: 22ch; }
.r-claim--band .r-claim-sub { max-width: 62ch; }
@media (max-width: 640px) { .r-claim--band .r-claim-in { padding-top: 48px; padding-bottom: 56px; } }

/* ---- services/zigzag ---- */

.r-zig { position: relative; }
.r-zig-row { display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; background: var(--r-bg); }
.r-zig-row--alt { background: var(--r-surface); }
.r-zig-media { position: relative; min-height: 420px; }
.r-zig-row--flip .r-zig-media { order: 2; }
.r-zig-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.r-placeholder.r-zig-img { position: absolute; inset: 0; border-radius: 0; border: 0; min-height: 0; height: 100%; }
.r-zig-text { display: flex; align-items: center; padding: 60px 52px; }
.r-zig-text-in { max-width: 560px; margin-right: auto; }
.r-zig-row--flip .r-zig-text-in { margin-right: 0; margin-left: auto; }
.r-zig-text h2 { font-family: var(--r-display); font-weight: var(--r-display-weight); letter-spacing: var(--r-display-tracking); font-size: clamp(1.75rem, 3vw, 2.5rem); line-height: 1.02; text-transform: var(--r-case-display, uppercase); margin: 0 0 14px; }
.r-zig-text p { color: var(--r-muted); margin: 0; }
.r-zig-list { list-style: none; margin: 18px 0 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 10px 20px; }
.r-zig-list li { position: relative; padding-left: 24px; font-size: 0.9375rem; line-height: 1.5; }
.r-zig-list li::before { content: '\2713'; position: absolute; left: 0; top: 0; color: var(--r-accent-text); font-weight: 700; }
.r-zig-link { display: inline-flex; align-items: center; gap: 8px; margin-top: 22px; min-height: 44px; color: var(--r-fg); text-decoration: none; font-size: 0.875rem; font-weight: 800; letter-spacing: .12em; text-transform: var(--r-case-label, uppercase); border-bottom: 2px solid var(--r-accent); }
.r-zig-link::after { content: '\2192'; }
.r-zig-cloud { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 10px; padding-block: var(--cx-band); }
.r-zig-cloud-label { width: 100%; text-align: center; font-size: var(--r-micro); font-weight: 700; letter-spacing: .2em; text-transform: var(--r-case-label, uppercase); color: var(--r-muted); margin-bottom: 6px; }
.r-zig-chip { display: inline-flex; align-items: center; min-height: 40px; padding: 0 16px; border: 1px solid var(--r-line); border-radius: 999px; color: var(--r-fg); text-decoration: none; font-size: 0.875rem; font-weight: 600; }
a.r-zig-chip:hover { border-color: var(--r-fg); }
.r-zig-chip--accent { background: color-mix(in srgb, var(--r-accent) 12%, var(--r-bg)); border-color: transparent; }
@media (max-width: 900px) {
  .r-zig-row { grid-template-columns: 1fr; }
  .r-zig-media, .r-zig-row--flip .r-zig-media { order: -1; min-height: 260px; }
  .r-zig-text { padding: 36px 24px 44px; }
  .r-zig-text-in, .r-zig-row--flip .r-zig-text-in { margin: 0; }
}
@media (max-width: 560px) { .r-zig-list { grid-template-columns: 1fr; } }

/* ---- process/ghost-numerals ---- */

/* Columns from the step COUNT (cardCols), not from the width: four steps in a width-sized grid came
   out three and one, with two thirds of the second row bare under the last step. */
.r-process-grid { list-style: none; margin: 0; padding: 0; gap: var(--sp-card-gap); }
.r-step { border: 1px solid var(--r-line); border-radius: var(--cx-radius-media); padding: 28px 26px 26px; background: var(--r-surface); }
.r-step-n { display: block; font-family: var(--r-display); font-size: 3.375rem; line-height: 1; margin-bottom: 18px; color: color-mix(in srgb, var(--r-fg) 10%, transparent); -webkit-text-stroke: 1px color-mix(in srgb, var(--r-accent) 45%, transparent); }
.r-step h3 { font-size: 1.25rem; font-weight: 700; }
.r-step p { font-size: 0.9375rem; color: var(--r-muted); margin: 0; }
.r-process .r-head--center .r-eyebrow { display: inline-flex; gap: 12px; }
.r-process .r-head--center .r-eyebrow::before, .r-process .r-head--center .r-eyebrow::after { content: ''; width: 28px; height: 2px; background: var(--r-accent); }

/* ---- band/cta ---- */

.r-ctaband, .r-ctaband--photo { position: relative; overflow: hidden; text-align: center; }
/* A scrim, not a ghost (audit F45): every site showed its closing photo grayscale at 18% opacity, the same
   washed-out band everywhere. The photo keeps its color and a layer of the section's own ground sits over
   it, dense enough that the heading and the buttons keep their contrast on the brightest pixel. */
.r-ctaband-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.r-ctaband--photo::before { content: ''; position: absolute; inset: 0; z-index: 1; background: color-mix(in srgb, var(--r-bg) 80%, transparent); }
.r-ctaband--left { text-align: left; }
.r-ctaband.r-ctaband--left .r-ctaband-in { justify-items: start; }
.r-ctaband.r-ctaband--left .r-btns { justify-content: flex-start; }
/* The outline button's edge is its boundary, so it carries full contrast (WCAG 1.4.11); a tinted edge on a
   bright brand ground failed it. */
.r-ctaband .r-btn--ghost { border-color: currentColor; }
/* One owner per gap (spacing rule 3): the grid adds nothing, each child's top margin is its gap, so a skin
   that sets one of them is the only thing setting it (a skin margin plus an 18px grid gap made 54px). */
.r-ctaband-in { position: relative; z-index: 2; display: grid; justify-items: center; gap: 0; }
.r-ctaband h2 { font-family: var(--r-display); font-weight: var(--r-display-weight); letter-spacing: var(--r-display-tracking); text-transform: var(--r-case-display, uppercase); line-height: 1; max-width: 22ch; margin: 0; text-align: inherit; }
.r-ctaband .r-lead { margin: var(--sp-head-intro, 18px) 0 0; }
.r-ctaband .r-btns { justify-content: center; margin-top: var(--sp-text-buttons, 26px); }

/* ---- split/text-photo-card ---- */

.r-split--card { position: relative; }
.r-textlink { display: inline-flex; align-items: center; gap: 10px; color: var(--r-fg); text-decoration: none; font-size: 0.875rem; font-weight: 800; letter-spacing: .14em; text-transform: var(--r-case-label, uppercase); border-bottom: 2px solid var(--r-accent); padding-bottom: 4px; min-height: 44px; }
.r-textlink::after { content: '\2192'; transition: transform .2s ease; }
.r-textlink:hover::after { transform: translateX(4px); }
.r-split-card { position: absolute; bottom: -22px; left: -22px; background: var(--r-inverse-bg); color: var(--r-inverse-fg); padding: var(--sp-card-inset); max-width: 230px; display: grid; gap: 8px; border-radius: var(--cx-radius); }
.r-split-card strong { font-family: var(--r-display); font-weight: var(--r-display-weight); font-size: 1.125rem; text-transform: var(--r-case-label, uppercase); line-height: 1.05; }
.r-split-card span { font-size: 0.875rem; font-weight: 600; color: var(--r-inverse-muted); line-height: 1.5; }
@media (max-width: 640px) { .r-split-card { left: 12px; bottom: -16px; max-width: 70%; } .r-split-media { margin-bottom: 28px; } }

/* ---- band/proof-strip ---- */

.r-proof { background: var(--r-bg); color: var(--r-fg); border-top: 1px solid var(--r-line); border-bottom: 1px solid var(--r-line); }
/* A column on a phone, one row of equal cells from 700px (owner, 2026-09-24). A centered wrapping row
   left the fourth badge alone on a second line on a desktop, and on a phone stacked the badges centered
   at their own widths, so a skin's dividers zigzagged down the screen. Cells are full width on a phone
   (a divider spans the row) and equal on a wide screen (a long label wraps inside its cell). "margin: 0 auto",
   not 0: the list IS the cx-wrap, and a bare 0 cancelled its centring, pinning the strip to the screen's edge. */
.r-proof-list { list-style: none; margin: 0 auto; padding: 18px 0; display: grid; grid-template-columns: 1fr; gap: 14px 36px; font-size: 0.875rem; font-weight: 700; letter-spacing: .08em; text-transform: var(--r-case-label, uppercase); }
.r-proof-list li { display: flex; align-items: center; gap: 10px; min-width: 0; }
@media (min-width: 700px) {
  .r-proof-list { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
  .r-proof-list li { justify-content: center; text-align: center; }
}
.r-proof-mark { width: 8px; height: 8px; background: var(--r-accent); transform: rotate(45deg); }

/* ---- gallery/grid ---- */

.r-gallery { position: relative; }
/* Columns from the photo COUNT (cardCols), not from the width: four photographs in a width-sized grid
   came out three and one, with 853px of the second row bare beside the last picture. A skin that lays
   the gallery out as a mosaic overrides this, which is the point of a default. */
.r-gallery-grid { list-style: none; margin: 0; padding: 0; gap: 12px; }
/* min-width: 0 and height: 100% are both load-bearing, and both are about a grid the SKIN writes.
   A skin that lays the gallery out as a mosaic writes repeat(6, 1fr), and 1fr means minmax(auto, 1fr):
   the auto minimum is the item's min-content width, which for a 1600px photograph inflates the track,
   so the tiles in one row came out 247px and 295px wide instead of equal. min-width: 0 on the item is
   what lets a track be the fraction it says it is. Then the cell: grid items stretch, so a tile beside
   a taller one is as tall as that one, and an image with only an aspect-ratio sits at the top of it
   with the rest of the cell empty. That was a 115px band of dead ground under the top-right photograph
   of the sixth build's gallery. The photograph fills the cell it is given and crops, which is what
   object-fit: cover is for; the aspect-ratio still sets the cell's shape when nothing stretches it. */
.r-tile { position: relative; overflow: hidden; border-radius: var(--cx-radius-media); min-width: 0; }
.r-tile-img { width: 100%; height: 100%; aspect-ratio: 4 / 3; object-fit: cover; transition: transform .5s ease; }
.r-tile:hover .r-tile-img { transform: scale(1.04); }
/* The scrim is opaque UNDER the text, not merely at the bottom edge: a two-line caption's first line
   sat where a transparent-to-.65 gradient was still see-through, unreadable over bright grass, and
   the eye flagged it on every skinned build. The gradient's transparent part is padding above the
   text; every line of the caption sits on at least 78% black, plus a shadow for the edges. */
/* On a 390px screen the tiles are two to a row, so each photograph is about 167px tall. A caption of
   two lines then covered 74% of it and a three-line caption 89%: the gallery stopped showing the
   work. The caption is capped at a share of the tile and clips with an ellipsis rather than growing
   over the picture, and the tile itself opens the full image so the detail is still reachable. */
.r-tile-open { position: absolute; inset: 0; z-index: 1; }
.r-tile-cap { position: absolute; inset: auto 0 0 0; padding: 34px 14px 12px; font-size: 0.875rem; font-weight: 600; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.6); background: linear-gradient(180deg, transparent 0, rgba(0,0,0,.78) 24px, rgba(0,0,0,.86) 100%); }
.r-gallery-more { margin: 28px 0 0; max-width: none; }
/* One tile per row on a phone. Two columns made each photograph about 125px tall, so a two-line
   caption sitting on it covered two thirds of the picture and the gallery stopped showing the work.
   One column gives the photograph the width of the screen and the caption about a quarter of it. */
@media (max-width: 640px) { .r-gallery-grid { grid-template-columns: 1fr; } }

/* ---- contact/icon-rows ---- */

.r-visit { position: relative; }
/* :where() so this centring counts for NOTHING in specificity. It is the default for a head the
   section asks for centred, and a skin that re-aligns its heads to the left writes .r-head--center,
   which at 0-1-0 used to lose to the 0-2-0 selector this was and left the head indented 274px from
   the column of contact details directly beneath it. A default a skin can overrule has to be written
   at a specificity a skin can reach. */
:where(.r-visit) .r-head { max-width: 62ch; margin-inline: auto; }
:where(.r-visit) .r-head .r-lead { margin-inline: auto; }
/* The details column SPANS the row rather than floating in it. It is always shorter than the form
   card beside it, and the two obvious answers are both wrong: align-items:center floats it down the
   middle with a third of the section empty above it, which is what the owner saw and called wonky,
   and align-items:start gathers every pixel of the difference into one bare rectangle underneath it,
   which is the hole checkdesktop's check 2b exists for. Stretching the column and anchoring its ask
   at the bottom puts content at both ends, so the space between them reads as the breathing room of
   a full-height column instead of as an unfinished corner. auto-fit is also given an explicit
   two-track ceiling, because at 1180px it built three tracks, collapsed the empty one and left the
   pair sized for a grid that is not there. */
.r-visit-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: var(--sp-columns); align-items: stretch; }
@media (min-width: 860px) { .r-visit-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.r-visit-rows { display: flex; flex-direction: column; gap: 22px; min-width: 0; }
.r-visit-row { display: flex; gap: 18px; align-items: flex-start; }
.r-visit-icon { flex: 0 0 auto; display: grid; place-items: center; width: 48px; height: 48px; border-radius: 50%; background: var(--r-inverse-bg); color: var(--r-inverse-accent); }
.r-visit-body { min-width: 0; padding-top: 2px; }
.r-visit-label { font-family: var(--r-display); font-weight: var(--r-display-weight); font-size: 1.25rem; line-height: 1.2; margin: 0 0 4px; color: var(--r-fg); }
.r-visit-val { font-style: normal; font-size: 1rem; line-height: 1.6; color: var(--r-muted); margin: 0; max-width: none; }
.r-visit-link { color: var(--r-fg); text-decoration: none; display: inline-flex; align-items: center; min-height: 28px; border-bottom: 1px solid var(--r-line); }
.r-visit-link:hover { border-bottom-color: var(--r-fg); }
.r-visit-action { margin: 10px 0 0; max-width: none; }
/* The action follows the rows. It used to be pushed to the foot of the column (margin-top: auto), and
   beside the form card, which is far taller, it sat about 500px below the Hours row on its own: the
   owner read it as a stray button (Test D contact page, 2026-11-05). */
.r-visit-cta { min-width: 220px; }
.r-visit-note { font-size: 0.875rem; line-height: 1.6; color: var(--r-muted); margin: 0; max-width: 44ch; }
.r-visit-book { margin-top: 10px; padding-top: 22px; border-top: 1px solid var(--r-line); }
.r-visit-book .booking-fallback { font-size: 0.875rem; color: var(--r-muted); margin: 8px 0 0; }
.r-visit-book .booking-fallback a { color: var(--r-fg); }
.r-visit-card { position: relative; background: var(--r-surface); border-radius: calc(var(--cx-radius-media) * .75); padding: var(--sp-card-inset); box-shadow: 0 28px 56px -32px color-mix(in srgb, var(--r-inverse-bg) 55%, transparent); min-width: 0; }
.r-visit-card--form .cx-form { display: grid; gap: var(--sp-form-group, 22px); }
.r-visit-card--form .cx-form > .cx-field { margin: 0; }
.r-visit-card--form .cx-form input, .r-visit-card--form .cx-form select, .r-visit-card--form .cx-form textarea { background-color: var(--r-bg); color: var(--r-fg); border-color: var(--r-line); }
.r-visit-card--form .cx-form textarea { border-radius: calc(var(--cx-radius-media) * .5); }
.r-visit-card--form .cx-actions { margin: 6px 0 0; }
.r-visit-card--form .cx-form button { min-width: 200px; }
.r-visit-card-title { font-family: var(--r-display); font-weight: var(--r-display-weight); font-size: 1.625rem; line-height: 1.15; margin: 0 0 12px; color: var(--r-fg); }
.r-visit-card-text { font-size: 0.9375rem; line-height: 1.6; color: var(--r-muted); margin: 0 0 18px; }
.r-visit-card--visit { display: flex; flex-direction: column; align-items: flex-start; min-height: 420px; overflow: hidden; }
.r-visit-mark { position: absolute; right: -12px; top: -12px; color: var(--r-accent); opacity: .35; pointer-events: none; }
.r-visit-card-addr { position: relative; font-style: normal; font-family: var(--r-display); font-weight: var(--r-display-weight); font-size: clamp(1.25rem, 2vw, 1.625rem); line-height: 1.3; color: var(--r-fg); max-width: 18ch; margin: 0 0 22px; }
.r-visit-hours { position: relative; display: grid; gap: 8px; margin: 0 0 22px; width: 100%; max-width: 360px; }
.r-visit-hours-row { display: grid; grid-template-columns: minmax(120px, 1fr) 1fr; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--r-line); }
.r-visit-hours dt { font-size: var(--r-micro); font-weight: 700; letter-spacing: .16em; text-transform: var(--r-case-label, uppercase); color: var(--r-accent-text); align-self: center; }
.r-visit-hours dd { margin: 0; font-size: 0.9375rem; color: var(--r-fg); }
.r-visit-directions { margin-top: auto; }

/* ---- content/territories ---- */

.r-terr { position: relative; }
.r-terr-group + .r-terr-group { margin-top: clamp(40px, 6vw, 64px); }
.r-terr-group h2 { font-family: var(--r-display); font-weight: var(--r-display-weight); letter-spacing: var(--r-display-tracking); line-height: 1.02; text-transform: var(--r-case-display, uppercase); margin: 0 0 24px; }
.r-terr-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: var(--sp-card-gap); align-items: stretch; }
.r-terr-card { background: var(--r-surface); border-left: 4px solid var(--r-inverse-bg); border-radius: 0 var(--cx-radius) var(--cx-radius) 0; padding: var(--sp-card-inset); }
.r-terr-group--accent .r-terr-card { background: color-mix(in srgb, var(--r-accent) 10%, var(--r-bg)); border-left-color: var(--r-accent-text); }
.r-terr-card h3 { font-family: var(--r-display); font-weight: var(--r-display-weight); letter-spacing: var(--r-display-tracking); font-size: 1.375rem; line-height: 1.1; text-transform: var(--r-case-display, uppercase); margin: 0 0 8px; }
.r-terr-card p { margin: 0; color: var(--r-muted); font-size: 0.9375rem; line-height: 1.6; max-width: none; }
.r-terr-fallback { text-align: center; margin: clamp(36px, 5vw, 56px) auto 0; max-width: 60ch; }
.r-terr-fallback a { color: var(--r-fg); font-weight: 700; }
.r-terr-tel { white-space: nowrap; }

/* ---- content/prose ---- */
.r-prose-in { max-width: var(--cx-measure); }
.r-prose-in .r-head { margin-bottom: 20px; }
.r-prose p:not(:where(.r-eyebrow)) { color: var(--r-muted); font-size: 1.0625rem; line-height: 1.7; }
.r-prose-cta { margin-top: 24px; }

/* ---- split/text-photo ---- */
.r-split-img--43 { aspect-ratio: 4 / 3; }

/* ---- process/circle-triad ---- */

.r-triad { position: relative; }
.r-triad .r-head { max-width: 62ch; margin-inline: auto; }
.r-triad .r-head .r-lead { margin-inline: auto; }
/* Columns from the step count (cardCols, audit F46): auto-fit put three steps into two and one between
   600 and 768px. */
.r-triad-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-columns); }
.r-triad-step { display: flex; flex-direction: column; align-items: center; text-align: center; }
.r-triad-mark { display: grid; place-items: center; width: 72px; height: 72px; border-radius: 50%; background: var(--r-accent); color: var(--r-on-accent); margin-bottom: 22px; }
.r-triad-title { font-family: var(--r-display); font-weight: var(--r-display-weight); font-size: 1.5rem; line-height: 1.2; margin: 0 0 10px; color: var(--r-fg); }
.r-triad-text { font-size: 1rem; line-height: 1.65; color: var(--r-muted); max-width: 34ch; margin: 0; }



/* Responsive image wrappers must not participate in layout: <picture> is inline by
   default and wrapping a block <img> in one silently reflows the section around it. */
picture{display:contents}
