/* ==========================================================================
   San Antonio Garage Door Co — theme tokens derived from the brand logo
   (charcoal ink + magenta accent). Mobile-first, no build step.
   ========================================================================== */

:root {
  --color-ink: #18171b;
  --color-ink-soft: #34323b;
  --color-accent: #d10cd9;
  --color-accent-dark: #970a9e;
  --color-accent-light: #f6def9;
  --color-bg: #ffffff;
  --color-bg-alt: #faf5fb;
  --color-bg-dark: #18171b;
  --color-border: #e9e2eb;
  --color-text: #262430;
  --color-text-muted: #5c5866;
  --color-white: #ffffff;
  --font-display: "Barlow Condensed", "Arial Narrow", sans-serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --radius: 14px;
  --radius-sm: 8px;
  --shadow-sm: 0 1px 3px rgba(20, 16, 22, 0.08);
  --shadow-md: 0 12px 28px rgba(20, 16, 22, 0.14);
  --shadow-lg: 0 20px 45px rgba(20, 16, 22, 0.22);
  --header-h: 118px;
  --floating-bar-h: 60px;
  --wrap: 1180px;
  --divider-h: 48px;
}

* { box-sizing: border-box; }

/* Decorative background shapes - subtle texture behind section content,
   never interactive, always beneath the real content's stacking order. */
.decor { position: absolute; z-index: 0; pointer-events: none; }
.decor-dots {
  width: 150px; height: 150px; opacity: 0.35;
  background-image: radial-gradient(circle, var(--color-accent) 1.6px, transparent 1.6px);
  background-size: 18px 18px;
}
.tone-ink .decor-dots { opacity: 0.18; }
.decor-blob {
  width: 340px; height: 340px; opacity: 0.07;
  border-radius: 42% 58% 65% 35% / 45% 45% 55% 55%;
  background: var(--color-accent);
}
.tone-ink .decor-blob { opacity: 0.14; }
.decor-ring {
  width: 220px; height: 220px; border-radius: 50%; opacity: 0.5;
  border: 2px dashed var(--color-accent);
}
.tone-ink .decor-ring { opacity: 0.2; border-color: #fff; }
.decor-grid {
  width: 140px; height: 140px; opacity: 0.4;
  background-image: linear-gradient(var(--color-accent) 1px, transparent 1px), linear-gradient(90deg, var(--color-accent) 1px, transparent 1px);
  background-size: 20px 20px;
}
.tone-ink .decor-grid { opacity: 0.16; }
.decor-arc {
  width: 190px; height: 190px; border-radius: 50%;
  border: 36px solid var(--color-accent); opacity: 0.08;
}
.tone-ink .decor-arc { opacity: 0.14; }
.decor-diamond {
  width: 150px; height: 150px; opacity: 0.35;
  border: 2px dashed var(--color-accent); transform: rotate(45deg);
}
.tone-ink .decor-diamond { opacity: 0.16; border-color: #fff; }
.decor-top-right { top: -30px; right: -20px; }
.decor-bottom-left { bottom: -40px; left: -30px; }
.decor-bottom-right { bottom: -50px; right: -60px; }
.decor-top-left { top: -20px; left: -20px; }
.decor-mid-right { top: 50%; right: -80px; transform: translateY(-50%); }
@media (max-width: 700px) {
  .decor { display: none; }
}
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--color-text);
  background: var(--color-bg);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--color-accent-dark); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.1;
  color: var(--color-ink);
  letter-spacing: 0.01em;
  margin: 0 0 0.5em;
}
h1 { font-size: clamp(2rem, 5vw + 1rem, 3.4rem); }
h2 { font-size: clamp(1.5rem, 2.6vw + 1rem, 2.2rem); }
h3 { font-size: 1.25rem; }
p { margin: 0 0 1em; }
ul, ol { padding-left: 1.25em; }
.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 20px; }
.wrap-narrow { max-width: 820px; }
.skip-link {
  position: absolute; left: -999px; top: 0; background: var(--color-ink); color: #fff;
  padding: 10px 16px; z-index: 200; border-radius: 0 0 8px 0;
}
.skip-link:focus { left: 0; }

/* Buttons ---------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--font-display); font-weight: 600; font-size: 1.05rem;
  letter-spacing: 0.02em; text-transform: uppercase;
  padding: 12px 22px; border-radius: var(--radius-sm); border: 2px solid transparent;
  cursor: pointer; text-decoration: none; transition: transform 0.15s ease, background-color 0.15s ease;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn-primary { background: var(--color-accent); color: #fff; }
.btn-primary:hover { background: var(--color-accent-dark); }
.btn-ghost { border-color: var(--color-ink); color: var(--color-ink); background: transparent; }
.btn-ghost:hover { background: var(--color-ink); color: #fff; }
.btn-outline-light { border-color: #fff; color: #fff; }
.btn-outline-light:hover { background: #fff; color: var(--color-ink); }
.btn-lg { padding: 15px 28px; font-size: 1.1rem; }
.btn-block { display: flex; width: 100%; margin-top: 12px; }

/* Header ------------------------------------------------------------------ */
/* z-index:200, not 100: .site-header creates its own stacking context, so
   the mobile nav drawer nested inside it (z-index:160) is capped at
   whatever stacking position .site-header itself has relative to page
   siblings like .floating-call-bar (z-index:150) - a child's z-index
   can't "escape" its ancestor's stacking level. At 100 the header (and
   everything in it, including the open drawer) rendered BELOW the
   floating call button. */
