/* ==========================================================================
   GCA Painting — Components
   Header, footer, hero, buttons, cards, badges, testimonial, and the
   asset-gated placeholder components (gallery / map). Depends on
   tokens.css and base.css being loaded first.
   ========================================================================== */

/* --- Buttons / CTA --------------------------------------------------------
   Shape/positioning pattern inspired by certapro.com's CTAs: near-square
   corners (not pill-shaped), bold uppercase label, a darker "depth" edge
   along the bottom that flattens into a solid color on hover, and a
   trailing arrow on primary CTAs. Colors are GCA's own accent tokens. */
.btn {
  display: inline-block;
  padding: 0.875rem 1.75rem;
  border-radius: var(--radius-sm);
  font-weight: 700;
  font-size: var(--font-size-base);
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  cursor: pointer;
  border: 2px solid transparent;
  border-bottom-width: 4px;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.05s ease;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }

.btn--primary {
  background: var(--color-accent-500);
  color: var(--color-neutral-000);
  border-bottom-color: var(--color-accent-600);
}
.btn--primary:hover { background: var(--color-accent-600); border-bottom-color: var(--color-accent-600); }

.btn--outline {
  background: transparent;
  border-color: var(--color-neutral-000);
  color: var(--color-neutral-000);
}
.btn--outline:hover { background: rgba(255, 255, 255, 0.12); }

.btn--lg { padding: 1.125rem 2.25rem; font-size: var(--font-size-lg); }

/* Trailing arrow on large primary CTAs — matches the arrow-after-label
   affordance used on every major CTA across certapro.com. */
.btn--lg::after {
  content: "\2192";
  display: inline-block;
  margin-left: var(--space-1);
}

/* --- Site header ------------------------------------------------------------ */
/* --- Top banner (homepage only) --------------------------------------------------
   Slim colored strip above the header: mark, service area, divider, phone,
   far-right CTA in a single row. Structural pattern matches CertaPro's
   franchise-page top bar (per description); colors are GCA's own navy/
   terracotta tokens. */
.top-banner { background: var(--color-brand-900); }
.top-banner__bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-top: var(--space-1);
  padding-bottom: var(--space-1);
}
.top-banner__mark { display: flex; align-items: center; flex-shrink: 0; }
.top-banner__mark img { height: 28px; width: auto; }
.top-banner__area {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--color-neutral-000);
  font-size: var(--font-size-sm);
  font-weight: 600;
  white-space: nowrap;
}
.top-banner__icon { width: 16px; height: 16px; flex-shrink: 0; }
.top-banner__divider {
  width: 1px;
  height: 20px;
  background: rgba(255, 255, 255, 0.25);
  flex-shrink: 0;
}
.top-banner__phone {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--color-neutral-000);
  font-size: var(--font-size-sm);
  font-weight: 700;
  white-space: nowrap;
}
.top-banner__cta {
  margin-left: auto;
  padding: 0.5rem 1rem;
  font-size: var(--font-size-sm);
  flex-shrink: 0;
}
@media (max-width: 699px) {
  .top-banner__area,
  .top-banner__divider {
    display: none;
  }
  .top-banner__bar { gap: var(--space-2); }
  .top-banner__cta { padding: 0.5rem 0.75rem; }
}
@media (max-width: 480px) {
  .top-banner__phone-text { display: none; }
  .top-banner__cta { padding: 0.5rem 0.6rem; }
}

.site-header {
  background: var(--color-neutral-000);
  border-bottom: 1px solid var(--color-neutral-100);
  position: sticky;
  top: 0;
  z-index: 100;
}

.site-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding-top: var(--space-2);
  padding-bottom: var(--space-2);
}

.site-logo { display: flex; align-items: center; }
.site-logo__img {
  display: block;
  height: 44px;
  width: auto;
}
@media (max-width: 480px) {
  .site-logo__img { height: 34px; }
}

/* Circular hover badge, modeled on acgcarrentals.com's .nav__wa nav call
   button (same phone number, related client site): icon reads as green at
   rest inside a light-bordered circle; on hover the circle fills solid
   green, the icon inverts to a dark color, and it lifts slightly. Fixed
   40px size accommodates the 22.5px icon with comfortable padding, same
   proportions as the reference's 40px circle / ~22px icon. */
.site-header__phone {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  width: 40px;
  height: 40px;
  border: 1px solid var(--color-neutral-100);
  border-radius: 50%;
  color: var(--color-success-500);
  white-space: nowrap;
  transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease, transform 0.25s ease;
}
.site-header__phone:hover {
  background: var(--color-success-500);
  color: var(--color-neutral-900);
  border-color: var(--color-success-500);
  transform: translateY(-2px);
}
.site-header__phone-icon { width: 22.5px; height: 22.5px; flex-shrink: 0; }
.site-header__phone-text { display: none; }

.nav-toggle {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-width: 44px;
  min-height: 44px;
  background: none;
  border: none;
  padding: var(--space-1);
  cursor: pointer;
}
.nav-toggle__bar {
  width: 22px;
  height: 2px;
  background: var(--color-brand-900);
}

