/* =========================================================================
 THE HARDWOOD GUYS — COMPONENT LIBRARY
 Depends on tokens.css (load it first). Every color/spacing/type value
 below is a var(--semantic-token) reference — no raw hex, no raw px
 color literal, ever. That is what makes a retone a one-file change.
 ========================================================================= */

/* ---------------------------------------------------------------------
 0. RESET / 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;
 font-family: var(--font-body);
 font-size: var(--text-base);
 line-height: var(--leading-normal);
 color: var(--color-text-body);
 background: var(--color-bg-page);
 font-variant-numeric: normal;
}

img, svg { max-width: 100%; display: block; }
button, input, select, textarea { font: inherit; color: inherit; }
ul, ol { padding: 0; margin: 0; list-style: none; }
h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 {
 font-family: var(--font-heading);
 color: var(--color-text-heading);
 line-height: var(--leading-tight);
 font-weight: var(--weight-semibold);
}

.tabular-nums { font-variant-numeric: tabular-nums; }

/* Universal focus-visible treatment — solid outline, never a glow-only
 box-shadow, so it survives on every background in the system. */
:focus-visible {
 outline: 3px solid var(--color-focus-ring);
 outline-offset: 2px;
 border-radius: var(--radius-sm);
}
.site-header :focus-visible,
.site-header__mobile-nav :focus-visible,
.mobile-cta-bar :focus-visible,
.site-footer :focus-visible,
.hero :focus-visible {
 outline-color: var(--color-focus-ring-inverse);
}

/* ---------------------------------------------------------------------
 1. LAYOUT UTILITIES
 --------------------------------------------------------------------- */
.container {
 max-width: var(--container-max);
 margin-inline: auto;
 padding-inline: var(--container-pad);
}

.section {
 padding-block: var(--space-16);
}
.section--alt { background: var(--color-bg-page-alt); }
.section--dark { background: var(--color-bg-header); color: var(--color-text-inverse); }

.section-head {
 max-width: 640px;
 margin-bottom: var(--space-8);
}
.section-head p { color: var(--color-text-muted); margin-top: var(--space-3); }

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

/* Skip link — visible on keyboard focus, WCAG 2.4.1 */
.skip-link {
 position: absolute;
 top: -60px;
 left: var(--space-4);
 z-index: var(--z-skip-link);
 background: var(--color-cta-bg);
 color: var(--color-cta-text);
 padding: var(--space-3) var(--space-5);
 border-radius: 0 0 var(--radius-base) var(--radius-base);
 font-weight: var(--weight-semibold);
 transition: top var(--motion-base) var(--motion-ease);
}
.skip-link:focus {
 top: 0;
}

/* ---------------------------------------------------------------------
 2. BUTTONS
 --------------------------------------------------------------------- */
.btn {
 display: inline-flex;
 align-items: center;
 justify-content: center;
 gap: var(--space-2);
 min-height: var(--touch-target-min);
 padding: var(--space-3) var(--space-6);
 border-radius: var(--radius-base);
 font-family: var(--font-body);
 font-weight: var(--weight-semibold);
 font-size: var(--text-base);
 border: 2px solid transparent;
 cursor: pointer;
 transition: background-color var(--motion-base) var(--motion-ease),
 color var(--motion-base) var(--motion-ease),
 box-shadow var(--motion-base) var(--motion-ease),
 border-color var(--motion-base) var(--motion-ease);
 text-align: center;
}
.btn--lg { padding: var(--space-4) var(--space-8); font-size: var(--text-md); }
.btn--sm { padding: var(--space-2) var(--space-4); font-size: var(--text-sm); min-height: 36px; }
.btn--block { width: 100%; }

.btn--primary {
 background: var(--color-cta-bg);
 color: var(--color-cta-text);
}
.btn--primary:hover { background: var(--color-cta-bg-hover); box-shadow: var(--shadow-md); }
.btn--primary:disabled {
 background: var(--color-cta-bg-disabled);
 color: var(--color-cta-text-disabled);
 cursor: not-allowed;
}

.btn--secondary {
 background: var(--color-btn-secondary-bg);
 color: var(--color-btn-secondary-text);
 border-color: var(--color-btn-secondary-border);
}
.btn--secondary:hover {
 background: var(--color-btn-secondary-hover-bg);
 color: var(--color-btn-secondary-hover-text);
}

/* Outline button — used on top of the hero photo scrim (dark). Hover
 fills solid rather than swapping to red, because red-on-dark is one
 of the documented contrast traps. */
.btn--outline {
 background: transparent;
 color: var(--color-btn-outline-text);
 border-color: var(--color-btn-outline-border);
}
.btn--outline:hover {
 background: var(--color-btn-outline-hover-bg);
 color: var(--color-btn-outline-hover-text);
}

.btn svg { width: 1.15em; height: 1.15em; flex: none; }

/* ---------------------------------------------------------------------
 3. HEADER
 --------------------------------------------------------------------- */
.site-header {
 position: sticky;
 top: 0;
 z-index: var(--z-header);
 background: var(--color-bg-header);
 color: var(--color-text-inverse);
 box-shadow: var(--shadow-header);
}

/* The header is sticky (72px tall) but no section ever declared clearance
   for it, so any in-page jump straight to a section id — the quote form
   most of all, since every CTA site-wide points at #quote-form — landed
   its heading tucked half behind the header bar instead of below it. */
section[id] { scroll-margin-top: 88px; }

.site-header__bar {
 display: flex;
 align-items: center;
 gap: var(--space-6);
 min-height: 72px;
 padding-block: var(--space-2);
}