.site-header { position: sticky; top: 0; z-index: 200; background: var(--color-white); box-shadow: var(--shadow-sm); }
.header-top { background: var(--color-ink); color: #fff; font-size: 0.85rem; }
.header-top-inner { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 7px 20px; flex-wrap: wrap; }
.header-tagline { margin: 0; opacity: 0.9; }
.header-phone { color: #fff; font-weight: 700; display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.header-phone .icon { width: 16px; height: 16px; fill: var(--color-accent); }
.header-main { display: flex; align-items: center; justify-content: space-between; padding: 8px 20px; gap: 16px; }
.brand-logo { height: 68px; width: auto; } /* padding above trimmed to match, so header-main's total height is unchanged */
/* Flex row so a visible .brand-name (see below) sits beside the logo
   instead of wrapping under it - the base img reset is display:block,
   which would otherwise put the two on separate lines. No effect on
   any site where .brand-name stays hidden: a flex container with one
   visible child renders identically to a block one. */
.brand { display: flex; align-items: center; }
/* Hidden by default everywhere - only variant P's header markup emits
   this span, and only Webster (below) turns it on. See that site's
   own override for why. */
.brand-name { display: none; }
.primary-nav > ul { list-style: none; display: flex; align-items: center; gap: 22px; margin: 0; padding: 0; }
.primary-nav { display: flex; align-items: center; gap: 24px; }
.primary-nav > ul > li > a {
  color: var(--color-ink); font-family: var(--font-display); font-weight: 600;
  text-transform: uppercase; font-size: 0.98rem; letter-spacing: 0.02em; padding: 8px 2px; display: inline-block;
  white-space: nowrap;
}
.primary-nav > ul > li > a:hover, .primary-nav > ul > li > a[aria-current="page"] { color: var(--color-accent); text-decoration: none; }
.dropdown-caret { width: 10px; height: 7px; margin-left: 5px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; transition: transform 0.2s ease; vertical-align: middle; position: relative; top: -1px; }
.has-dropdown { position: relative; }
.has-dropdown:hover .dropdown-caret, .has-dropdown:focus-within .dropdown-caret, .has-dropdown.is-open .dropdown-caret { transform: rotate(180deg); }
.dropdown {
  /* top:100%, zero gap: the box sits flush against the trigger so there's
     no dead zone the pointer can slip through while moving down to it -
     even a small real gap here would drop :hover on .has-dropdown
     mid-transit and close the menu before the pointer arrives. The extra
     top padding (rather than a margin/gap) gives it visual breathing room
     without creating one, since padding is still part of the hoverable box. */
  display: block; list-style: none; position: absolute; top: 100%; left: 0; padding: 14px 8px 8px;
  width: 240px; background: #fff;
  border: 1px solid var(--color-border); border-radius: var(--radius-sm); box-shadow: var(--shadow-md);
  opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(2px) scale(0.98); transform-origin: top left;
  transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s; z-index: 50; margin: 0;
}
.has-dropdown-right .dropdown { transform-origin: top right; }
.dropdown::before {
  content: ""; position: absolute; top: -6px; left: 20px; width: 12px; height: 12px; background: #fff;
  border-left: 1px solid var(--color-border); border-top: 1px solid var(--color-border); transform: rotate(45deg);
}
.has-dropdown-right .dropdown::before { left: auto; right: 20px; }
.has-dropdown:hover .dropdown, .has-dropdown:focus-within .dropdown { opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0) scale(1); }
/* The rightmost nav items sit close to the viewport edge - hang their
   flyout from the right so it opens inward instead of running off-screen. */
.has-dropdown-right .dropdown { left: auto; right: 0; }
.dropdown li a { display: block; padding: 8px 12px; color: var(--color-text); text-transform: none; font-family: var(--font-body); font-weight: 500; border-radius: 6px; }
.dropdown li a:hover { background: var(--color-bg-alt); color: var(--color-accent-dark); text-decoration: none; }
.link-arrow { width: 13px; height: 13px; margin-left: 4px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; vertical-align: middle; position: relative; top: -1px; }
.nav-cta { margin-left: 4px; }
.nav-toggle { display: none; flex-direction: column; justify-content: center; gap: 5px; width: 42px; height: 38px; background: none; border: 1px solid var(--color-border); border-radius: 8px; cursor: pointer; }
.nav-toggle span { display: block; height: 2px; background: var(--color-ink); border-radius: 2px; }
.nav-backdrop { display: none; }
.nav-close { display: none; }

/* Breadcrumbs -------------------------------------------------------------- */
.breadcrumbs { background: var(--color-bg-alt); border-bottom: 1px solid var(--color-border); font-size: 0.85rem; }
.breadcrumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 10px 0; }
.breadcrumbs li:not(:last-child)::after { content: "/"; margin-left: 6px; color: var(--color-text-muted); }
.breadcrumbs li[aria-current="page"] { color: var(--color-text-muted); }