.site-nav__list {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.site-nav__list a { color: var(--color-neutral-900); font-weight: 600; }
.site-nav__list .nav-cta { color: var(--color-neutral-000); font-weight: 700; }
.site-nav__list .nav-cta:hover { text-decoration: none; }

/* Breakpoint intentionally 991px (matching the --bp-lg token), not the
   767px used elsewhere: at 768px (the tablet width this site is QA'd
   against) the full 6-item nav — including "Residential Painting" /
   "Commercial Painting" and the Get a Quote button — doesn't fit on one
   line and wraps mid-word. Keeping the hamburger through tablet width
   avoids that; @992px+ there's enough room (~928px content width vs.
   ~755px needed) for the full nav on one line. */
@media (max-width: 991px) {
  .nav-toggle { display: flex; }
  .site-nav { display: none; width: 100%; }
  .site-nav.is-open { display: block; }
  .site-nav.is-open .site-nav__list {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
    padding: var(--space-3) 0;
  }
}

/* --- Landing-page header/footer (pages/landing/ track) ---------------------
   Stripped-down variants: logo + phone + single CTA in the header (no nav),
   contact info + legal links only in the footer (no nav columns). See
   includes/header-landing.html / includes/footer-landing.html. */
.site-header__landing-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.footer-landing__contact {
  color: var(--color-neutral-100);
  font-weight: 600;
  margin-bottom: var(--space-3);
}
/* Without this override the <a> tags inherit base.css's global link color
   (--color-brand-500), which computes to only ~2:1 contrast against this
   dark navy footer — well under the 4.5:1 WCAG AA minimum. Matches the
   same override already applied to .footer-col a in the institutional
   footer. */
.footer-landing__contact a { color: var(--color-neutral-100); }

/* --- Hero --------------------------------------------------------------------
   Fixed vertical presence with vertically-centered content and a single
   primary CTA sitting directly below the subheadline with a generous gap —
   the same headline → subhead → CTA relationship certapro.com uses in its
   hero, minus the background photo (asset-gated, see index.html). */
.hero {
  background: var(--color-brand-900);
  color: var(--color-neutral-000);
  text-align: center;
  padding: var(--space-7) 0;
  min-height: 520px;
  display: flex;
  align-items: center;
}
/* Photo variant: institutional homepage + painting-near-me only (the asset
   this was gated on — see comment above — is now available). A navy
   gradient overlay sits between the photo and the text so the white
   headline/subhead keep the same contrast they had against the flat
   --color-brand-900 background; the other landing pages keep the flat
   navy .hero and aren't touched by this class. */
.hero--photo {
  background:
    linear-gradient(rgba(19, 38, 61, 0.6), rgba(19, 38, 61, 0.64)),
    url('/assets/images/hero/finished-living-room-nyc-hero.webp') center / cover no-repeat;
}

/* Desktop composition: a wide, centered content column sitting on a
   horizontal navy band across the photo's middle (top/bottom strips stay
   at full brightness). Class name is a holdover from an earlier
   right-shifted-column version of this hero — kept as-is since renaming
   it would mean touching both HTML pages for no functional gain, but the
   layout itself is now centered, not split. Desktop-only (min-width:
   768px) — below that .hero--photo keeps the full-tint background and
   centered single-column stack, both already covered by Prompt 13's
   mobile hero QA.
   Band stops are 23%/77% rather than a literal 33%/66%: the vertically-
   centered content stack (headline + kicker + paragraph + CTA pill) is
   taller than a strict middle third, and a literal-thirds band left the
   headline's top line straddling the bright/dark boundary with poor
   contrast. 23–77% keeps clear bright strips top and bottom while
   reliably covering the whole text column.
   background-position-y is back to the default center/50% (was 38% for
   the prior painter-and-ladder photo, tuned to keep the painter's upper
   body in frame). The current photo — a furnished living room — is a full
   subject-matter swap, not a like-for-like replacement: its focal
   elements (sofa, coffee table, window, plant) already sit in a
   vertically balanced band across the frame, with only decorative ceiling
   molding above and rug/floor below, so a plain center crop keeps
   everything that matters in frame at both the 640px desktop min-height
   and the 78vh mobile height — verified by simulating the actual cover-fit
   crop box at representative viewport widths (992/1600/1920px) before
   landing on 50%. */
@media (min-width: 768px) {
  .hero--split.hero--photo {
    min-height: 640px;
    background:
      linear-gradient(
        to bottom,
        rgba(19, 38, 61, 0) 0%,
        rgba(19, 38, 61, 0) 23%,
        rgba(19, 38, 61, 0.49) 23%,
        rgba(19, 38, 61, 0.49) 77%,
        rgba(19, 38, 61, 0) 77%,
        rgba(19, 38, 61, 0) 100%
      ),
      url('/assets/images/hero/finished-living-room-nyc-hero.webp') center / cover no-repeat;
  }
  .hero--split .hero__content { width: 100%; max-width: 960px; margin: 0 auto; text-align: center; }
}

.hero__inner { width: 100%; }
.hero__title { color: var(--color-neutral-000); font-size: var(--font-size-3xl); }
.hero__kicker {
  color: var(--color-neutral-000);
  font-weight: 700;
  font-size: var(--font-size-xl);
  margin-bottom: var(--space-1);
}
.hero__subtitle {
  font-size: var(--font-size-lg);
  color: var(--color-neutral-100);
  margin-bottom: 0;
}
.hero .btn { margin-top: var(--space-4); }

/* Area-page photo hero — same overlay/sizing treatment as .hero--photo, but
   the image itself comes from a CSS custom property set inline per page
   (--area-hero-photo, from area.heroPhoto in data/areas.js) since each of
   the 16 area pages needs a different photo rather than one fixed image
   baked into the class. Kept deliberately simpler than .hero--split.hero
   --photo's banded-gradient treatment — a flat overlay at every breakpoint,
   matching CertaPro's simpler neighborhood-page hero (no split-band). */
.hero--area-photo {
  background-image:
    linear-gradient(rgba(19, 38, 61, 0.59), rgba(19, 38, 61, 0.62)),
    var(--area-hero-photo);
  background-size: cover;
  background-position: var(--area-hero-position, center);
  background-repeat: no-repeat;
}
.hero__subtitle a { color: var(--color-neutral-000); text-decoration: underline; }

/* Compact-short landing-page photo hero — same overlay/cover treatment as
   .hero--area-photo above, but its own class so it stays out of the 78vh
   mobile media query below: these landing pages are tuned for a short,
   above-the-fold CTA (see .hero--compact-short), not a near-fullscreen
   photo hero. Image supplied per-page via the same --area-hero-photo
   custom property the area pages use. */
.hero--compact-photo {
  background-image:
    linear-gradient(rgba(19, 38, 61, 0.6), rgba(19, 38, 61, 0.64)),
    var(--area-hero-photo);
  background-size: cover;
  background-position: var(--area-hero-position, center);
  background-repeat: no-repeat;
}

/* Per-page desktop min-height bump, shared by .hero--area-photo and
   .hero--compact-photo via the same --area-hero-min-height-desktop custom
   property: some source photos (e.g. a portrait-oriented subject shot
   for a service card) need real vertical room to keep both the subject's
   face and hands in frame at wide/short desktop hero widths, without
   changing the 520px default every other page sharing these classes
   still gets. Desktop-only — doesn't touch either class's mobile height
   (78vh for .hero--area-photo, content-driven for .hero--compact-photo,
   both already set elsewhere). */
@media (min-width: 768px) {
  .hero--area-photo,
  .hero--compact-photo {
    min-height: var(--area-hero-min-height-desktop, 520px);
  }
}

/* Area-page inline service-section photo — single image below the section's
   text, reused identically across all 16 area pages per service section
   (see generate-areas.js). */
.area-section__photo {
  display: block;
  width: 100%;
  max-width: 700px;
  height: auto;
  margin: var(--space-3) auto 0;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
}

/* Area-page two-column split — generic text/content + photo layout reused
   for the "Interior Painters", "Your Local Painters", and Why-Choose-Us/
   team-photo sections (see generate-areas.js). Matches CertaPro's side-by-
   side structure for these sections. Column order follows source order, so
   swapping which element comes first in the markup is enough to get a
   photo-left or photo-right variant — no reverse modifier needed. Stacks to
   one column below 768px. */
.area-split {
  display: grid;
  gap: var(--space-4);
  align-items: center;
}
@media (min-width: 768px) {
  .area-split { grid-template-columns: 1fr 1fr; }
}
.area-split__photo {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
}
.area-split .checklist { margin: 0; max-width: none; }

/* Caps portrait-oriented photos (e.g. the commercial office-corridor shot,
   1284x1703) at a sane mobile height so they don't push the text column
   below the fold before .area-split switches to 2-column at 768px. */
@media (max-width: 767px) {
  .area-split__photo {
    max-height: 50vh;
    object-fit: cover;
  }
}

/* Top-aligned variant — matches certapro.com's own "Meet Your Commercial
   Painting Needs" section structure: the text column starts flush with the
   top of the photo instead of .area-split's default vertical centering, and
   the photo is simply left at its natural tall height (no forced
   equal-height stretch/crop) — any leftover space if the photo runs taller
   than the text just sits below the text, same as the reference. Scoped to
   its own modifier rather than changed on .area-split itself so the many
   existing photo/text splits elsewhere (generate-areas.js) keep their
   current center-aligned behavior. */
.area-split--top { align-items: start; }

/* Meet Your Commercial Painting Needs — text sized up 5px across the board
   (headline, subheading, body copy, checklist rows) per request. calc() off
   each element's existing token keeps the same relative hierarchy (h2 still
   biggest, then h3, then body) rather than flattening everything to one size. */
.meet-needs .section__title { font-size: calc(var(--font-size-2xl) + 5px); }
.meet-needs h3.card__title { font-size: calc(var(--font-size-xl) + 5px); }
.meet-needs p,
.meet-needs .checklist__item-body { font-size: calc(var(--font-size-base) + 5px); }

/* Extra breathing room requested after the intro paragraph and the "Any
   Project, Any Time" subheading — one step up the spacing scale after the
   paragraph (space-2 -> space-3) instead of its normal tighter default
   margin. Subheading's gap matched to the same space-3 value (doubling it
   was too much per follow-up feedback) so both gaps in this text block read
   as equal. Selector is h3.meet-needs__subhead (not just the class alone)
   because .card__title's own margin-bottom rule sits later in this file —
   at equal class-only specificity it was silently winning the cascade and
   erasing this override entirely. */
.meet-needs__intro { margin-bottom: var(--space-3); }
h3.meet-needs__subhead { margin-bottom: var(--space-3); }

/* Drops the text block down by one blank line so it doesn't start flush at
   the very top of the column — margin-top sized to exactly one line-height
   of this paragraph's own (bumped) font-size, so the space reads as one
   empty line above "We'll work with you...", not an arbitrary gap. */
.meet-needs__intro--first { margin-top: calc(1em * var(--line-height-base)); }

/* Checklist icons sized up 30% (22px -> ~28.6px) per request. Scoped to
   .meet-needs so the shared .checklist__icon default used elsewhere
   (generate-areas.js) is unaffected. */
.meet-needs .checklist__icon { width: calc(22px * 1.3); height: calc(22px * 1.3); }

/* Area-page local project showcase cards — reuses .card-grid's responsive
   column behavior; figure/figcaption here since each card is just a photo
   + a short caption, not a full .card with title/body/link. */
.area-project-card { margin: 0; text-align: center; }
.area-project-card img {
  display: block;
  width: 100%;
  height: 220px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card);
}
.area-project-card figcaption {
  margin-top: var(--space-1);
  font-weight: 600;
  color: var(--color-neutral-600);
}
/* Click-to-zoom trigger — plain button reset wrapping the photo so the
   existing .area-project-card img sizing/shadow above still applies
   unchanged; only adds the pointer affordance. Opens the shared .lightbox
   overlay (assets/js/main.js). */