.site-header__logo {
 display: flex;
 align-items: center;
 gap: var(--space-2);
 flex: none;
 max-width: 260px;
 color: var(--color-text-inverse);
}
/* The mark is a near-square badge (1391x1175), not a wide wordmark — it needs real
   height to read. David asked for it prominently displayed. */
.site-header__logo-mark { height: 92px; width: auto; display: block; flex: none; }
@media (max-width: 900px) {
  .site-header__logo-mark { height: 76px; }
}
@media (max-width: 480px) {
  .site-header__logo-mark { height: 58px; }
}

/* The bar carries logo + 6 nav items + phone + hours + CTA. Below 1400px the
   decorative tagline is the first thing to go — the crest already says who we
   are, and the footer NAP block repeats the location. */
@media (max-width: 1400px) {
  .site-header__logo-tag { display: none; }
}
/* Keep a real gutter between the last nav item and the phone block. */
.site-header__bar { column-gap: var(--space-8); }

.site-header__logo-word {
 font-family: var(--font-heading);
 font-weight: var(--weight-bold);
 font-size: 1.35rem;
 line-height: 1.1;
 letter-spacing: var(--tracking-tight);
}
.site-header__logo-tag {
 display: block;
 white-space: nowrap;
 font-family: var(--font-body);
 font-size: var(--text-xs);
 font-weight: var(--weight-medium);
 letter-spacing: var(--tracking-wide);
 text-transform: uppercase;
 color: var(--color-text-inverse);
 opacity: 0.85;
}

.site-nav { flex: 1; display: none; min-width: 0; }
.site-nav ul { display: flex; gap: var(--space-5); flex-wrap: nowrap; white-space: nowrap; }
@media (max-width: 1100px) {
  .site-nav ul { gap: var(--space-4); }
}
.site-nav a {
 display: inline-block;
 padding: var(--space-2) 0;
 font-weight: var(--weight-medium);
 color: var(--color-nav-link);
 border-bottom: 2px solid transparent;
}
.site-nav a:hover,
.site-nav a:focus-visible {
 text-decoration: underline;
 text-underline-offset: 4px;
}

.site-header__meta {
 display: none;
 flex-direction: column;
 align-items: flex-end;
 line-height: 1.3;
 flex: none;
}
.site-header__phone {
 font-weight: var(--weight-bold);
 font-size: var(--text-md);
 color: var(--color-text-inverse);
}
.site-header__phone:hover,
.site-header__phone:focus-visible { text-decoration: underline; }
.site-header__hours {
 font-size: var(--text-xs);
 color: var(--color-text-inverse);
 opacity: 0.85;
}
.site-header__cta { display: none; flex: none; }

/* Mobile-only click-to-call in the top header. Below 1024px the nav, phone
   number, and CTA button all disappear (see the media query below) and the
   header shrinks to just the logo and hamburger, with nothing else written
   on it — a real caller has to open the menu or scroll to the bottom bar to
   find a phone number. This restores a visible number up top. Hidden again
   at desktop widths since .site-header__meta already shows the number there. */
.site-header__mobile-call {
 display: inline-flex;
 align-items: center;
 gap: var(--space-2);
 margin-left: auto;
 color: var(--color-text-inverse);
 font-weight: var(--weight-semibold);
 font-size: var(--text-sm);
 white-space: nowrap;
}
.site-header__mobile-call svg { width: 18px; height: 18px; flex: none; }
.site-header__mobile-call:hover,
.site-header__mobile-call:focus-visible { text-decoration: underline; }

.hamburger {
 flex: none;
 display: inline-flex;
 align-items: center;
 justify-content: center;
 width: var(--touch-target-min);
 height: var(--touch-target-min);
 background: transparent;
 border: 2px solid transparent;
 border-radius: var(--radius-base);
 color: var(--color-text-inverse);
 cursor: pointer;
}
.hamburger svg { width: 26px; height: 26px; }
.hamburger .icon-close { display: none; }
.hamburger[aria-expanded="true"] .icon-menu { display: none; }
.hamburger[aria-expanded="true"] .icon-close { display: block; }

.site-header__mobile-nav {
 position: fixed;
 inset: 72px 0 0 0;
 background: var(--color-bg-header);
 z-index: var(--z-mobile-nav);
 overflow-y: auto;
 padding: var(--space-6) var(--container-pad) var(--space-24);
}
.site-header__mobile-nav[hidden] { display: none; }

.site-header__mobile-nav ul { display: flex; flex-direction: column; }
.site-header__mobile-nav a {
 display: block;
 padding: var(--space-4) 0;
 font-family: var(--font-heading);
 font-size: var(--text-lg);
 font-weight: var(--weight-semibold);
 color: var(--color-text-inverse);
 border-bottom: 1px solid rgba(255, 255, 255, 0.18);
}
.site-header__mobile-nav a:hover,
.site-header__mobile-nav a:focus-visible { text-decoration: underline; }

.site-header__mobile-meta {
 margin-top: var(--space-8);
 padding-top: var(--space-8);
 border-top: 1px solid rgba(255, 255, 255, 0.25);
}
.site-header__mobile-meta .site-header__phone { font-size: var(--text-xl); }
.site-header__mobile-meta .site-header__hours { display: block; margin-top: var(--space-2); }

@media (min-width: 1024px) {
 .site-nav { display: block; }
 .site-header__meta { display: flex; }
 .site-header__cta { display: inline-flex; }
 .hamburger { display: none; }
 .site-header__mobile-call { display: none; }
}

/* ---------------------------------------------------------------------
 4. MOBILE STICKY BOTTOM CTA BAR
 The single most important conversion element on the site: it is the
 only UI guaranteed to be on-screen no matter how far a phone user has
 scrolled. Two 44px+ targets, safe-area aware, always visible.
 --------------------------------------------------------------------- */