/* Section tone alternation --------------------------------------------------*/
.tone-bg { background: var(--color-bg); }
.tone-alt { background: var(--color-bg-alt); }
.tone-ink { background: var(--color-ink); color: #f1eff2; }
.tone-ink h2, .tone-ink h3 { color: #fff; }
.tone-ink p { color: #d3cfd6; }
.tone-ink .content-section p { color: #d3cfd6; }

/* Decorative section divider shapes ----------------------------------------*/
.shape-divider { position: absolute; left: 0; right: 0; bottom: -1px; height: var(--divider-h); overflow: hidden; line-height: 0; pointer-events: none; }
.shape-divider svg { width: 100%; height: 100%; display: block; }
.shape-to-bg polygon { fill: var(--color-bg); }
.shape-to-alt polygon { fill: var(--color-bg-alt); }
.shape-to-ink polygon { fill: var(--color-ink); }

/* Hero ---------------------------------------------------------------------*/
.hero { position: relative; color: #fff; overflow: hidden; }
.hero-media { position: absolute; inset: 0; }
.hero-media img { width: 100%; height: 100%; object-fit: cover; }
/* The last gradient stop used to be a hardcoded rgba(209,12,217,...) -
   San Antonio's own accent, from before this file was shared across
   multiple sites' theme colors. color-mix() ties it to each site's own
   --color-accent instead, so the hero scrim actually tints toward
   whatever color that site's logo produced. */
.hero-scrim { position: absolute; inset: 0; background: linear-gradient(100deg, rgba(23,22,26,0.94) 15%, rgba(23,22,26,0.62) 62%, color-mix(in srgb, var(--color-accent) 35%, transparent) 100%); }
.hero-inner { position: relative; padding: 68px 20px 76px; }
.hero-copy { max-width: 700px; }
.eyebrow { font-family: var(--font-display); text-transform: uppercase; letter-spacing: 0.12em; color: var(--color-accent); font-weight: 700; margin-bottom: 10px; font-size: 0.95rem; display: inline-flex; align-items: center; gap: 8px; }
.eyebrow::before { content: ""; width: 26px; height: 3px; background: var(--color-accent); border-radius: 2px; display: inline-block; }
.hero h1 { color: #fff; }
.hero-lead { font-size: 1.15rem; color: #ecebee; max-width: 60ch; }
.hero-actions { display: flex; gap: 14px; flex-wrap: wrap; margin: 22px 0; }
.trust-badges { list-style: none; display: flex; gap: 18px; flex-wrap: wrap; padding: 0; margin: 10px 0 0; font-size: 0.9rem; }
.trust-badges li { display: flex; align-items: center; gap: 6px; color: #d9d7de; }
.trust-badges li::before { content: "\2713"; color: var(--color-accent); font-weight: 700; }

/* Content sections ---------------------------------------------------------*/
.content-section { padding: 44px 0; position: relative; overflow: hidden; }
.content-section > .wrap { position: relative; z-index: 1; }
.content-section p { color: var(--color-text); }
.content-section-media { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: 36px; align-items: center; }
.content-section-media.reverse .content-section-media-figure { order: -1; }
.content-section-media-figure { border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-md); aspect-ratio: 4 / 3; }
.content-section-media-figure img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.4s ease; }
.content-section-media-figure:hover img { transform: scale(1.06); }
/* Feature pattern - contentSections() cycles every third section into this
   photo-less, decorative-shape-and-numeral treatment instead of repeating
   the media-left/media-right pattern for every section on the page. */
.content-section-feature-mark {
  display: block; font-family: var(--font-display); font-weight: 700;
  font-size: 3.2rem; line-height: 1; color: var(--color-accent); opacity: 0.32;
  margin-bottom: -0.22em;
}
/* Real, clickable neighborhood/suburb chips (see sections.js areaChips())
   for the "Areas We Cover" section - same location data and links as the
   footer, instead of leaving place names stranded inside a paragraph. */
.area-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 18px 0 4px; }
.area-chip {
  display: inline-flex; align-items: center; padding: 7px 14px;
  background: var(--color-bg-alt); color: var(--color-ink); font-weight: 600; font-size: 0.86rem;
  border-radius: var(--radius-sm); border: 1px solid var(--color-border);
}
.area-chip:hover { background: var(--color-accent-light); border-color: var(--color-accent); color: var(--color-accent-dark); text-decoration: none; }
.area-chip-more { background: var(--color-accent); color: #fff; border-color: var(--color-accent); gap: 4px; }
.area-chip-more:hover { background: var(--color-accent-dark); color: #fff; }
.area-chip-more .link-arrow { width: 11px; height: 11px; }

/* Photo service cards -------------------------------------------------------*/
.services-grid-section { padding: 56px 0; position: relative; overflow: hidden; }
.services-grid-section > .wrap { position: relative; z-index: 1; }
.services-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 26px; margin-top: 28px; }
.service-card { background: #fff; border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-sm); transition: transform 0.18s ease, box-shadow 0.18s ease; display: flex; flex-direction: column; }
.service-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); text-decoration: none; }
.service-card-media { position: relative; aspect-ratio: 16 / 11; overflow: hidden; }
.service-card-media img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.35s ease; }
.service-card:hover .service-card-media img { transform: scale(1.06); }
.service-icon {
  /* Fully contained within the photo (top-left corner), not straddling
     the photo/body seam - a badge that overlaps two different
     backgrounds reads as broken rather than deliberate. */
  position: absolute; left: 14px; top: 14px; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 12px; background: var(--color-accent); box-shadow: var(--shadow-md);
}
.service-icon svg { width: 21px; height: 21px; fill: #fff; }
.service-card-body { padding: 22px; }
.service-card h3 { margin-bottom: 6px; }
.service-card p { color: var(--color-text-muted); font-size: 0.95rem; }
.service-card-link { color: var(--color-accent-dark); font-weight: 700; font-size: 0.9rem; }

/* Gallery / recent work - a quilted grid (see sections.js: gallery()):
   a true CSS grid where every photo's edges snap to shared row/column
   lines, with some tiles spanning 2x1 or 1x2 for a mosaic look. Unlike
   masonry's independently-flowing columns, a grid can't produce a
   ragged bottom edge - every row is a real row. ------------------------*/
.gallery-section { padding: 56px 0; position: relative; overflow: hidden; }
.gallery-section > .wrap { position: relative; z-index: 1; }
.gallery-grid {
  display: grid; grid-template-columns: repeat(var(--quilt-cols, 3), 1fr);
  grid-auto-rows: 150px; gap: 14px; margin-top: 26px;
}
.gallery-grid figure {
  margin: 0; border-radius: var(--radius-sm); overflow: hidden; position: relative;
  box-shadow: var(--shadow-sm); display: block;
}
.gallery-grid img { width: 100%; height: 100%; display: block; object-fit: cover; transition: transform 0.4s ease, filter 0.4s ease; }
.gallery-grid figure:hover img { transform: scale(1.08); }
.gallery-grid figcaption {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 8px 10px 6px;
  background: linear-gradient(0deg, rgba(15,14,17,0.75), transparent); color: #fff; font-size: 0.78rem; font-weight: 600;
  opacity: 0; transition: opacity 0.2s ease;
}
.gallery-grid figure:hover figcaption { opacity: 1; }

/* Trust / stat band -----------------------------------------------------*/
.trust-band { padding: 52px 0; position: relative; overflow: hidden; }
.trust-band > .wrap { position: relative; z-index: 1; }
.trust-band-photo { color: #fff; background-size: cover; background-position: center; background-repeat: no-repeat; }
.trust-band-scrim { position: absolute; inset: 0; background: linear-gradient(115deg, rgba(23,22,26,0.93) 10%, rgba(23,22,26,0.7) 100%); z-index: 0; }
/* Parallax: same "stuck while you scroll past" treatment as
   .cta-photo-band-parallax, desktop only (background-attachment:fixed is
   unreliable and can cause scroll jank on mobile, notably iOS Safari). */
@media (min-width: 1025px) {
  .trust-band-photo-parallax { background-attachment: fixed; }
}
.trust-band-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; margin-top: 28px; }
.trust-band-item { display: flex; flex-direction: column; gap: 8px; padding: 22px; border-radius: var(--radius); background: rgba(255,255,255,0.06); }
.tone-bg .trust-band-item, .tone-alt .trust-band-item { background: #fff; box-shadow: var(--shadow-sm); border: 1px solid var(--color-border); }
.trust-band-icon { width: 40px; height: 40px; border-radius: 10px; background: var(--color-accent); display: flex; align-items: center; justify-content: center; }
.trust-band-icon svg { width: 20px; height: 20px; fill: #fff; }
.trust-band-item strong { font-family: var(--font-display); font-size: 1.5rem; letter-spacing: 0.01em; }
.trust-band-item span { font-size: 0.88rem; color: inherit; opacity: 0.85; }

/* Process / how-it-works steps ---------------------------------------------*/
.process-section { padding: 56px 0; position: relative; overflow: hidden; }
.process-section > .wrap { position: relative; z-index: 1; }
.process-grid { list-style: none; margin: 28px 0 0; padding: 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; counter-reset: step; }
.process-step { position: relative; padding: 28px 20px 22px; background: #fff; border: 1px solid var(--color-border); border-radius: var(--radius); box-shadow: var(--shadow-sm); }
.tone-alt .process-step, .tone-ink .process-step { background: rgba(255,255,255,0.9); }
.process-step-number {
  position: absolute; top: -14px; left: 20px; width: 30px; height: 30px; border-radius: 50%;
  background: var(--color-ink); color: #fff; font-family: var(--font-display); font-weight: 700;
  display: flex; align-items: center; justify-content: center; font-size: 0.95rem; box-shadow: var(--shadow-sm);
}
.process-step-icon { display: flex; width: 42px; height: 42px; border-radius: 10px; background: var(--color-accent-light); align-items: center; justify-content: center; margin: 10px 0 14px; }
.process-step-icon svg { width: 20px; height: 20px; fill: var(--color-accent-dark); }
.process-step h3 { font-size: 1.1rem; margin-bottom: 6px; }
.process-step p { color: var(--color-text-muted); font-size: 0.92rem; margin: 0; }
.process-grid li:not(:last-child)::after {
  content: ""; position: absolute; top: 45%; left: 100%; width: 24px; height: 2px; background: var(--color-border);
  display: none;
}
@media (min-width: 1025px) {
  .process-grid li:not(:last-child)::after { display: block; }
}

/* CTA photo band (mid-page promo banner) -------------------------------------*/
.cta-photo-band {
  position: relative; color: #fff; overflow: hidden; min-height: 320px; display: flex; align-items: center;
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
/* Parallax: the photo stays fixed to the viewport while the page scrolls
   past it, so the section appears to slide over a static image - desktop
   only, since background-attachment:fixed is unreliable and can cause
   scroll jank on mobile browsers (notably iOS Safari, which never
   properly supported it). Mobile keeps a normal scrolling background. */
@media (min-width: 1025px) {
  .cta-photo-band-parallax { background-attachment: fixed; }
}
.cta-photo-band-scrim { position: absolute; inset: 0; background: linear-gradient(115deg, rgba(151,10,158,0.92) 0%, rgba(24,23,27,0.88) 100%); }
.cta-photo-band-inner { position: relative; padding: 52px 20px; display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.cta-photo-band h2 { color: #fff; margin-bottom: 6px; }
.cta-photo-band p { color: #f3e6f5; max-width: 46ch; margin: 0; }

/* Link grid (areas we serve, related links) --------------------------------*/
.link-grid-section { padding: 52px 0; }
.link-grid { list-style: none; margin: 20px 0 0; padding: 0; display: grid; grid-template-columns: repeat(var(--cols, 3), 1fr); gap: 12px; }
.link-grid li a { display: flex; align-items: center; gap: 10px; padding: 14px 16px; background: #fff; border-radius: var(--radius-sm); border: 1px solid var(--color-border); font-weight: 600; color: var(--color-ink); box-shadow: var(--shadow-sm); }
.link-grid li a::before { content: ""; flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--color-accent); }
.link-grid li a:hover { border-color: var(--color-accent); color: var(--color-accent-dark); text-decoration: none; transform: translateY(-2px); }
.link-grid li a span { font-weight: 400; font-size: 0.85rem; color: var(--color-text-muted); }

/* Area directory (hub page) ------------------------------------------------*/
.area-directory-section { padding: 52px 0; }
.area-directory { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 24px; margin-top: 20px; }
.area-group { background: #fff; border: 1px solid var(--color-border); border-radius: var(--radius-sm); padding: 16px 18px; box-shadow: var(--shadow-sm); }
.area-group h3 { color: var(--color-accent-dark); font-size: 1rem; margin-bottom: 8px; border-bottom: 2px solid var(--color-accent); display: inline-block; padding-bottom: 2px; }
.area-group ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
.area-group li a { color: var(--color-text); font-size: 0.92rem; }
.area-group li a:hover { color: var(--color-accent-dark); }

/* FAQ ------------------------------------------------------------------- */
.faq-section { padding: 48px 0; }
.faq-list { margin-top: 20px; display: flex; flex-direction: column; gap: 10px; }
.faq-item { border: 1px solid var(--color-border); border-radius: var(--radius-sm); padding: 4px 18px; background: #fff; transition: border-color 0.2s ease, box-shadow 0.2s ease; }
.faq-item.is-open { border-color: var(--color-accent); box-shadow: var(--shadow-sm); }
.faq-item summary { cursor: pointer; font-weight: 700; padding: 14px 0; font-family: var(--font-display); font-size: 1.05rem; list-style: none; position: relative; padding-right: 28px; }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "+"; position: absolute; right: 0; top: 12px; font-size: 1.4rem; color: var(--color-accent); line-height: 1;
  transition: transform 0.3s ease;
}
.faq-item[open] summary::after { transform: rotate(45deg); }
/* Native <details> shows/hides its content instantly via the `open`
   attribute with no way to transition "auto" height. With JS available,
   main.js takes over: it intercepts the toggle, measures the real
   content height, and animates max-height/opacity itself (see
   .faq-item.is-open below, driven by the JS-set inline max-height).
   Without JS, .js never gets added to <html> and the native instant
   open/close still works fully - just without the animation. */
.js .faq-answer { display: block; max-height: 0; overflow: hidden; opacity: 0; transition: max-height 0.35s ease, opacity 0.3s ease; }
.js .faq-item.is-open .faq-answer { opacity: 1; }
.faq-answer p { color: var(--color-text-muted); padding-bottom: 14px; }

/* CTA band ---------------------------------------------------------------*/
/* A visibly different shade from the footer that usually follows it
   (var(--color-ink-soft), not --color-ink, which is identical to
   --color-bg-dark) - back to back, two identical near-black sections
   read as one undifferentiated block with no visible seam. */
.cta-band { background: var(--color-ink-soft); color: #fff; padding: 40px 0; position: relative; overflow: hidden; }
.cta-band > .wrap { position: relative; z-index: 1; }
.cta-band-inner { display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.cta-band h2 { color: #fff; margin-bottom: 4px; }
.cta-band p { color: #cfccd4; margin: 0; }

/* Contact card / two column trust layout ----------------------------------*/
.wrap-narrow-with-aside { max-width: var(--wrap); margin: 0 auto; padding: 44px 20px; }
.wrap-narrow-with-aside.has-aside { display: grid; grid-template-columns: 1fr 320px; gap: 40px; align-items: start; }
.contact-card { background: var(--color-bg-alt); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 26px; position: sticky; top: calc(var(--header-h) + 20px); }
.contact-card h2 { font-size: 1.2rem; }
.contact-card p { font-size: 0.95rem; margin-bottom: 14px; }

/* Quote request form -------------------------------------------------------*/
.quote-form-section { padding: 52px 0; position: relative; overflow: hidden; }
.quote-form-section > .wrap { position: relative; z-index: 1; }
.quote-form-card { background: #fff; border: 1px solid var(--color-border); border-radius: var(--radius); box-shadow: var(--shadow-md); padding: 32px; max-width: 640px; margin: 0 auto; }
.quote-form-card h2 { margin-bottom: 6px; }
.quote-form-card > p { color: var(--color-text-muted); margin-bottom: 22px; }
.quote-form { display: flex; flex-direction: column; gap: 16px; }
.quote-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.quote-form label { display: flex; flex-direction: column; gap: 6px; font-size: 0.9rem; font-weight: 600; color: var(--color-ink); }
.quote-form label em { color: var(--color-accent); font-style: normal; margin-left: 2px; }
.quote-form input, .quote-form select, .quote-form textarea {
  font: inherit; padding: 11px 12px; border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-bg-alt); color: var(--color-text); width: 100%;
}
.quote-form input:focus, .quote-form select:focus, .quote-form textarea:focus {
  outline: 2px solid var(--color-accent); outline-offset: 1px; background: #fff;
}
.quote-form textarea { resize: vertical; min-height: 90px; }
.quote-form-note { font-size: 0.82rem; color: var(--color-text-muted); text-align: center; margin: 0; }
.quote-form-note[data-state="error"] { color: #b3261e; }
.quote-form-note[data-state="ok"] { color: #1a7a3c; }
@media (max-width: 560px) {
  .quote-form-row { grid-template-columns: 1fr; }
  .quote-form-card { padding: 22px; }
}

/* Legal pages ------------------------------------------------------------*/
.legal-hero { background: var(--color-bg-alt); padding: 44px 0 24px; border-bottom: 1px solid var(--color-border); }
.legal-body { padding: 36px 0 60px; }
.legal-body h2 { margin-top: 1.6em; font-size: 1.3rem; }

/* Footer -------------------------------------------------------------------*/
.site-footer { background: var(--color-bg-dark); color: #cfccd4; padding: 56px 0 0; }
.footer-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 32px; padding-bottom: 40px; }
.footer-col h2 { color: #fff; font-size: 1.05rem; margin-bottom: 14px; }
.footer-col ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
.footer-col a { color: #cfccd4; font-size: 0.92rem; }
.footer-col a:hover { color: var(--color-accent); }
/* Every logo in this photo library mixes a dark charcoal/black line-art
   element (roofline, house outline) with the brand accent color - fine
   on the white background the source PNGs ship with, but the
   transparency step (make_logo_transparent.py) strips exactly that
   white, so those dark strokes go near-invisible against the footer's
   own dark background (var(--color-bg-dark)) on every site. A white
   card behind the logo restores the contrast the artwork was designed
   for, everywhere the footer's dark background is used. */
.footer-brand img { background: #fff; border-radius: var(--radius-sm); margin-bottom: 14px; }
.footer-brand p { font-size: 0.92rem; }
.footer-nap { font-size: 0.9rem; }
.footer-nap p { display: flex; align-items: flex-start; gap: 10px; margin: 0 0 10px; }
.footer-nap p:last-child { margin-bottom: 0; }
.footer-nap-icon { flex: none; display: flex; margin-top: 0.15em; opacity: 0.75; }
/* currentColor, not --color-accent: the accent is only guaranteed to
   read against white (extract_logo_color.py's contrast safeguard), not
   against the footer's own dark background - some extracted accents
   (e.g. a deep navy) are nearly invisible there. The footer's own text
   color is already proven safe against whatever background it's on
   (dark ink by default, or white on Oklahoma City's override), so the
   icon just inherits it instead of introducing an unverified color. */
.footer-nap-icon svg { width: 15px; height: 15px; fill: currentColor; }
.footer-nap a { color: #fff; font-weight: 600; }
.footer-bottom { border-top: 1px solid rgba(255,255,255,0.12); padding: 18px 20px; display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; font-size: 0.85rem; }
.footer-legal { list-style: none; display: flex; gap: 16px; margin: 0; padding: 0; }
.footer-legal a { color: #a7a3ae; }

/* Site-specific request (Oklahoma City only, not the variant it happens
   to be on, and not the CTA band above it) - a white footer instead of
   the shared dark one. Scoped via data-site rather than touching
   variant-e.css, since this is a one-off preference for this domain,
   not a design change for every future site that lands on variant E. */
[data-site="oklahomacitygaragedoorpros.com"] .site-footer { background: #fff; color: var(--color-text); border-top: 1px solid var(--color-border); }
[data-site="oklahomacitygaragedoorpros.com"] .footer-col h2 { color: var(--color-ink); }
[data-site="oklahomacitygaragedoorpros.com"] .footer-col a { color: var(--color-text-muted); }
[data-site="oklahomacitygaragedoorpros.com"] .footer-col a:hover { color: var(--color-accent-dark); }
[data-site="oklahomacitygaragedoorpros.com"] .footer-nap a { color: var(--color-ink); }
[data-site="oklahomacitygaragedoorpros.com"] .footer-bottom { border-top-color: var(--color-border); }
[data-site="oklahomacitygaragedoorpros.com"] .footer-legal a { color: var(--color-text-muted); }

/* Bigger header logo for these two sites specifically - requested on
   these two only, not a design change for every site on variant F or
   H, so scoped via data-site rather than touching variant-f.css /
   variant-h.css. Oak Park's variant F default is 52px (this variant's
   own smaller/restrained sizing); Davie's variant H has no override,
   so it inherits main.css's 68px default - both bumped to the same
   84px for legibility. */
[data-site="oakparkgaragedoorpros.com"] .brand-logo,
[data-site="daviegaragedoorpros.com"] .brand-logo { height: 84px; }

/* The Villages (variant I): two fixes, requested on this site only.
   1. .site-header-i's backdrop-filter (the glassmorphism sticky-header
      blur) makes the header a CSS containing block for any descendant
      position:fixed element - including the mobile drawer, whose
      top:0/bottom:0 then resolve against the ~90px-tall header instead
      of the viewport, collapsing the drawer to header-height instead
      of full-screen. Dropping backdrop-filter only inside the mobile
      breakpoint (where the header's translucency isn't visible behind
      the opaque-white drawer anyway) fixes the drawer without touching
      the desktop glass effect.
   2. variant-i.css's .nav-cta is a full pill (border-radius: 999px)
      while every other button on the site (Call, Request a Quote) uses
      the shared var(--radius-sm) - resetting it to match. */
@media (max-width: 1024px) {
  [data-site="thevillagesgaragedoorpros.com"] .site-header-i { backdrop-filter: none; }
}
[data-site="thevillagesgaragedoorpros.com"] .site-header-i .nav-cta { border-radius: var(--radius-sm); }

/* Huntersville (variant N): the mobile header's 14px top/bottom padding
   plus the 74px logo reads as too tall/bulky on small screens -
   requested on this site only, so scoped via data-site rather than
   touching variant-n.css's shared .header-main padding (which also
   sizes Danville's and Orange's headers). Desktop padding is untouched.
   Selector includes .site-header-n (not just [data-site] .header-main)
   so its 3-class specificity beats variant-n.css's own 2-class
   .site-header-n .header-main rule - variant CSS is concatenated after
   main.css, so an equal-specificity rule here would otherwise lose on
   source order. */
@media (max-width: 1024px) {
  [data-site="huntersvillegaragedoorpros.com"] .site-header-n .header-main { padding: 0 16px; }
}

/* Bellingham (variant M): the mobile drawer's nav links inherit
   .site-header-m's near-white desktop text color (#e8e6ec, meant for
   the dark header background), which is nearly invisible against the
   drawer's own white background - only the active/hover accent-colored
   link (Home) reads clearly. Same story for the dropdown-caret chevron
   icons. Reset both to dark, mobile only. Requested on this site only. */
@media (max-width: 1024px) {
  [data-site="bellinghamgaragedoorpros.com"] .site-header-m .primary-nav > ul > li > a { color: var(--color-ink); }
  [data-site="bellinghamgaragedoorpros.com"] .site-header-m .dropdown-caret { stroke: var(--color-ink); }
}

/* Batch6 kits (variants P/Q/R): in the 600-1024px tablet band the
   primary nav is already hidden behind the hamburger, so with only the
   logo and the toggle button left, .header-main's space-between leaves
   a big empty gap between them. Showing the business name next to the
   logo fills that gap. Left out below 600px, where the header is
   narrow enough that the name would start crowding the toggle button
   again, and above 1024px, where the full nav already fills the space. */
@media (min-width: 600px) and (max-width: 1024px) {
  [data-variant="p"] .brand-name,
  [data-variant="q"] .brand-name,
  [data-variant="r"] .brand-name {
    display: inline-block; font-family: var(--font-display); font-weight: 700;
    font-size: 1.05rem; color: var(--color-ink); margin-left: 12px; white-space: nowrap;
  }
}

/* Variant A ("Classic Bold") footer accent - a bold diagonal accent-color
   wedge across the top edge, matching the variant's flush hero/CTA banner
   language, so this variant's footer reads as visually distinct from the
   other variants' plain dark footer instead of all of them looking
   identical. Scoped to the variant, not any one site, so it applies
   automatically to every current and future Variant A site. */
[data-variant="a"] .site-footer { position: relative; }
[data-variant="a"] .site-footer::before {
  content: ""; position: absolute; top: -1px; left: 0; right: 0; height: 10px;
  background: var(--color-accent);
  clip-path: polygon(0 100%, 100% 0, 100% 100%);
}

/* Floating mobile call bar - nearly full width (small inset on all sides
   so all 4 rounded corners are actually visible - flush against the
   screen edge, a rounded bottom corner just looks like a notch, not
   rounding), pinned near the bottom edge. A corner-anchored pill (tried
   first) is a fixed-position element too, so it sits over whatever
   content happens to scroll underneath it at any given moment, not just
   at the end of the page - on a busy page that reads as broken (covering
   headings mid-scroll). Staying nearly full width avoids that: it still
   reads as a persistent toolbar, the same convention as a native app's
   bottom tab bar, just with room for the rounding to show. -------------*/
/* Matches .btn's own type treatment (weight, uppercase, letter-spacing)
   and border-radius token instead of its own hardcoded 18px pill, so it
   reads as the same button style as the rest of the site instead of a
   different-shaped element bolted onto the bottom of the screen. */
.floating-call-bar {
  display: none;
  position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 150;
  height: var(--floating-bar-h);
  background: var(--color-accent);
  color: #fff;
  align-items: center; justify-content: center; gap: 10px;
  font-family: var(--font-display); font-weight: 600; font-size: 1.1rem; letter-spacing: 0.02em; text-transform: uppercase;
  text-decoration: none;
  border-radius: var(--radius-sm);
  box-shadow: 0 10px 26px rgba(20,16,22,0.3), 0 2px 8px rgba(20,16,22,0.16);
}
.floating-call-bar:hover, .floating-call-bar:active {
  background: var(--color-accent-dark); text-decoration: none; color: #fff;
}
.floating-call-bar .icon { width: 20px; height: 20px; fill: #fff; }

/* Responsive ---------------------------------------------------------------*/
@media (max-width: 1024px) {
  /* justify-content: flex-start, not left unset - some variants (b, i,
     k, n) set justify-content: flex-end on .primary-nav for their
     desktop row layout (pushing nav+CTA to the header's right edge),
     with no media guard of their own. Left alone, that value survives
     the cascade into this column layout and bottom-packs the menu:
     once a dropdown expands past the drawer's height, the excess gets
     pushed above the top edge instead of below it - "unsafe" flex
     alignment clips that overflow with no way to scroll to it (flex
     only auto-corrects overflow for the *start* edge by default).
     Resetting here, once, for every variant is more robust than
     hunting down each variant file that might do this. */
  .primary-nav { position: fixed; top: 0; bottom: 0; right: -340px; left: auto; width: min(320px, 86vw); background: #fff; flex-direction: column;
    justify-content: flex-start; align-items: stretch; padding: 90px 24px 24px; box-shadow: -8px 0 30px rgba(0,0,0,0.18); z-index: 160;
    transition: right 0.25s ease; overflow-y: auto; }
  /* #primary-nav, not .primary-nav - some variants set justify-content
     on ".site-header-x .primary-nav" (2 classes), which outranks the
     single-class reset above regardless of source order. The ID
     selector on this same element always wins without resorting to
     !important. */
  #primary-nav { justify-content: flex-start; }
  .primary-nav.is-open { right: 0; }
  .nav-backdrop { display: block; position: fixed; inset: 0; background: rgba(15,14,17,0.45); z-index: 155; opacity: 0; visibility: hidden; transition: opacity 0.25s ease; }
  .nav-backdrop.is-open { opacity: 1; visibility: visible; }
  /* Sits inside the drawer's own top-right corner (.primary-nav is the
     containing block via position:fixed above), inside the 90px top
     padding reserved above the nav links - so it's always reachable
     even though the drawer visually covers the header's own toggle
     button once open. */
  .nav-close {
    display: flex; align-items: center; justify-content: center;
    position: absolute; top: 20px; right: 20px; width: 36px; height: 36px;
    background: none; border: 1px solid var(--color-border); border-radius: 8px; cursor: pointer;
    color: var(--color-ink);
  }
  .nav-close svg { width: 18px; height: 18px; }
  .nav-close:hover { background: var(--color-bg-alt); }
  .primary-nav > ul { flex-direction: column; align-items: stretch; gap: 4px; }
  .primary-nav > ul > li > a { padding: 12px 4px; border-bottom: 1px solid var(--color-border); }
  .dropdown { position: static; opacity: 1; visibility: visible; transform: none; box-shadow: none; border: none; background: none; display: none; padding: 4px 0 4px 12px; }
  .dropdown::before { display: none; }
  .has-dropdown.is-open .dropdown { display: block; }
  /* Animated open/close for the second (post-batch4) variant family
     only (i-o) - display:none/block can't be transitioned, so these
     variants keep the dropdown always rendered and collapse it via
     max-height + padding instead; older variants (a-h) keep the
     original instant display toggle above untouched. main.js's click
     handler already just toggles the .is-open class either way, so no
     JS branching is needed to support both behaviors side by side. */
  [data-variant="i"] .dropdown, [data-variant="j"] .dropdown, [data-variant="k"] .dropdown,
  [data-variant="l"] .dropdown, [data-variant="m"] .dropdown, [data-variant="n"] .dropdown,
  [data-variant="o"] .dropdown {
    display: block; max-height: 0; padding-top: 0; padding-bottom: 0; overflow: hidden;
    transition: max-height 0.3s ease, padding 0.25s ease;
  }
  [data-variant="i"] .has-dropdown.is-open .dropdown, [data-variant="j"] .has-dropdown.is-open .dropdown,
  [data-variant="k"] .has-dropdown.is-open .dropdown, [data-variant="l"] .has-dropdown.is-open .dropdown,
  [data-variant="m"] .has-dropdown.is-open .dropdown, [data-variant="n"] .has-dropdown.is-open .dropdown,
  [data-variant="o"] .has-dropdown.is-open .dropdown {
    max-height: 600px; padding-top: 4px; padding-bottom: 4px;
  }
  .dropdown-caret { margin-left: auto; }
  .primary-nav > ul > li > a { display: flex; align-items: center; }
  .nav-cta { margin: 16px 0 0; text-align: center; }
  .nav-toggle { display: flex; }
  .header-tagline { display: none; }
  .header-top-inner { justify-content: flex-end; }
  body { padding-bottom: calc(var(--floating-bar-h) + 24px); } /* bar height + its 12px top/bottom clearance from the inset */
  .floating-call-bar { display: flex; }
  /* .floating-call-bar (z-index:150) is wider than .primary-nav's open
     drawer (z-index:160) and isn't scoped inside it, so without this its
     left edge would peek out from behind the drawer while it's open,
     overlapping the drawer's own phone/Get a Quote elements right next
     to it. main.js toggles this class on <body> in openNav/closeNav. */
  .nav-open .floating-call-bar { display: none; }
  .wrap-narrow-with-aside.has-aside { grid-template-columns: 1fr; }
  .contact-card { position: static; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .content-section-media { grid-template-columns: 1fr; gap: 20px; }
  .content-section-media .content-section-media-figure {
    /* Break out of .wrap's 20px side padding to run edge-to-edge instead
       of sitting as a narrower, floating rounded card with visible
       margin on both sides. */
    order: -1; aspect-ratio: 16 / 9;
    width: calc(100% + 40px); margin: 0 -20px;
    border-radius: 0; box-shadow: none;
  }
  .trust-band-grid { grid-template-columns: repeat(2, 1fr); }
  .gallery-grid { grid-auto-rows: 120px; }
  .cta-photo-band-inner { flex-direction: column; align-items: flex-start; text-align: left; }
  .process-grid { grid-template-columns: repeat(2, 1fr); }
  :root { --divider-h: 32px; }
}
@media (max-width: 560px) {
  .footer-grid { grid-template-columns: 1fr; }
  .link-grid { grid-template-columns: repeat(2, 1fr) !important; }
  .area-directory { grid-template-columns: repeat(2, 1fr); }
  .hero-inner { padding: 44px 16px 40px; }
  .cta-band-inner { flex-direction: column; align-items: flex-start; }
  .trust-band-grid { grid-template-columns: 1fr; }
  /* The large 2-span quilt tiles feel cramped this narrow - drop every
     figure back to a plain 1x1 cell in a simple 2-column grid instead
     of trying to preserve the mosaic spans (!important beats the
     per-figure inline grid-column/grid-row set in sections.js). */
  .gallery-grid { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 140px; }
  .gallery-grid figure { grid-column: auto !important; grid-row: auto !important; }
  .services-grid { grid-template-columns: 1fr; }
  .process-grid { grid-template-columns: 1fr; }
}
@media (min-width: 1025px) {
  .nav-toggle { display: none; }
}

/* Scroll-reveal entrance animation -------------------------------------
   Sections and grid items fade/slide in the first time they scroll into
   view (JS toggles .is-visible via IntersectionObserver in main.js; with
   JS disabled the noscript rule below keeps everything visible). */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity 0.6s ease, transform 0.6s ease; }
.reveal.is-visible { opacity: 1; transform: none; }
.reveal-stagger > * { opacity: 0; transform: translateY(20px); transition: opacity 0.55s ease, transform 0.55s ease; }
.reveal-stagger.is-visible > * { opacity: 1; transform: none; }
.reveal-stagger.is-visible > *:nth-child(1) { transition-delay: 0.02s; }
.reveal-stagger.is-visible > *:nth-child(2) { transition-delay: 0.08s; }
.reveal-stagger.is-visible > *:nth-child(3) { transition-delay: 0.14s; }
.reveal-stagger.is-visible > *:nth-child(4) { transition-delay: 0.2s; }
.reveal-stagger.is-visible > *:nth-child(5) { transition-delay: 0.26s; }
.reveal-stagger.is-visible > *:nth-child(6) { transition-delay: 0.32s; }
.reveal-stagger.is-visible > *:nth-child(7) { transition-delay: 0.38s; }
.reveal-stagger.is-visible > *:nth-child(8) { transition-delay: 0.44s; }
.no-js .reveal, .no-js .reveal-stagger > * { opacity: 1; transform: none; }

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
  .reveal, .reveal-stagger > * { opacity: 1; transform: none; }
}

/* ==========================================================================
   V2 shared components - base styles for the second design family
   (variants i-m, see templates/variants/index.js). Purely additive: these
   classes never appear in variants a-h's markup, so this block has zero
   effect on any existing site. Each new variant's own CSS file layers
   bespoke header/hero/ctaBand/gallery styling plus its own token values
   (--radius, --shadow variants, --font-display) on top of this shared
   baseline, the same way variant-b.css through variant-h.css already do
   for the original shared components.
   ========================================================================== */

/* Trust band v2 - elevated "glass" cards instead of a plain flex row. */
.trust-band-v2 { padding: 60px 0; position: relative; overflow: hidden; }
.trust-band-v2 > .wrap { position: relative; z-index: 1; }
.trust-band-v2-photo { color: #fff; background-size: cover; background-position: center; background-repeat: no-repeat; }
.trust-band-v2-scrim { position: absolute; inset: 0; background: linear-gradient(115deg, rgba(23,22,26,0.93) 10%, rgba(23,22,26,0.7) 100%); z-index: 0; }
.trust-band-v2-head { max-width: 640px; margin-bottom: 32px; }
.trust-band-v2-head p { margin-top: 6px; }
.trust-band-v2-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
.trust-band-v2-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px; padding: 24px 20px;
  border-radius: var(--radius); background: rgba(255,255,255,0.12); backdrop-filter: blur(10px);
  border: 1px solid rgba(255,255,255,0.18); transition: transform 0.25s ease, background 0.25s ease;
}
.trust-band-v2-card:hover { transform: translateY(-4px); background: rgba(255,255,255,0.18); }
.tone-bg .trust-band-v2-card, .tone-alt .trust-band-v2-card {
  background: #fff; border-color: var(--color-border); box-shadow: var(--shadow-sm);
}
.tone-bg .trust-band-v2-card:hover, .tone-alt .trust-band-v2-card:hover { box-shadow: var(--shadow-md); background: #fff; }
.trust-band-v2-icon { width: 44px; height: 44px; border-radius: var(--radius-sm); background: var(--color-accent); display: flex; align-items: center; justify-content: center; }
.trust-band-v2-icon svg { width: 22px; height: 22px; fill: #fff; }
.trust-band-v2-stat { font-family: var(--font-display); font-size: 1.6rem; letter-spacing: 0.01em; line-height: 1; }
.trust-band-v2-label { font-size: 0.88rem; opacity: 0.85; }

/* Process v2 - icon-forward cards, no numbered badges; a connecting flow
   line links cards left-to-right on wide screens (pure CSS, no digits). */
.process-v2 { padding: 60px 0; position: relative; overflow: hidden; }
.process-v2 > .wrap { position: relative; z-index: 1; }
.process-v2-grid { list-style: none; margin: 28px 0 0; padding: 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; }
.process-v2-card {
  position: relative; padding: 26px 20px; text-align: left; background: #fff;
  border: 1px solid var(--color-border); border-radius: var(--radius); box-shadow: var(--shadow-sm);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.process-v2-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
.tone-alt .process-v2-card, .tone-ink .process-v2-card { background: rgba(255,255,255,0.94); }
.process-v2-icon {
  display: flex; align-items: center; justify-content: center; width: 46px; height: 46px;
  border-radius: var(--radius-sm); background: var(--color-accent-light); margin-bottom: 14px;
}
.process-v2-icon svg { width: 22px; height: 22px; fill: var(--color-accent-dark); }
.process-v2-card h3 { font-size: 1.08rem; margin-bottom: 6px; }
.process-v2-card p { color: var(--color-text-muted); font-size: 0.92rem; margin: 0; }
.process-v2-grid .process-v2-card:not(:last-child)::after {
  content: ""; position: absolute; top: 50%; left: 100%; width: 24px; height: 2px; background: var(--color-border);
  display: none;
}
@media (min-width: 1025px) { .process-v2-grid .process-v2-card:not(:last-child)::after { display: block; } }

/* Content cards v2 - every section is an elevated card with up to two
   real stat chips extracted from its own prose; "Areas We Cover" renders
   as a horizontal scroll-snap slider of location cards. */
.content-card-v2 { padding: 40px 0; position: relative; overflow: hidden; }
.content-card-v2 > .wrap { position: relative; z-index: 1; }
.content-card-v2-media { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 32px; align-items: center; }
.content-card-v2-media.reverse .content-card-v2-figure { order: 2; }
.content-card-v2-figure { position: relative; margin: 0; border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-lg); aspect-ratio: 4 / 3; }
.content-card-v2-figure img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.4s ease; }
.content-card-v2-figure:hover img { transform: scale(1.06); }
.content-card-v2-copy { position: relative; }
.content-card-v2-box {
  position: relative; overflow: hidden; background: #fff; border: 1px solid var(--color-border);
  border-radius: var(--radius); box-shadow: var(--shadow-sm); padding: 32px;
}
.content-card-v2-icon {
  display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px;
  border-radius: var(--radius-sm); background: var(--color-accent-light); margin-bottom: 12px;
}
.content-card-v2-icon svg { width: 20px; height: 20px; fill: var(--color-accent-dark); }
.content-card-v2-facts { display: flex; flex-wrap: wrap; gap: 8px; margin: 14px 0 4px; }
.content-card-v2-fact {
  display: inline-flex; align-items: center; padding: 6px 12px; font-weight: 700; font-size: 0.82rem;
  font-family: var(--font-display); letter-spacing: 0.02em; color: var(--color-accent-dark);
  background: var(--color-accent-light); border-radius: 999px;
}
.content-card-v2-facts-onphoto { position: absolute; left: 14px; bottom: 14px; margin: 0; }
.content-card-v2-facts-onphoto .content-card-v2-fact { background: rgba(255,255,255,0.95); box-shadow: var(--shadow-sm); }
.area-slider-v2 { margin-top: 18px; }
.area-slider-v2-track {
  display: flex; gap: 10px; overflow-x: auto; padding: 4px 4px 10px; scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.area-slider-v2-card {
  flex: none; scroll-snap-align: start; display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 16px; background: var(--color-bg-alt); border: 1px solid var(--color-border);
  border-radius: 999px; font-weight: 600; font-size: 0.86rem; color: var(--color-ink); white-space: nowrap;
}
.area-slider-v2-card svg { width: 14px; height: 14px; fill: var(--color-accent); }
.area-slider-v2-card:hover { background: var(--color-accent-light); border-color: var(--color-accent); color: var(--color-accent-dark); text-decoration: none; }
.area-slider-v2-more { background: var(--color-accent); color: #fff; border-color: var(--color-accent); }
.area-slider-v2-more svg { fill: #fff; width: 12px; height: 12px; }
.area-slider-v2-more:hover { background: var(--color-accent-dark); color: #fff; }
@media (max-width: 1024px) {
  .content-card-v2-media { grid-template-columns: 1fr; }
  .content-card-v2-media.reverse .content-card-v2-figure { order: -1; }
}

/* Quote form v2 - hosted-form iframe embed, same card chrome as the
   original quote-form-card. */
.quote-form-v2 { padding: 52px 0; position: relative; overflow: hidden; }
.quote-form-v2 > .wrap { position: relative; z-index: 1; }
.quote-form-v2-card { background: #fff; border: 1px solid var(--color-border); border-radius: var(--radius); box-shadow: var(--shadow-md); padding: 32px; max-width: 640px; margin: 0 auto; }
.quote-form-v2-card h2 { margin-bottom: 6px; }
.quote-form-v2-card > p { color: var(--color-text-muted); margin-bottom: 22px; }
.quote-form-v2-embed { border-radius: var(--radius-sm); overflow: hidden; min-height: 600px; }
.quote-form-v2-embed iframe { display: block; min-height: 600px; }

/* Footer v2 - icon-accented column headings, otherwise the same real
   NAP/service/area/company data as the original footer. */
.site-footer-v2 { background: var(--color-bg-dark); color: #cfccd4; }
.footer-v2-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 32px; padding: 48px 20px 40px; }
.footer-v2-col h2 {
  display: flex; align-items: center; gap: 8px; color: #fff; font-size: 1.02rem; margin-bottom: 14px;
}
.footer-v2-col h2 svg { width: 16px; height: 16px; fill: var(--color-accent); }
.footer-v2-col ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
.footer-v2-col a { color: #cfccd4; font-size: 0.92rem; }
.footer-v2-col a:hover { color: var(--color-accent); }
/* Every logo in this photo library mixes dark charcoal/black line-art
   with the brand accent color - fine on the white background the
   source PNGs ship with, but the transparency step strips exactly
   that white, so those dark strokes go near-invisible against the
   footer's own dark background. A white card behind the logo restores
   the contrast the artwork was designed for (same fix as the original
   .footer-brand img), rather than flattening it to a plain white
   silhouette via a filter. */
.footer-v2-brand img { height: 92px; width: auto; background: #fff; border-radius: var(--radius-sm); padding: 6px 10px; margin-bottom: 16px; }
.footer-v2-brand > p { font-size: 0.9rem; line-height: 1.6; margin-bottom: 14px; }
.footer-v2-nap { display: flex; flex-direction: column; gap: 8px; font-size: 0.9rem; }
.footer-v2-nap p { display: flex; align-items: flex-start; gap: 8px; margin: 0; }
.footer-v2-nap svg { width: 14px; height: 14px; fill: var(--color-accent); flex: none; margin-top: 3px; }
.footer-v2-nap a { color: #cfccd4; }
.footer-v2-nap a:hover { color: var(--color-accent); }
.footer-v2-bottom {
  display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  padding: 18px 20px; border-top: 1px solid rgba(255,255,255,0.12); font-size: 0.84rem; color: #a9a6b0;
}
.footer-v2-legal { display: flex; gap: 18px; list-style: none; margin: 0; padding: 0; }
.footer-v2-legal a { color: #a9a6b0; }
.footer-v2-legal a:hover { color: #fff; }
@media (max-width: 1024px) {
  .trust-band-v2-grid, .process-v2-grid { grid-template-columns: repeat(2, 1fr); }
  .footer-v2-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .trust-band-v2-grid, .process-v2-grid, .footer-v2-grid { grid-template-columns: 1fr; }
  .quote-form-v2-card { padding: 22px; }
}


/* ==========================================================================
   Variant G - "Heritage": a sturdy, vintage-signage design language layered
   on top of main.css. Redeclares the shape/type tokens (small corners,
   hard flat shadows, a slab-serif Roboto Slab display face) so every
   shared component reshapes for free, then supplies the four structurally
   distinct pieces (utility-strip header, a bordered hero card with a
   rotated seal badge, a dashed "ticket stub" CTA band, a rotated Polaroid
   photo grid) that main.css has no rules for. See templates/variants/g.js
   for the markup these target.
   ========================================================================== */

:root {
  --radius: 6px;
  --radius-sm: 3px;
  --shadow-sm: 0 2px 0 rgba(40, 30, 10, 0.16);
  --shadow-md: 0 5px 0 rgba(40, 30, 10, 0.16);
  --shadow-lg: 0 9px 0 rgba(40, 30, 10, 0.18);
  --font-display: "Roboto Slab", Georgia, "Times New Roman", serif;
  --header-h: 108px;
}

/* Header - a small utility strip above the main bar, thick ink border
   underneath instead of a soft shadow. ------------------------------------*/
.header-strip { background: var(--color-ink); color: #fff; font-size: 0.76rem; letter-spacing: 0.04em; text-align: center; padding: 6px 12px; text-transform: uppercase; }
.site-header { border-bottom: 3px solid var(--color-ink); box-shadow: none; }
.header-main { padding: 14px 20px; }
.brand-logo { height: 62px; }
.header-phone-g { display: inline-flex; align-items: center; gap: 7px; font-family: var(--font-display); font-weight: 700; color: var(--color-ink); font-size: 1.05rem; margin: 0 6px; white-space: nowrap; }
.header-phone-g .icon { width: 16px; height: 16px; fill: var(--color-accent); }
.header-phone-g:hover { color: var(--color-accent-dark); text-decoration: none; }
.nav-cta { border-radius: var(--radius-sm); }
@media (max-width: 1024px) {
  .header-phone-g { margin: 14px 0 0; justify-content: center; padding: 10px 4px; border-top: 1px solid var(--color-border); }
}

/* Bordered hero card with a rotated seal badge, over a full-bleed photo
   with a bottom-anchored scrim - unlike variant A/C's plain scrim, the
   copy sits inside its own thick-bordered card rather than directly on
   the photo. -----------------------------------------------------------*/
.hero-g { position: relative; overflow: hidden; min-height: 540px; display: flex; align-items: flex-end; }
.hero-g-media { position: absolute; inset: 0; margin: 0; }
.hero-g-media img { width: 100%; height: 100%; object-fit: cover; }
.hero-g-scrim { position: absolute; inset: 0; background: linear-gradient(0deg, rgba(20,16,10,0.75) 10%, rgba(20,16,10,0.2) 65%, rgba(20,16,10,0) 100%); }
.hero-g-inner { position: relative; padding: 60px 20px 0; width: 100%; }
.hero-g-card {
  position: relative; background: var(--color-bg-alt);
  border: 3px solid var(--color-ink); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); max-width: 640px;
  padding: 34px clamp(22px, 4vw, 40px) 38px;
}
.hero-g-card h1 { color: var(--color-ink); }
.hero-g-card .hero-lead { color: var(--color-text-muted); }
.hero-g-card .trust-badges li { color: var(--color-text); }
.hero-g-seal {
  position: absolute; top: -18px; right: -12px;
  background: var(--color-accent); color: #fff; font-family: var(--font-display); font-weight: 700;
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 8px 14px; border-radius: 999px; border: 2px dashed rgba(255,255,255,0.7);
  box-shadow: var(--shadow-sm); transform: rotate(4deg);
}
@media (max-width: 700px) {
  .hero-g { min-height: 440px; }
  .hero-g-card { padding: 26px 20px 30px; }
  .hero-g-seal { font-size: 0.62rem; padding: 6px 10px; top: -14px; right: -6px; }
}

/* Dashed "ticket stub" CTA band - the opposite move from a flush solid
   banner. -----------------------------------------------------------------*/
.cta-ticket { padding: 52px 0; }
.cta-ticket-box {
  position: relative; display: flex; align-items: center; justify-content: space-between; gap: 28px; flex-wrap: wrap;
  background: var(--color-accent); color: #fff; border-radius: var(--radius);
  border: 3px dashed rgba(255,255,255,0.55);
  padding: 34px clamp(22px, 4vw, 40px);
}
.cta-ticket-copy h2 { color: #fff; margin-bottom: 4px; }
.cta-ticket-copy p { color: rgba(255,255,255,0.88); margin: 0; }
.cta-ticket .btn-ghost { border-color: #fff; color: #fff; }
.cta-ticket .btn-ghost:hover { background: #fff; color: var(--color-accent-dark); }
@media (max-width: 700px) {
  .cta-ticket-box { flex-direction: column; align-items: flex-start; }
}

/* Rotated Polaroid-style photo grid - a thick bottom border mimicking
   instant-film stock, alternating tilt, straightening on hover. ----------*/
.gallery-polaroid-section { padding: 60px 0; }
.gallery-polaroid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 34px; margin-top: 30px; }
.gallery-polaroid-item {
  margin: 0; background: #fff; border: 1px solid var(--color-border); border-bottom-width: 26px;
  box-shadow: var(--shadow-md); transition: transform 0.2s ease;
}
.gallery-polaroid-item.tilt-left { transform: rotate(-2deg); }
.gallery-polaroid-item.tilt-right { transform: rotate(2deg); }
.gallery-polaroid-item:hover { transform: rotate(0deg) scale(1.03); }
.gallery-polaroid-media { aspect-ratio: 1 / 1; overflow: hidden; margin: 8px 8px 0; }
.gallery-polaroid-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gallery-polaroid-item figcaption { text-align: center; font-family: var(--font-display); font-size: 0.78rem; font-weight: 600; color: var(--color-ink); margin-top: 6px; }
@media (max-width: 560px) {
  .gallery-polaroid { grid-template-columns: repeat(2, 1fr); gap: 22px; }
  .gallery-polaroid-item { border-bottom-width: 18px; }
}

/* Footer - a thick ink border matching the header strip and hero
   card's own thick-border language, instead of the shared footer's
   plain top edge. -----------------------------------------------------*/
.site-footer { border-top: 4px solid var(--color-ink); }


:root{--color-accent:#124d91;--color-accent-dark:#083262;--color-accent-light:#d5e5f7;}