.area-project-card__zoom {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}

/* Zip-lookup CTA pill: pill-bordered input + attached "Go" button, using
   the existing accent token for both the border and the button so no new
   color is introduced. This is a static site with no zip-based routing
   backend, so "Go" links straight to the existing /pages/quote/ form —
   the input itself isn't wired to any logic. */
.hero-zip {
  display: flex;
  max-width: 380px;
  margin: var(--space-4) auto 0;
  background: var(--color-neutral-000);
  border: 2px solid var(--color-accent-500);
  border-radius: 999px;
  overflow: hidden;
}
.hero-zip__field {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex: 1;
  min-width: 0;
  padding: 0 var(--space-3);
}
.hero-zip__icon { width: 18px; height: 18px; flex-shrink: 0; color: var(--color-accent-500); }
.hero-zip__input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: 0;
  background: none;
  font: inherit;
  color: var(--color-neutral-900);
}
.hero-zip__input::placeholder { color: var(--color-neutral-600); }
.hero-zip__submit {
  display: flex;
  align-items: center;
  padding: 0 var(--space-4);
  background: var(--color-accent-500);
  color: var(--color-neutral-000);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.hero-zip__submit:hover { background: var(--color-accent-600); text-decoration: none; }

@media (max-width: 767px) {
  /* Compact the hero on mobile: the desktop padding/min-height/44px title
     were sized for the homepage's short headline. The landing pages
     (pages/landing/) use longer, ad-copy-length headlines, and at full
     desktop sizing those push the single above-the-fold CTA well past a
     realistic mobile viewport (measured ~830-970px to the CTA on real
     landing-page content vs. a ~600-700px visible mobile viewport). This
     keeps the same headline → subhead → CTA structure, just sized to fit. */
  .hero { padding: var(--space-3) 0; min-height: 0; }
  .hero__title { font-size: var(--font-size-2xl); }
  .hero__subtitle { font-size: var(--font-size-base); }
  .hero .btn { margin-top: var(--space-2); }

  /* Near-full-viewport mobile heroes: homepage (.hero--home),
     Residential/Commercial hub (.hero--fullscreen-mobile), and every page
     built on .hero--area-photo — the 16 area pages, 9 service thin pages,
     and 8 commercial-services thin pages (33 pages total; Residential/
     Commercial hub also carry .hero--area-photo, so this rule alone
     already covers them — the modifier classes are kept for clarity and
     as a hook independent of the shared component). 78vh rather than a
     full 100vh/100dvh: matches CertaPro's pattern of leaving a visible
     sliver of the next section peeking in at the bottom of the screen as
     a scroll cue, instead of hiding it completely. 78 (not 90) accounts
     for the sticky top-banner + site-header sitting above the hero
     (~100-110px, itself 12-16% of typical mobile viewport heights) —
     90vh of hero stacked under that header still overflowed the fold
     entirely with no sliver visible; 78vh reliably leaves one across
     common device heights (~560-900px). dvh accounts for mobile browser
     chrome collapsing on scroll; vh is the fallback for browsers without
     dvh support. Deliberately scoped to these modifier/component classes
     rather than the bare .hero, so the landing pages (pages/landing/)
     keep their existing shorter mobile hero sizing. */
  .hero--home,
  .hero--fullscreen-mobile,
  .hero--area-photo {
    min-height: 78vh;
    min-height: 78dvh;
  }

  /* Mobile-only zoom override for .hero--area-photo, keyed off a custom
     property so it defaults to today's cover (no change) on all 32 other
     pages sharing this class. Some source photos are landscape-shot and
     get cropped down to a narrow sliver by cover in this near-square-to-
     portrait mobile container — Financial District's hero is the first
     case (painter and skyline both landing outside the visible band).
     Set --area-hero-size-mobile inline per-page to zoom out; the tradeoff
     is a thin navy letterbox strip (from the base .hero background) top
     and bottom, since the image can no longer also fill the container's
     full height at a wider crop. */
  .hero--area-photo {
    background-size: var(--area-hero-size-mobile, cover);
  }

  /* Mobile-only position override, same custom-property-with-fallback
     pattern as background-size above: falls back to whatever
     --area-hero-position resolves to (itself falling back to center),
     so pages that don't set this render identically to before. Needed
     because a photo's ideal crop position can differ between the wide
     desktop hero and the narrow mobile one — the subject can sit at
     center on one and need to shift off-center on the other to stay in
     frame, since the two containers' aspect ratios differ so much. */
  .hero--area-photo,
  .hero--compact-photo {
    background-position: var(--area-hero-position-mobile, var(--area-hero-position, center));
  }

  /* About page hero — 75% of the 78vh/78dvh standard above (58.5vh/
     58.5dvh), not the full height: this hero's heading+subheading are
     noticeably shorter than the other near-full-viewport heroes, so it
     doesn't need as much vertical space. Own rule rather than joining the
     .hero--home group since the value differs. Vertical centering of
     .hero__content still comes from the base .hero { display:flex;
     align-items:center } rule — shrinking min-height here doesn't affect
     that, so the heading/subheading stay centered within the shorter box. */
  .hero--about {
    min-height: 58.5vh;
    min-height: 58.5dvh;
  }
}

/* Height-scoped (not width-scoped) further compaction for legacy
   small-phone viewports (~538-553px visible height, e.g. iPhone SE-class
   devices) — deliberately max-height, since this is about vertical fold
   visibility on short screens, not narrow screens. A width-based rule
   would also hit tall phones at the same widths, which already pass.
   Scoped to .hero--compact-short only: applied on the two landing pages
   (commercial-painting, drywall-sheetrock-repair) whose longer headlines
   still missed the fold on short screens after the width-based mobile
   compaction above. painting-near-me and the institutional homepage
   don't carry this class and render exactly as before at every height. */
@media (max-height: 570px) {
  .hero--compact-short { padding: var(--space-1) 0; }
  .hero--compact-short .hero__title { font-size: var(--font-size-xl); margin-bottom: var(--space-1); }
  .hero--compact-short .hero__subtitle { font-size: var(--font-size-sm); }
  .hero--compact-short .btn { margin-top: var(--space-1); }
}

/* --- Trust strip ---------------------------------------------------------------
   Still used as a plain wrapper (text-align + padding only) on the
   badge-row sections of index.html's landing-page siblings — see
   pages/landing/*. Not used for index.html's own trust content anymore;
   that's the Contact Info / Areas Served block below. */
.trust-strip { text-align: center; padding: var(--space-4) 0; }

/* --- Contact Info / Areas Served -------------------------------------------------
   Two-column layout: narrow contact column + wider areas-served column,
   left-aligned (unlike the centered trust-strip pattern above). Stacks
   to one column on mobile. */
.contact-areas__grid {
  display: grid;
  gap: var(--space-5);
}
@media (min-width: 768px) {
  .contact-areas__grid { grid-template-columns: 1fr 2.5fr; align-items: start; }
}
.contact-areas__label {
  text-transform: uppercase;
  font-size: var(--font-size-sm);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--color-accent-500);
  margin: 0 0 var(--space-2);
}
.contact-areas__line {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-weight: 700;
  margin: 0 0 var(--space-2);
}
.contact-areas__icon { width: 20px; height: 20px; flex-shrink: 0; color: var(--color-accent-500); }
.contact-areas__link { color: var(--color-neutral-900); }
.contact-areas__link:hover { color: var(--color-accent-500); }
.contact-areas__cta { margin-top: var(--space-2); }
.contact-areas__body {
  color: var(--color-neutral-900);
  margin: 0 0 var(--space-3);
}
.contact-areas__list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-2);
}
@media (min-width: 600px) {
  .contact-areas__list { grid-template-columns: repeat(4, 1fr); }
}
.contact-areas__list a { display: block; font-weight: 700; color: var(--color-neutral-900); }
.contact-areas__list a:hover { color: var(--color-accent-500); }