.mobile-cta-bar {
 position: fixed;
 left: 0; right: 0; bottom: 0;
 z-index: var(--z-bottom-bar);
 display: grid;
 grid-template-columns: 1fr 1.3fr;
 gap: 1px;
 background: var(--color-border-default);
 box-shadow: var(--shadow-bottom-bar);
 padding-bottom: env(safe-area-inset-bottom, 0);
}
.mobile-cta-bar a {
 display: flex;
 align-items: center;
 justify-content: center;
 gap: var(--space-2);
 min-height: var(--touch-target-min);
 padding-block: var(--space-4);
 font-weight: var(--weight-bold);
 font-size: var(--text-base);
}
.mobile-cta-bar__call {
 background: var(--color-bg-header);
 color: var(--color-text-inverse);
}
.mobile-cta-bar__call:hover,
.mobile-cta-bar__call:focus-visible { text-decoration: underline; }
.mobile-cta-bar__estimate {
 background: var(--color-cta-bg);
 color: var(--color-cta-text);
}
.mobile-cta-bar__estimate:hover,
.mobile-cta-bar__estimate:focus-visible { background: var(--color-cta-bg-hover); }
.mobile-cta-bar svg { width: 20px; height: 20px; }

/* Reserve space so the fixed bar never covers the last content/footer */
.has-mobile-cta-bar { padding-bottom: 64px; }

@media (min-width: 1024px) {
 .mobile-cta-bar { display: none; }
 .has-mobile-cta-bar { padding-bottom: 0; }
}

/* ---------------------------------------------------------------------
 5. PLACEHOLDER PHOTO BLOCK
 Every "photo" in this system is a placeholder — never a hotlinked
 live-site image, never an external request. The pattern + label make
 it obvious in review that real photography drops in later.
 --------------------------------------------------------------------- */
.photo-placeholder {
 position: relative;
 display: flex;
 align-items: flex-end;
 overflow: hidden;
 background:
 repeating-linear-gradient(135deg,
 rgba(var(--navy-rgb), 0.10) 0px, rgba(var(--navy-rgb), 0.10) 2px,
 transparent 2px, transparent 14px),
 var(--color-bg-page-alt);
 border: 1px solid var(--color-border-default);
 color: var(--color-text-muted);
 aspect-ratio: 4 / 3;
}
.photo-placeholder--wide { aspect-ratio: 16 / 9; }
.photo-placeholder--tall { aspect-ratio: 3 / 4; }
.photo-placeholder--square { aspect-ratio: 1 / 1; }
.photo-placeholder__label {
 display: flex;
 align-items: center;
 gap: var(--space-2);
 width: 100%;
 padding: var(--space-3);
 background: linear-gradient(to top, rgba(var(--near-black-rgb), 0.55), transparent);
 color: var(--white);
 font-size: var(--text-xs);
 font-weight: var(--weight-medium);
}
.photo-placeholder__label svg { width: 18px; height: 18px; flex: none; }

/* ---------------------------------------------------------------------
 5b. REAL PHOTOS — the placed-photo counterparts to the placeholder block
 above. Same footprint/positions, real <img> content instead of a
 decorative pattern.
 --------------------------------------------------------------------- */
/* Card-top photo — service-card, city cards, blog cards (all share
   .service-card markup). Matches .photo-placeholder--wide's aspect
   ratio and sits in the same spot at the top of the card. */
.service-card__photo {
 display: block;
 width: 100%;
 aspect-ratio: 16 / 9;
 object-fit: cover;
 object-position: center;
}
/* Two homepage service-card photos are portrait detail/macro shots
   (675x1200 — a door-panel finish close-up and a cabinet-hardware
   close-up), not the wide establishing shot the 16:9 crop above assumes.
   Cropped to 16:9 that grabs a horizontal center-slice that lands on
   either the blank flat door panel or misses the hardware entirely —
   "just some lines" (owner, 2026-08-18). Shown at full, uncropped
   proportions on mobile instead, where the card is a single stacked
   column and the extra height costs nothing. Desktop keeps the uniform
   16:9 grid crop since it wasn't reported as a problem there. */
@media (max-width: 639px) {
 .service-card__photo--full {
   aspect-ratio: auto;
   height: auto;
   object-fit: unset;
 }
}
/* In-content photo — blog post bodies and any other prose block that
   previously held a .photo-placeholder. */
/* Image sizing reset. The width/height attributes on every <img> exist only
   to reserve layout space before load (CLS) — CSS owns the rendered size.
   Without height:auto the height ATTRIBUTE beats every aspect-ratio crop
   below, and portrait photos render as full-height strips (the 2026-08-06
   "tall skinny photos" bug). Scoped to main so header/footer logos keep
   their attribute-set sizes. */
main img { max-width: 100%; height: auto; }

.content-photo {
 display: block;
 width: 100%;
 aspect-ratio: 16 / 9;   /* wide by default — the owner wants no tall photos */
 object-fit: cover;
 border-radius: var(--radius-lg);
 margin-block: var(--space-8);
}
/* Opt-out for genuinely portrait subjects (people), shown small + centered
   instead of cropped. */
.content-photo--portrait {
 aspect-ratio: auto;
 object-fit: unset;
 width: auto;
 max-width: min(420px, 100%);
 margin-inline: auto;
}
.content-photo--wide { aspect-ratio: 16 / 9; object-fit: cover; }
.content-photo__caption {
 margin-top: var(--space-2);
 font-size: var(--text-xs);
 color: var(--color-text-muted);
 text-align: center;
}