/* --- Badge / differentiator row -------------------------------------------------- */
.badge-row {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(2, 1fr);
  text-align: center;
}
@media (min-width: 768px) {
  .badge-row { grid-template-columns: repeat(4, 1fr); }
}
.badge__icon {
  display: block;
  width: 48px;
  height: 48px;
  margin: 0 auto var(--space-1);
  border-radius: 50%;
  object-fit: cover;
}
.badge__label { font-weight: 600; font-size: var(--font-size-sm); }

/* Larger-icon variant — used where .badge__icon holds a real image (its
   own baked-in circle, see badge__icon's object-fit: cover) rather than
   the plain empty placeholder circle other pages still use. Scoped here
   rather than resizing .badge__icon globally, since the placeholder
   badge-rows on pages/about, pages/landing/* aren't part of this ask.
   Icon and circle are the same element, so scaling width/height together
   keeps the icon-to-circle ratio identical at any size. */
.badge-row--lg { gap: var(--space-4); }
.badge-row--lg .badge__icon { width: 60px; height: 60px; }

/* --- Cards -----------------------------------------------------------------
   Centered card body with a small pill CTA pinned to the bottom, structurally
   inspired by certapro.com's service cards (borderless, shadow-only, a
   "Learn More" pseudo-button under the copy rather than a plain text link).
   .card is a flex column so it can stretch to match its row's tallest
   sibling (the default CSS Grid stretch behavior of .card-grid's items) and
   have that extra height actually reach .card__content — which every card
   markup wraps its title/body/link in, photo variant included — rather than
   .card__content just shrink-wrapping its own content. .card__link's
   margin-top: auto then pushes the button to the bottom of that fully
   stretched box, so "Learn More" lines up at the same height across a row
   regardless of how long each card's body text is. */
.card {
  display: flex;
  flex-direction: column;
  background: var(--color-neutral-000);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  box-shadow: var(--shadow-card);
  text-align: center;
  transition: box-shadow 0.15s ease;
}
.card:hover { box-shadow: var(--shadow-card-hover); }
.card__title { margin-bottom: var(--space-1); }
.card__content {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
}

/* Photo-topped variant — image fills the full width of the card, capping
   it top-to-edge (CertaPro Morristown reference layout), with the
   heading/body/CTA in a separately-padded content block below. Scoped as
   a modifier rather than changing .card's own padding, since plain
   (imageless) .card instances elsewhere on the site — pages/contact and
   index.html's other card-grid sections — still rely on the padding
   applying to the whole card. */
.card--photo { padding: 0; overflow: hidden; }
/* object-position keyed off a custom property (default: center, i.e. today's
   behavior for the 21 other photos sharing this component) so a single tall
   portrait source — commercial-hallway-clean-nyc.webp, 1792x2400 — can shift
   its crop upward via an inline style override without touching how any
   other .card__photo image crops. */
.card__photo {
  display: block;
  width: 100%;
  height: 220px;
  object-fit: cover;
  object-position: var(--card-photo-position, center);
}
.card--photo .card__content { padding: var(--space-3); }
.card__link {
  display: inline-block;
  margin-top: auto;
  padding: 0.75rem 1.5rem;
  border-radius: var(--radius-sm);
  background: var(--color-accent-100);
  color: var(--color-brand-700);
  font-weight: 700;
  font-size: var(--font-size-base);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.card__link:hover {
  background: var(--color-accent-500);
  color: var(--color-neutral-000);
  text-decoration: none;
}
.card__link::after {
  content: "\2192";
  display: inline-block;
  margin-left: var(--space-1);
}

/* --- Area landing pages (areas/*-painters/) ----------------------------------------
   Shared components for the generated per-neighborhood/town pages — see
   data/areas.js + generate-areas.js. Reuses .section__title, .btn, and
   .badge-row from elsewhere on the site rather than introducing a
   parallel set of page-specific styles. */
.area-hero__byline {
  text-align: center;
  color: var(--color-neutral-600);
  margin: 0 0 var(--space-2);
}
.area-hero__byline a { font-weight: 700; }

.checklist {
  display: grid;
  gap: var(--space-3);
  max-width: 700px;
  margin: 0 auto;
  list-style: none;
}
@media (min-width: 600px) {
  .checklist { grid-template-columns: repeat(2, 1fr); }
}
.checklist__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  text-align: left;
}
.checklist__icon { width: 22px; height: 22px; flex-shrink: 0; color: var(--color-accent-500); margin-top: 0.2em; }
.checklist__item-title { font-weight: 700; margin: 0 0 var(--space-1); }
.checklist__item-body { margin: 0; font-weight: 400; color: var(--color-neutral-600); }

/* Closing CTA below the checklist+photo split — text then button, single
   centered group (reuses the same idea as .full-services__cta elsewhere,
   scoped separately here since it needs an extra gap between the text and
   the button rather than sharing one flat top margin). */
.checklist__cta { text-align: center; margin-top: var(--space-4); }
.checklist__cta-text { max-width: 700px; margin: 0 auto var(--space-3); }

/* "See What Other Areas We Serve" — reuses the existing .card / .card-grid
   --3up components verbatim (same white/rounded/shadowed treatment as
   every other card-grid on the site), just holding a single bold link
   instead of a title/body/pill-CTA. All 15 links show at once, no toggle. */
.area-links__intro { text-align: center; }
.area-links__name { display: block; font-weight: 700; color: var(--color-brand-900); }

/* --- Lightbox ----------------------------------------------------------------------
   Click-to-zoom overlay for the area pages' "Recent Painting Projects"
   photos (.area-project-card__zoom triggers, assets/js/main.js builds and
   controls this single shared element). Structurally the same idea as
   CertaPro's reference page's zoom behavior (click a thumbnail, see a
   larger version in a dismissible overlay) but built as dependency-free
   vanilla JS/CSS with GCA's own class names and navy/terracotta styling —
   no CertaPro code, class names, or branding carried over. z-index 300
   sits above the floating call button (200) and sticky header (100). */
.lightbox {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 300;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background: rgba(19, 38, 61, 0.92);
}
.lightbox.is-open { display: flex; }
.lightbox__img {
  display: block;
  max-width: 90vw;
  max-height: 85vh;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card-hover);
}
.lightbox__close {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 50%;
  background: var(--color-neutral-000);
  color: var(--color-brand-900);
  font-size: var(--font-size-xl);
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.lightbox__close:hover { background: var(--color-accent-100); }

/* --- Testimonial ------------------------------------------------------------------- */
.testimonial { text-align: center; }

/* --- Testimonial carousel — 3-card grid (structural pattern from
   gcapaintingnyc.com's "What Our Clients Say About Us"; GCA's own colors,
   own card markup, no copied text). JS shows/hides cards per page and
   builds the dot list to match however many cards fit per viewport. -------- */
.testimonial-carousel__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  justify-content: center;
  gap: var(--space-3);
}
.testimonial-card {
  display: none;
  flex: 1 1 0;
  max-width: 360px;
  min-width: 0;
  background: var(--color-neutral-000);
  border: 1px solid var(--color-neutral-100);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  text-align: left;
  animation: testimonial-fade 0.4s ease;
}
.testimonial-card.is-active { display: flex; flex-direction: column; }
@keyframes testimonial-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}
.testimonial-card__header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-bottom: var(--space-2);
  margin-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-neutral-100);
}
.testimonial-card__avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--color-neutral-100);
  color: var(--color-neutral-600);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.testimonial-card__avatar svg { width: 20px; height: 20px; }
.testimonial-card__name {
  margin: 0;
  font-weight: 700;
  font-size: var(--font-size-sm);
  color: var(--color-neutral-900);
}
.testimonial-card__rating {
  margin: 2px 0 0;
  color: var(--color-accent-500);
  font-size: var(--font-size-sm);
  letter-spacing: 1px;
}
.star-half {
  position: relative;
  display: inline-block;
  line-height: 1;
}
.star-half__bg { color: var(--color-neutral-300); }
.star-half__fg {
  position: absolute;
  left: 0;
  top: 0;
  width: 50%;
  overflow: hidden;
  color: var(--color-accent-500);
}
.testimonial-card__quote {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--color-neutral-600);
}
.testimonial-carousel__dots {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-1);
  max-width: 480px;
  margin: var(--space-3) auto 0;
}
.testimonial-carousel__dot {
  width: 10px;
  height: 10px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--color-neutral-600);
  cursor: pointer;
}
.testimonial-carousel__dot.is-active { background: var(--color-accent-500); }
.testimonial-card__source {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 2px 0 0;
  font-size: var(--font-size-sm);
  color: var(--color-neutral-600);
}
.testimonial-card__source-icon { width: 13px; height: 13px; color: var(--color-accent-500); flex-shrink: 0; }
.testimonial-card__google-icon { width: 13px; height: 13px; flex-shrink: 0; }
@media (max-width: 767px) {
  .testimonial-carousel__grid { max-width: 400px; margin: 0 auto; }
}