/* Project gallery — grouped-by-job grid on /project. */
.photo-gallery {
 display: grid;
 grid-template-columns: 1fr;
 gap: var(--space-5);
}
@media (min-width: 640px) {
 .photo-gallery { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 960px) {
 .photo-gallery { grid-template-columns: repeat(3, 1fr); }
}
.photo-gallery__item { display: flex; flex-direction: column; gap: var(--space-2); }
.photo-gallery__item img {
 display: block;
 width: 100%;
 aspect-ratio: 4 / 3;
 object-fit: cover;
 border-radius: var(--radius-base);
 border: 1px solid var(--color-border-default);
}
.photo-gallery__caption {
 font-size: var(--text-xs);
 color: var(--color-text-muted);
}

/* ---------------------------------------------------------------------
 6. HERO
 --------------------------------------------------------------------- */
.hero {
 position: relative;
 color: var(--color-text-inverse);
 overflow: hidden;
}
.hero__media {
 position: absolute;
 inset: 0;
 background:
 linear-gradient(rgba(var(--near-black-rgb), 0.62), rgba(var(--near-black-rgb), 0.5)),
 repeating-linear-gradient(120deg,
 rgba(255, 255, 255, 0.06) 0px, rgba(255, 255, 255, 0.06) 2px,
 transparent 2px, transparent 18px),
 var(--color-bg-header);
 z-index: 0;
}
/* .hero--photo: drop a real photo into any hero without duplicating the
   gradient block per page. Set the photo via the --hero-photo custom
   property (e.g. style="--hero-photo:url('/photos/x.jpg')") on the
   .hero element. Per the owner's hero rule, text never sits on a boxed
   overlay panel — the treatment is always this full-bleed gradient over
   the photo itself, plus a small contrast/saturation lift so real
   photography reads true instead of washed out. Mirrors the pattern
   first used on index.html's .hero--real. */
.hero--photo .hero__media {
 background-image:
 linear-gradient(180deg, rgba(var(--near-black-rgb), 0.62) 0%, rgba(var(--near-black-rgb), 0.50) 45%, rgba(var(--near-black-rgb), 0.64) 100%),
 var(--hero-photo);
 background-size: cover;
 background-position: center 38%;
 background-repeat: no-repeat;
 filter: contrast(1.04) saturate(1.05);
}
.hero__media-tag {
 position: absolute;
 bottom: var(--space-4);
 right: var(--space-4);
 z-index: 1;
 font-size: var(--text-xs);
 color: var(--white);
 opacity: 0.7;
 background: rgba(var(--near-black-rgb), 0.4);
 padding: var(--space-1) var(--space-3);
 border-radius: var(--radius-full);
}
.hero__content {
 position: relative;
 z-index: 1;
 padding-block: var(--space-20) var(--space-16);
 max-width: 760px;
}
/* On narrow phones the hero was running past a full screen tall (the
   photo background is set with background-size:cover, so a section this
   much taller than it is wide crops a real photo down to an unrecognizable
   sliver — the owner's exact "change the main photo to something I can see
   better" complaint traces back to this, not to any one photo). Trimming
   the padding here is the lever: it shortens the section without touching
   type size or removing any content. */
@media (max-width: 639px) {
 .hero__content { padding-block: var(--space-12) var(--space-10); }
}
.hero__eyebrow {
 font-size: var(--text-sm);
 font-weight: var(--weight-semibold);
 letter-spacing: var(--tracking-wide);
 text-transform: uppercase;
 color: var(--white);
 opacity: 0.9;
 margin-bottom: var(--space-4);
}
.hero__title {
 font-size: var(--text-4xl);
 color: var(--white);
 letter-spacing: var(--tracking-tight);
 margin-bottom: var(--space-5);
}
.hero__subtitle {
 font-size: var(--text-md);
 line-height: var(--leading-relaxed);
 color: var(--white);
 max-width: 56ch;
 margin-bottom: var(--space-8);
}

.proof-chips {
 display: flex;
 flex-wrap: wrap;
 gap: var(--space-3);
 margin-bottom: var(--space-8);
}
.proof-chip {
 display: inline-flex;
 align-items: center;
 gap: var(--space-2);
 padding: var(--space-2) var(--space-4);
 border-radius: var(--radius-full);
 background: rgba(255, 255, 255, 0.12);
 border: 1px solid rgba(255, 255, 255, 0.35);
 font-size: var(--text-sm);
 font-weight: var(--weight-medium);
 color: var(--white);
}
.proof-chip svg { width: 18px; height: 18px; flex: none; }
/* Gold, sparingly: only the review-star and TV icons, per brand
 direction. Icon-only so chip text stays white for readability against
 the photo scrim (gold text on white/red both fail contrast — see
 tokens.css known traps). */
.proof-chip__icon--gold { color: var(--color-rating-star); }

.hero__actions {
 display: flex;
 flex-wrap: wrap;
 gap: var(--space-4);
}

/* ---------------------------------------------------------------------
 7. REVIEW BAND
 --------------------------------------------------------------------- */
.reviews__head {
 display: flex;
 flex-wrap: wrap;
 align-items: center;
 justify-content: space-between;
 gap: var(--space-4);
 margin-bottom: var(--space-8);
}
.review-badge {
 display: inline-flex;
 align-items: center;
 gap: var(--space-3);
 padding: var(--space-3) var(--space-5);
 background: var(--color-bg-card);
 border: 1px solid var(--color-border-default);
 border-radius: var(--radius-base);
 box-shadow: var(--shadow-sm);
}
.review-badge__stars { display: flex; gap: 2px; color: var(--color-rating-star); }
.review-badge__stars svg { width: 18px; height: 18px; }
.review-badge__text { font-size: var(--text-sm); color: var(--color-text-body); font-weight: var(--weight-medium); }
.review-badge__text strong { display: block; font-size: var(--text-base); color: var(--color-text-heading); }

.reviews__list {
 display: grid;
 gap: var(--space-6);
 grid-template-columns: 1fr;
}
.review-card {
 background: var(--color-bg-card);
 border: 1px solid var(--color-border-default);
 border-radius: var(--radius-lg);
 padding: var(--space-6);
 box-shadow: var(--shadow-sm);
 display: flex;
 flex-direction: column;
 gap: var(--space-4);
}
.review-card__stars { display: flex; gap: 2px; color: var(--color-rating-star); }
.review-card__stars svg { width: 16px; height: 16px; }
.review-card blockquote {
 font-size: var(--text-base);
 line-height: var(--leading-relaxed);
 color: var(--color-text-body);
}
.review-card__author {
 font-weight: var(--weight-semibold);
 color: var(--color-text-heading);
 font-size: var(--text-sm);
}
.review-card__location { color: var(--color-text-muted); font-weight: var(--weight-regular); }

.reviews__stat {
 margin-top: var(--space-8);
 text-align: center;
 color: var(--color-text-muted);
 font-size: var(--text-sm);
}
.reviews__stat strong { color: var(--color-text-heading); font-family: var(--font-heading); font-size: var(--text-lg); }

@media (min-width: 768px) {
 .reviews__list { grid-template-columns: repeat(3, 1fr); }
}

/* ---------------------------------------------------------------------
 8. QUOTE FORM
 --------------------------------------------------------------------- */
.quote-form-wrap {
 background: var(--color-bg-card);
 border: 1px solid var(--color-border-default);
 border-radius: var(--radius-lg);
 box-shadow: var(--shadow-md);
 padding: var(--space-8);
 max-width: 720px;
 margin-inline: auto;
}

.form-error-summary {
 display: none;
 background: var(--color-bg-error);
 border: 1px solid var(--color-border-input-error);
 border-left: 4px solid var(--color-text-error);
 border-radius: var(--radius-base);
 padding: var(--space-4) var(--space-5);
 margin-bottom: var(--space-6);
 color: var(--color-text-error);
 font-weight: var(--weight-semibold);
 gap: var(--space-2);
 align-items: flex-start;
}
.form-error-summary.is-visible { display: flex; }
.form-error-summary svg { width: 22px; height: 22px; flex: none; margin-top: 2px; }
.form-error-summary a { text-decoration: underline; color: var(--color-text-error); }

.form-grid {
 display: grid;
 gap: var(--space-5);
 grid-template-columns: 1fr;
}
.form-field { display: flex; flex-direction: column; gap: var(--space-2); }
.form-field--span2 { grid-column: 1 / -1; }

.form-field label {
 font-weight: var(--weight-semibold);
 font-size: var(--text-sm);
 color: var(--color-text-heading);
}
.form-field .optional-tag {
 font-weight: var(--weight-regular);
 color: var(--color-text-muted);
 text-transform: none;
}
.form-field input[type="text"],
.form-field input[type="tel"],
.form-field input[type="email"],
.form-field input[type="number"],
.form-field select,
.form-field textarea {
 min-height: var(--touch-target-min);
 padding: var(--space-3) var(--space-4);
 border: 2px solid var(--color-border-input);
 border-radius: var(--radius-base);
 background: var(--color-bg-input);
 font-size: var(--text-base);
 color: var(--color-text-body);
}
.form-field textarea { min-height: 120px; resize: vertical; }
.form-field select {
 appearance: none;
 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B6B6B' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
 background-repeat: no-repeat;
 background-position: right var(--space-4) center;
 background-size: 18px;
 padding-right: var(--space-10);
}
.form-field input:focus-visible,
.form-field select:focus-visible,
.form-field textarea:focus-visible {
 outline: 3px solid var(--color-focus-ring);
 outline-offset: 1px;
 border-color: var(--color-focus-ring);
}
.form-field input[aria-invalid="true"],
.form-field select[aria-invalid="true"],
.form-field textarea[aria-invalid="true"] {
 border-color: var(--color-border-input-error);
}
.field-error {
 display: none;
 align-items: center;
 gap: var(--space-1);
 font-size: var(--text-sm);
 color: var(--color-text-error);
 font-weight: var(--weight-medium);
}
.field-error.is-visible { display: flex; }
.field-error svg { width: 16px; height: 16px; flex: none; }
.field-hint { font-size: var(--text-sm); color: var(--color-text-muted); }

.form-checkbox {
 display: flex;
 align-items: flex-start;
 gap: var(--space-3);
}
.form-checkbox input[type="checkbox"] {
 width: 24px; height: 24px;
 flex: none;
 margin-top: 2px;
 accent-color: var(--color-cta-bg);
}
.form-checkbox label { font-weight: var(--weight-regular); font-size: var(--text-sm); color: var(--color-text-body); }

.form-actions { margin-top: var(--space-2); }
.form-fine-print {
 font-size: var(--text-xs);
 color: var(--color-text-muted);
 margin-top: var(--space-3);
}

.form-success {
 display: none;
 text-align: center;
 padding: var(--space-10) var(--space-4);
}
.form-success.is-visible { display: block; }
.form-success__icon {
 width: 56px; height: 56px;
 margin-inline: auto var(--space-4);
 color: var(--color-text-success);
 background: var(--color-bg-success);
 border: 2px solid var(--color-text-heading);
 border-radius: var(--radius-full);
 display: flex; align-items: center; justify-content: center;
}
.form-success h3 { margin-bottom: var(--space-2); }
.form-success p { color: var(--color-text-muted); max-width: 46ch; margin-inline: auto; }
.quote-form.is-submitted .form-grid,
.quote-form.is-submitted .form-checkbox,
.quote-form.is-submitted .form-actions,
.quote-form.is-submitted .form-fine-print { display: none; }

@media (min-width: 640px) {
 .form-grid { grid-template-columns: 1fr 1fr; }
}

/* ---------------------------------------------------------------------
 9. VIDEO STRIP (YouTube facade — real iframe only injected on click)
 --------------------------------------------------------------------- */
.video-grid {
 display: grid;
 gap: var(--space-6);
 grid-template-columns: 1fr;
}
.video-card { display: flex; flex-direction: column; gap: var(--space-3); }
.video-thumb {
 position: relative;
 width: 100%;
 aspect-ratio: 16 / 9;
 border-radius: var(--radius-base);
 overflow: hidden;
 border: 0;
 padding: 0;
 cursor: pointer;
 background:
 linear-gradient(rgba(var(--near-black-rgb), 0.35), rgba(var(--near-black-rgb), 0.55)),
 repeating-linear-gradient(135deg,
 rgba(255, 255, 255, 0.08) 0px, rgba(255, 255, 255, 0.08) 2px,
 transparent 2px, transparent 16px),
 var(--color-bg-header);
}
.video-thumb__img {
 position: absolute;
 inset: 0;
 width: 100%;
 height: 100%;
 object-fit: cover;
 object-position: center;
 display: block;
}
.video-thumb--short .video-thumb__img { object-position: center 30%; }
.video-thumb__play {
 position: absolute;
 inset: 0;
 display: flex;
 align-items: center;
 justify-content: center;
}
.video-thumb__play svg {
 width: 64px; height: 64px;
 color: var(--white);
 filter: drop-shadow(0 2px 6px rgba(var(--near-black-rgb), 0.4));
}
.video-thumb:hover .video-thumb__play svg,
.video-thumb:focus-visible .video-thumb__play svg { transform: scale(1.08); }
.video-thumb__play svg { transition: transform var(--motion-base) var(--motion-ease); }
.video-thumb__duration {
 position: absolute;
 bottom: var(--space-2);
 right: var(--space-2);
 background: rgba(var(--near-black-rgb), 0.75);
 color: var(--white);
 font-size: var(--text-xs);
 font-weight: var(--weight-semibold);
 padding: 2px var(--space-2);
 border-radius: var(--radius-sm);
}
.video-card__title {
 font-size: var(--text-sm);
 font-weight: var(--weight-medium);
 color: var(--color-text-body);
 line-height: var(--leading-snug);
}
.video-embed-frame {
 width: 100%;
 aspect-ratio: 16 / 9;
 border: 0;
 border-radius: var(--radius-base);
}

@media (min-width: 768px) {
 .video-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
 .video-grid { grid-template-columns: repeat(4, 1fr); }
}

/* ---------------------------------------------------------------------
 10. PROCESS STRIP
 --------------------------------------------------------------------- */
.process-grid {
 display: grid;
 gap: var(--space-8);
 grid-template-columns: 1fr;
 counter-reset: process;
}
.process-step {
 position: relative;
 padding-top: var(--space-4);
 /* wood accent, not red — red is reserved exclusively for clickable CTAs
 so it never loses signal strength through decorative reuse */
 border-top: 3px solid var(--color-accent-wood);
}
.process-step__icon {
 width: 48px; height: 48px;
 color: var(--color-text-heading);
 margin-bottom: var(--space-4);
}
.process-step__number {
 font-family: var(--font-heading);
 font-size: var(--text-sm);
 font-weight: var(--weight-bold);
 color: var(--color-text-muted);
 letter-spacing: var(--tracking-wide);
 margin-bottom: var(--space-2);
}
.process-step h3 { font-size: var(--text-lg); margin-bottom: var(--space-2); }
.process-step p { color: var(--color-text-muted); }

@media (min-width: 768px) {
 .process-grid { grid-template-columns: repeat(3, 1fr); }
}

/* ---------------------------------------------------------------------
 11. FINANCING STRIP
 --------------------------------------------------------------------- */
.financing-strip {
 background: var(--color-strip-bg);
 color: var(--color-strip-text);
 border-block: 1px solid var(--color-border-default);
 padding-block: var(--space-6);
}
.financing-strip__row {
 display: flex;
 flex-wrap: wrap;
 align-items: center;
 justify-content: center;
 gap: var(--space-3);
 text-align: center;
 font-size: var(--text-base);
 font-weight: var(--weight-medium);
}
.financing-strip__row svg { width: 28px; height: 28px; color: var(--color-strip-accent); flex: none; }
.financing-strip strong { color: var(--color-text-heading); }
.financing-strip small { display: block; color: var(--color-text-muted); font-size: var(--text-xs); margin-top: var(--space-1); }

/* ---------------------------------------------------------------------
 12. SERVICE CARDS
 --------------------------------------------------------------------- */
.service-grid {
 display: grid;
 gap: var(--space-6);
 grid-template-columns: 1fr;
}
.service-card {
 display: flex;
 flex-direction: column;
 background: var(--color-bg-card);
 border: 1px solid var(--color-border-default);
 border-radius: var(--radius-lg);
 overflow: hidden;
 box-shadow: var(--shadow-sm);
 transition: box-shadow var(--motion-base) var(--motion-ease), transform var(--motion-base) var(--motion-ease);
}
.service-card:hover { box-shadow: var(--shadow-lg); transform: translateY(-2px); }
.service-card__body { padding: var(--space-6); display: flex; flex-direction: column; gap: var(--space-3); flex: 1; }
.service-card h3 { font-size: var(--text-lg); }
.service-card p { color: var(--color-text-muted); flex: 1; }
.service-card__links {
 display: flex;
 flex-wrap: wrap;
 gap: var(--space-4);
 margin-top: var(--space-2);
}
.service-card__links a {
 font-weight: var(--weight-semibold);
 font-size: var(--text-sm);
 color: var(--color-text-link);
 display: inline-flex;
 align-items: center;
 gap: var(--space-1);
 min-height: var(--touch-target-min);
}
.service-card__links a:hover,
.service-card__links a:focus-visible { color: var(--color-text-link-hover); text-decoration: underline; }
.service-card__links a.is-primary { color: var(--color-cta-bg); }
.service-card__links a.is-primary:hover,
.service-card__links a.is-primary:focus-visible { color: var(--color-cta-bg-hover); }
.service-card__links svg { width: 16px; height: 16px; }

@media (min-width: 640px) {
 .service-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
 .service-grid { grid-template-columns: repeat(4, 1fr); }
}

/* ---------------------------------------------------------------------
 13. BEFORE / AFTER SLIDER
 Vanilla JS drag + keyboard operable (Arrow Left/Right, Home, End).
 Respects prefers-reduced-motion (no transition on drag/keys, only an
 instant position update) — see components.html script.
 --------------------------------------------------------------------- */
.ba-slider {
 position: relative;
 width: 100%;
 aspect-ratio: 4 / 3;
 border-radius: var(--radius-lg);
 overflow: hidden;
 border: 1px solid var(--color-border-default);
 box-shadow: var(--shadow-sm);
 touch-action: pan-y;
 user-select: none;
}
.ba-slider__after,
.ba-slider__before {
 position: absolute;
 inset: 0;
 aspect-ratio: auto;
 border: 0;
 border-radius: 0;
}
.ba-slider__before {
 /* clipped by JS setting inline width % — starts at 50 */
 width: 50%;
 overflow: hidden;
}
.ba-slider__before .photo-placeholder,
.ba-slider__after .photo-placeholder {
 position: absolute;
 inset: 0;
 width: var(--ba-fixed-width, 100%);
 height: 100%;
 border-radius: 0;
 border: 0;
}
.ba-slider__before .photo-placeholder { width: 100vw; max-width: none; }
.ba-slider__handle {
 position: absolute;
 top: 0;
 bottom: 0;
 left: 50%;
 width: 4px;
 background: var(--white);
 transform: translateX(-50%);
 box-shadow: 0 0 0 1px rgba(var(--near-black-rgb), 0.25);
}
.ba-slider__handle-grip {
 position: absolute;
 top: 50%;
 left: 50%;
 transform: translate(-50%, -50%);
 width: var(--touch-target-min);
 height: var(--touch-target-min);
 border-radius: var(--radius-full);
 background: var(--white);
 color: var(--color-text-heading);
 display: flex;
 align-items: center;
 justify-content: center;
 box-shadow: var(--shadow-md);
 cursor: ew-resize;
 border: 3px solid var(--color-cta-bg);
}
.ba-slider__handle-grip:focus-visible {
 outline: 3px solid var(--color-focus-ring);
 outline-offset: 3px;
}
.ba-slider__handle-grip svg { width: 22px; height: 22px; }
.ba-slider__tag {
 position: absolute;
 top: var(--space-3);
 z-index: 1;
 padding: var(--space-1) var(--space-3);
 border-radius: var(--radius-full);
 font-size: var(--text-xs);
 font-weight: var(--weight-bold);
 letter-spacing: var(--tracking-wide);
 text-transform: uppercase;
 background: rgba(var(--near-black-rgb), 0.65);
 color: var(--white);
}
.ba-slider__tag--before { left: var(--space-3); }
.ba-slider__tag--after { right: var(--space-3); }
.ba-caption {
 margin-top: var(--space-3);
 font-size: var(--text-sm);
 color: var(--color-text-muted);
 text-align: center;
}

/* ---------------------------------------------------------------------
 13b. BEFORE/AFTER SLIDER — real-photo variant (color visualizer)
 The base .ba-slider above was built for the decorative .photo-placeholder
 fill: a width% + overflow:hidden "before" layer plus a 100vw inner trick
 works fine when the "image" is just a repeating stripe pattern, because
 nothing needs to stay in registration. Two REAL, pixel-aligned photos
 (same kitchen, different cabinet color) must stay perfectly aligned as
 the divider moves at any viewport width, so this modifier swaps the
 width-trick for clip-path on a full-size layer instead. Same handle/grip/
 tag markup and CSS, same keyboard model (Arrow keys, Home/End, Shift for
 a bigger step) — only the reveal mechanism changes.
 --------------------------------------------------------------------- */
.ba-slider--photo { aspect-ratio: 16 / 9; }
.ba-slider--photo .ba-slider__before {
 width: 100%;
 clip-path: inset(0 50% 0 0); /* JS updates the right inset as the handle moves */
}
.ba-slider--photo .ba-slider__before img,
.ba-slider--photo .ba-slider__after img {
 position: absolute;
 inset: 0;
 width: 100%;
 height: 100%;
 object-fit: cover;
 display: block;
}

/* Color-choice buttons under the visualizer slider */
.cv-colors {
 display: flex;
 flex-wrap: wrap;
 justify-content: center;
 gap: var(--space-3);
 margin-top: var(--space-5);
}
.cv-color-btn {
 display: inline-flex;
 align-items: center;
 gap: var(--space-2);
 min-height: var(--touch-target-min);
 padding: var(--space-2) var(--space-5);
 border-radius: var(--radius-full);
 border: 2px solid var(--color-border-default);
 background: var(--color-bg-card);
 font-family: var(--font-body);
 font-weight: var(--weight-semibold);
 font-size: var(--text-sm);
 color: var(--color-text-heading);
 cursor: pointer;
}
.cv-color-btn:hover,
.cv-color-btn:focus-visible { border-color: var(--color-text-link); }
.cv-color-btn[aria-pressed="true"] {
 border-color: var(--color-cta-bg);
 box-shadow: inset 0 0 0 2px var(--color-cta-bg);
}
.cv-color-btn__dot {
 width: 18px;
 height: 18px;
 border-radius: var(--radius-full);
 border: 1px solid rgba(var(--near-black-rgb), 0.15);
 flex: none;
}

/* ---------------------------------------------------------------------
 14. FOOTER — the only place disclaimers live (Canonical Decision #4)
 --------------------------------------------------------------------- */
.site-footer {
 background: var(--color-bg-footer);
 color: var(--color-text-inverse);
 padding-block: var(--space-16) var(--space-8);
}
.footer-grid {
 display: grid;
 gap: var(--space-10);
 grid-template-columns: 1fr;
 padding-bottom: var(--space-10);
 border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
/* Intentionally a styled <p>, not a heading element: footer nav groups are
 already labeled via aria-label on each <nav>, so no heading tag is
 introduced here. Keeps the document's heading outline (H1 → H2 → H3)
 uninterrupted by the footer, which sits after the last real heading. */
.footer-col-title {
 color: var(--color-text-inverse);
 font-size: var(--text-sm);
 font-weight: var(--weight-bold);
 letter-spacing: var(--tracking-wide);
 text-transform: uppercase;
 margin-bottom: var(--space-4);
}
.footer-col ul { display: flex; flex-direction: column; gap: var(--space-3); }
.footer-col a { color: var(--color-nav-link); opacity: 0.9; }
.footer-col a:hover, .footer-col a:focus-visible { text-decoration: underline; opacity: 1; }
.footer-brand p { color: var(--color-text-inverse); opacity: 0.85; max-width: 40ch; margin-top: var(--space-3); }
.footer-brand .site-header__phone { font-size: var(--text-lg); display: inline-block; margin-top: var(--space-4); }
.footer-social { display: flex; gap: var(--space-3); margin-top: var(--space-5); }
.footer-social a {
 width: 40px; height: 40px;
 display: flex; align-items: center; justify-content: center;
 border: 1px solid rgba(255, 255, 255, 0.4);
 border-radius: var(--radius-full);
}
.footer-social svg { width: 18px; height: 18px; }

.footer-bottom {
 margin-top: var(--space-8);
 display: flex;
 flex-direction: column;
 gap: var(--space-4);
 font-size: var(--text-xs);
 color: var(--color-text-inverse);
 opacity: 0.75;
}
.footer-disclaimer { max-width: 80ch; line-height: var(--leading-relaxed); }
.footer-legal { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); }
.footer-legal a { text-decoration: underline; }

@media (min-width: 640px) {
 .footer-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
 .footer-grid { grid-template-columns: 1.4fr 1fr 1fr 1fr; }
 .footer-bottom { flex-direction: row; align-items: center; justify-content: space-between; }
}

/* ---------------------------------------------------------------------
 15. MISC
 --------------------------------------------------------------------- */
.badge-row {
 display: flex;
 flex-wrap: wrap;
 gap: var(--space-3);
 align-items: center;
}

.eyebrow {
 display: inline-block;
 font-size: var(--text-sm);
 font-weight: var(--weight-semibold);
 letter-spacing: var(--tracking-wide);
 text-transform: uppercase;
 color: var(--color-cta-bg);
 margin-bottom: var(--space-3);
}

.showcase-block {
 border: 1px dashed var(--color-border-default);
 border-radius: var(--radius-lg);
 padding: var(--space-6);
 margin-bottom: var(--space-16);
}
.showcase-index {
 padding-block: var(--space-4);
 border-bottom: 1px solid var(--color-border-default);
 background: var(--color-bg-page-alt);
}
.showcase-index p {
 font-size: var(--text-xs);
 font-weight: var(--weight-bold);
 letter-spacing: var(--tracking-wide);
 text-transform: uppercase;
 color: var(--color-text-muted);
 margin-bottom: var(--space-2);
}
.showcase-index ul { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-5); }
.showcase-index a {
 display: inline-flex;
 align-items: center;
 min-height: 32px;
 font-size: var(--text-sm);
 font-weight: var(--weight-semibold);
 color: var(--color-text-link);
}
.showcase-index a:hover, .showcase-index a:focus-visible { color: var(--color-text-link-hover); text-decoration: underline; }

.showcase-block__label {
 display: inline-block;
 font-family: var(--font-body);
 font-size: var(--text-xs);
 font-weight: var(--weight-bold);
 letter-spacing: var(--tracking-wide);
 text-transform: uppercase;
 color: var(--color-text-muted);
 background: var(--color-bg-page-alt);
 padding: var(--space-1) var(--space-3);
 border-radius: var(--radius-sm);
 margin-bottom: var(--space-6);
}

/* Belt-and-suspenders global reduced-motion guard, in addition to the
 token-level override in tokens.css (covers any literal duration a
 future component author forgets to tokenize). */
@media (prefers-reduced-motion: reduce) {
 *, *::before, *::after {
 animation-duration: 0.01ms !important;
 animation-iteration-count: 1 !important;
 transition-duration: 0.01ms !important;
 }
}