/* --- Quote CTA section ---------------------------------------------------
   Same generous heading-to-CTA gap used in the hero. .btn is inline-block
   with no auto margins, so without this it sits left-aligned under the
   centered .section__title — center the whole column (heading, optional
   supporting paragraph on area pages, button) instead of just the button,
   matching the centered-banner treatment already used elsewhere (.hero). */
.quote-flow .section__inner { text-align: center; }
.quote-flow .btn { margin-top: var(--space-4); }

/* Homepage-only single-line bar variant — text immediately followed by the
   button, both as one horizontally-centered group, white background.
   Scoped to .quote-flow--bar so the ~40 other pages using the plain
   .quote-flow (stacked heading + centered button, rules above) are
   unaffected. */
.quote-flow--bar { background: var(--color-neutral-000); }
.quote-flow--bar .section__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  text-align: left;
}
.quote-flow__text {
  margin: 0;
  color: var(--color-brand-900);
  font-weight: 700;
  font-size: calc(var(--font-size-lg) * 1.25);
}
/* Area pages' closing CTA wraps a tel: link in .quote-flow__text (phone
   number instead of plain text) — base.css's global `a { color:
   var(--color-brand-500) }` would otherwise win over the inherited navy,
   since an explicit rule on the element itself always beats inheritance. */
.quote-flow__text a { color: inherit; }
.quote-flow--bar .btn { margin-top: 0; }

/* Below ~640px "Schedule a free estimate." + the button no longer fit on
   one line — stack them instead of letting the row wrap awkwardly, keeping
   the pair centered as a group. */
@media (max-width: 640px) {
  .quote-flow--bar .section__inner {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-2);
  }
}

/* Headline + button as one horizontally-centered row (instead of the
   default stacked column) — same .quote-flow background, padding, and
   title/button styling, just arranged inline as a single centered group.
   Scoped to .quote-flow--split so the plain .quote-flow pages are
   unaffected. Mobile keeps the existing stacked/centered treatment (the
   default .quote-flow rules above) up to the 768px breakpoint used
   elsewhere on the site. */
@media (min-width: 768px) {
  .quote-flow--split .section__inner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-4);
    text-align: left;
  }
  .quote-flow--split .section__title { margin: 0; max-width: none; }
  .quote-flow--split .btn { margin-top: 0; }
}

/* --- Offer / financing banner ---------------------------------------------
   Bold dark banner treatment structurally inspired by CertaPro's financing
   banner (headline + supporting line + CTA, disclaimer below) — GCA's own
   navy/terracotta colors and original wording, not CertaPro's copy. */
.offer-banner { text-align: center; }
.offer-banner__image {
  display: block;
  width: 100%;
  max-width: 900px;
  height: auto;
  margin: 0 auto var(--space-4);
  border-radius: var(--radius-sm);
}
.offer-banner__disclaimer {
  max-width: 600px;
  margin: 0 auto var(--space-3);
  font-size: var(--font-size-sm);
  color: var(--color-neutral-300);
}

/* --- Asset-gated placeholders (recent-work gallery, map widget) --------------------
   These components are structurally real but intentionally inert until real
   project photos / a confirmed address exist. Do not wire live embeds here. */
.gallery-grid {
  display: grid;
  gap: var(--space-2);
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  min-height: 120px;
}
.gallery-grid__item {
  border-radius: var(--radius-sm);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}
.gallery-grid__item img {
  display: block;
  width: 100%;
  height: 260px;
  object-fit: cover;
}

/* --- Full-bleed break-out ----------------------------------------------------------
   Breaks an element out of .section__inner's max-width/centering to span the
   full viewport edge-to-edge, while the section heading stays in the normal
   container above it. Standard "vw break-out" technique: since .section
   itself has no horizontal padding, centering on the viewport (not the
   parent) pulls the element flush to both edges regardless of how narrow or
   wide .section__inner's content column is. */
.gallery-grid--full-bleed,
.map-widget__embed--full-bleed {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}
.map-widget__embed--full-bleed { border-radius: 0; }

/* Trim (not zero out) the vertical whitespace between the gallery, map,
   and offer banner. A literal zero-gap edge-to-edge treatment was tried
   first but reads as an abrupt, cramped seam once the map is tall enough
   to read as its own section — small deliberate gaps here instead, well
   under the default .section padding (var(--space-6)), so the sections
   still feel connected without photos/map/banner butting directly into
   each other. Map keeps its own height (set on .map-widget__embed
   iframe); offer banner keeps its full bottom padding since the gap
   below it (before the next section) isn't part of this ask. */
.recent-work { padding-bottom: var(--space-3); }
.map-widget { padding-top: var(--space-3); padding-bottom: var(--space-3); }
.offer-banner { padding-top: var(--space-4); }

/* 2-row / 4-per-row grid — larger images than the default auto-fill
   .gallery-grid, scoped to this modifier only since .gallery-grid is
   shared with the landing-page asset-gated galleries. Steps down to 2
   columns on tablet and 1 on mobile, matching the site's existing
   card-grid breakpoint tiers (768px / 992px). */
.gallery-grid--full-bleed { grid-template-columns: repeat(1, 1fr); }
.gallery-grid--full-bleed .gallery-grid__item img { height: 300px; }
@media (min-width: 600px) {
  .gallery-grid--full-bleed { grid-template-columns: repeat(2, 1fr); }
  .gallery-grid--full-bleed .gallery-grid__item img { height: 360px; }
}
@media (min-width: 992px) {
  .gallery-grid--full-bleed { grid-template-columns: repeat(4, 1fr); }
  .gallery-grid--full-bleed .gallery-grid__item img { height: 480px; }
}

.map-widget__placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 240px;
  background: var(--color-neutral-050);
  border: 1px dashed var(--color-neutral-300);
  border-radius: var(--radius-md);
  color: var(--color-neutral-600);
  font-weight: 600;
  text-align: center;
  padding: var(--space-3);
}

/* --- Map widget (live embed) -----------------------------------------------
   Used once the business address is confirmed; iframe is a keyless Google
   Maps "output=embed" query (no API key required). */
.map-widget__embed {
  border-radius: var(--radius-md);
  overflow: hidden;
}
.map-widget__embed iframe {
  display: block;
  width: 100%;
  height: 638px;
  border: 0;
}

/* --- Team section (asset-gated) ---------------------------------------------------
   Structural pattern only — photo + name + title cards, following
   certapro.com's franchise "Our Team" page layout. Populated with pending
   markers until Richie supplies real photos/names/titles for the
   remaining team members. Individually gated cards are actually hidden
   (not just documented) via the data-status rule below — previously
   data-status was a documentation-only convention nowhere enforced by
   CSS, which is how 4 "[Name — Pending]" cards ended up live-rendered on
   pages/about/index.html. */
.team-card { text-align: center; }
.team-card[data-status="asset-gated"] { display: none; }
.team-card__photo {
  width: 120px;
  height: 120px;
  margin: 0 auto var(--space-2);
  border-radius: 50%;
  background: var(--color-neutral-100);
  border: 1px dashed var(--color-neutral-300);
  overflow: hidden;
}
.team-card__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.team-card__photo--filled { border-style: solid; }
.team-card__name { margin-bottom: 0.25rem; }
.team-card__title {
  color: var(--color-neutral-600);
  font-size: var(--font-size-sm);
  margin: 0;
}

/* Founder spotlight — reuses .area-split (photo + text split, already
   pairing this same founder photo with text in generate-areas.js's "Why
   Use GCA" section) instead of a team-card grid cell, since Alex is a
   single-person spotlight now, not one card among many. */
/* No margin-bottom on .area-split here — the pending team-card grid that
   used to follow it is now individually hidden (all 4 cards are
   data-status="asset-gated"), so that spacing was just adding trailing
   muted background after Alex's photo with nothing visible below it. */
.team-section .area-split { align-items: center; }
.team-section .area-split .team-card__title { margin-bottom: var(--space-2); }
.team-section { padding-bottom: var(--space-3); }
.founder-bio { margin: 0; }

/* Mobile-only: photo before text (right after the "Meet Our Founder"
   heading), reversing .area-split's default source-order stacking below
   768px. Scoped to .team-section so the desktop 2-column layout (and every
   other .area-split usage sitewide, e.g. generate-areas.js's "Why Use GCA"
   section) is untouched — order only affects grid auto-placement, which is
   irrelevant at the ≥768px 2-column breakpoint where column position
   already follows source order as intended. */
@media (max-width: 767px) {
  .team-section .area-split > img { order: -1; }
}

/* --- Site footer ---------------------------------------------------------------------- */
.site-footer {
  background: var(--color-brand-900);
  color: var(--color-neutral-100);
  padding: var(--space-6) 0 var(--space-3);
}

.footer-columns {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
  margin-bottom: var(--space-4);
}
@media (min-width: 768px) {
  .footer-columns { grid-template-columns: repeat(3, 1fr); }
}

.footer-col__title {
  color: var(--color-neutral-000);
  font-size: var(--font-size-base);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: var(--space-2);
}
.footer-col ul { display: flex; flex-direction: column; gap: var(--space-1); }
.footer-col a { color: var(--color-neutral-100); }

.footer-social { display: flex; gap: var(--space-2); margin-bottom: var(--space-3); }
.footer-social__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  color: var(--color-neutral-000);
  font-size: var(--font-size-sm);
  font-weight: 700;
}

.footer-legal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid rgba(255, 255, 255, 0.15);
  margin-bottom: var(--space-2);
  font-size: var(--font-size-sm);
}
.footer-legal a { color: var(--color-neutral-100); }

/* --- Quote request form -----------------------------------------------------
   Plain single-page form (no multi-step wizard tooling), styled to match the
   site's existing card/section language. */
.quote-form {
  max-width: 640px;
  margin: 0 auto;
  background: var(--color-neutral-000);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: var(--space-4);
}
.quote-form__row {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: 1fr;
  margin-bottom: var(--space-3);
}
@media (min-width: 600px) {
  .quote-form__row--2up { grid-template-columns: 1fr 1fr; }
}
.quote-form__group { display: flex; flex-direction: column; }
.quote-form label {
  font-weight: 600;
  font-size: var(--font-size-sm);
  margin-bottom: var(--space-1);
}
.quote-form input[type="text"],
.quote-form input[type="tel"],
.quote-form input[type="email"],
.quote-form select,
.quote-form textarea {
  font: inherit;
  padding: 0.75rem;
  border: 1px solid var(--color-neutral-300);
  border-radius: var(--radius-sm);
  background: var(--color-neutral-000);
  color: var(--color-neutral-900);
}
.quote-form textarea { resize: vertical; min-height: 120px; }
.quote-form fieldset {
  border: 1px solid var(--color-neutral-300);
  border-radius: var(--radius-sm);
  padding: var(--space-2);
  margin-bottom: var(--space-3);
}
.quote-form legend {
  font-weight: 600;
  font-size: var(--font-size-sm);
  padding: 0 var(--space-1);
}
.quote-form__checkbox-grid {
  display: grid;
  gap: var(--space-1) var(--space-2);
  grid-template-columns: 1fr;
}
@media (min-width: 600px) {
  .quote-form__checkbox-grid { grid-template-columns: 1fr 1fr; }
}
.quote-form__checkbox-grid label,
.quote-form__radio-group label {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-weight: 400;
  margin-bottom: 0;
}
.quote-form__radio-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}
.quote-form__submit { width: 100%; margin-top: var(--space-2); }

/* Mobile: the 10-item Service Needed checkbox list is single-column here
   (2-column only kicks in at 600px), so trims fieldset/row overhead to
   offset giving each checkbox a real ~44px tap target instead of the
   ~24px text-line-height hit area it had before. */
@media (max-width: 767px) {
  .quote-form__row { margin-bottom: var(--space-2); }
  .quote-form fieldset {
    padding: var(--space-1) var(--space-2);
    margin-bottom: var(--space-2);
  }
  .quote-form__checkbox-grid { gap: 0 var(--space-2); }
  .quote-form__checkbox-grid label,
  .quote-form__radio-group label {
    min-height: 44px;
    padding: var(--space-1) 0;
  }
}

.footer-copyright {
  font-size: var(--font-size-sm);
  color: var(--color-neutral-300);
  margin: 0;
}

/* --- Secondary CTA bar -------------------------------------------------------
   Slim phone + button strip directly under a photo hero — structural echo
   of CertaPro's commercial-page pattern (hero, then a distinct secondary
   CTA bar before the page's main content starts). Used on
   pages/commercial/index.html only; residential's hero carries its own
   single CTA and has no separate bar (CertaPro's residential hero is
   itself the zip-search/CTA unit, with no second bar beneath it). */
.cta-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-3) 0;
  background: var(--color-neutral-050);
  text-align: center;
}
.cta-bar__phone {
  font-weight: 700;
  font-size: var(--font-size-lg);
  color: var(--color-brand-700);
}

/* --- FAQ accordion -------------------------------------------------------------
   Native <details>/<summary> — zero JS needed for expand/collapse, fully
   keyboard/screen-reader accessible by default. Structural echo of
   CertaPro's FAQ accordion section; all Q&A content is GCA's own,
   grounded in already-confirmed facts. */
.faq { max-width: 800px; margin: 0 auto; }
.faq__item {
  border-bottom: 1px solid var(--color-neutral-100);
  padding: var(--space-2) 0;
}
.faq__item summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--color-brand-900);
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-2);
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary::after {
  content: '+';
  font-size: var(--font-size-xl);
  color: var(--color-accent-500);
  flex-shrink: 0;
}
.faq__item[open] summary::after { content: '\2212'; }
.faq__item p { margin: var(--space-2) 0 0; color: var(--color-neutral-600); }

/* --- Process steps ---------------------------------------------------------------
   Numbered 4-step walkthrough — structural echo of CertaPro's process
   timeline section. Stacks to one column below 768px. */
.process-steps {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
}
@media (min-width: 768px) {
  .process-steps { grid-template-columns: repeat(4, 1fr); }
}
.process-step { text-align: center; }
.process-step__number {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  margin: 0 auto var(--space-2);
  border-radius: 50%;
  background: var(--color-accent-500);
  color: var(--color-neutral-000);
  font-weight: 700;
  font-size: var(--font-size-lg);
}

/* Icon variant — swaps the numbered circle above for a custom image icon
   (used on the commercial page's "Scheduled Around Your Business" section).
   Same footprint/margin as .process-step__number so the surrounding layout
   and spacing are unchanged; icons are pre-cropped square art with
   transparent backgrounds, so no border-radius/background needed here. */
.process-step__icon {
  display: block;
  width: 56px;
  height: 56px;
  margin: 0 auto var(--space-2);
}

/* --- Floating call button -----------------------------------------------
   Persistent fixed CTA, site-wide (injected via includes/floating-call.html
   — see build.js and that file's comment for why the 3 pages/landing/
   pages are excluded). z-index 200 keeps it above .site-header's sticky
   z-index:100 in case they ever visually meet during scroll, though in
   practice they never do (header pins to the top, this pins to the
   bottom). Desktop/tablet: bottom-right pill with icon + number, same
   phone icon already used in index.html's top-banner. Mobile (<=480px):
   collapses to an icon-only circle (text visually hidden, not removed —
   still read by screen readers) rather than a full-width bar or dead-
   center pill, deliberately — a wide element in this exact corner risks
   sitting on top of the last thing on the page (e.g. pages/quote/'s submit
   button, which runs closer to full width on small screens), so the
   smallest reasonable footprint reduces that risk. Untested visually
   (see conversation) — reconsider bottom-center if a real device check
   says the corner reads worse. */
.floating-call {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: 200;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  /* One-off exception, this button only — not the site's terracotta accent.
     #25D366 matches acgcarrentals.com's floating "Call Us" button exactly
     (their tel: link, class .float-cta). Note: against white text/icon
     this is only ~1.98:1 contrast, well under WCAG AA's 4.5:1 — worse than
     the #5CB85C once rejected here for the same reason (~2.5:1) — but is
     intentional per explicit request to match ACG's color exactly. */
  background: #25D366;
  color: var(--color-neutral-000);
  padding: 0.875rem 1.25rem;
  border-radius: 999px;
  box-shadow: var(--shadow-card-hover);
  font-weight: 700;
  white-space: nowrap;
  text-decoration: none;
}
.floating-call:hover { background: #1FB558; color: var(--color-neutral-000); text-decoration: none; }
.floating-call:active { transform: translateY(1px); }
.floating-call__icon { width: 20px; height: 20px; flex-shrink: 0; }

@media (max-width: 480px) {
  .floating-call {
    right: var(--space-3);
    bottom: var(--space-3);
    padding: var(--space-2);
    border-radius: 50%;
  }
  .floating-call__text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; }
}

/* --- Legal pages (Privacy Policy, Terms of Use) -----------------------------------
   Long-form reading content, so left-aligned prose at a readable line
   length instead of the sitewide centered-marketing-copy convention used
   by .section__title/.section__subtitle. Reuses plain h1/h2/p/ul — no new
   heading component needed since base.css's bare (non .section__title)
   heading rules are already unstyled-for-centering. */
.legal-content {
  max-width: 760px;
  margin: 0 auto;
  text-align: left;
}
.legal-content h1 { margin-bottom: var(--space-2); }
.legal-content h2 { margin: var(--space-5) 0 var(--space-2); }
.legal-content p { margin-bottom: var(--space-3); }
.legal-content ul { margin: 0 0 var(--space-3); padding-left: var(--space-4); }
.legal-content li { margin-bottom: var(--space-2); }

/* --- Service thin-page intro subsections (.service-intro) -----------------
   The unified service-page template's intro block (2-3 named H2
   subsections, each with a body paragraph) paired centered H2s with
   full-width, left-aligned paragraphs — visually mismatched and bare,
   since the paragraph text ran the full .section__inner width while the
   heading above it stayed narrow and centered. Centers the body copy too,
   constrains it to the same readable width as .section__subtitle, and
   gives non-first headings real breathing room above them so the
   subsections read as distinct blocks rather than one run-on column.
   Single shared class + rule applied across all 17 service/commercial-
   services thin pages using this pattern, rather than per-page tweaks. */
.service-intro p {
  text-align: center;
  max-width: 760px;
  margin: 0 auto var(--space-4);
}
.service-intro .section__title {
  margin-top: var(--space-6);
}
.service-intro .section__title:first-child {
  margin-top: 0;
}

/* --- Centered intro paragraphs (.intro-text) --------------------------------
   Centers a body paragraph to match a centered heading above it, constrained
   to a readable width. Deliberately not .section__subtitle — that component
   also changes font-size/color (larger, gray), which isn't always wanted;
   this keeps the existing body text size/color and only changes alignment +
   max-width. Originally added for pages/about/'s hero subtitle and "Our
   Story" paragraph; reused on pages/quote/'s intro line. */
.intro-text {
  text-align: center;
  max-width: 760px;
  margin: 0 auto var(--space-2);
}
