/* Flow Through Home Improvements -- design-system.css
   Spec: specs/2026-07-22-design-conversion-overhaul.md (phases 1-4).
   Loaded AFTER /css/styles.css on every page. Reuses styles.css tokens
   (--teal, --charcoal, --motion-fast, --ease-out, --frame, --radius-*,
   .btn, .label, .text-col, .reveal, .cta, .materials, .process, .faq-item)
   rather than duplicating them -- this file only adds the classes that
   did not already exist: the one dominant Call button style, the mobile
   sticky call bar, and the home/subpage credential-chip row. Budget:
   <=50,000 bytes, stamped with its own ?v=<sha256 first 8> on every page
   that loads it. css/styles.css is untouched (49,954 / 50,000 bytes,
   46 bytes headroom -- no room left in that file for this pass). */

/* ---------- .btn-call: the ONE dominant Call CTA sitewide ----------
   Replaces the previous inconsistent mix of .btn-teal (some Call links)
   and .btn-outline (other Call links) for the same intent. Larger than
   the base .btn so it reads as the primary action next to a secondary
   .btn-outline "Get a Free Quote" link. Inherits .btn's flex/radius/
   transition rules; only the size + fill + phone glyph are new. */
.btn-call {
  background: var(--teal);
  color: var(--charcoal);
  min-height: 56px;
  padding: 0 32px;
  font-size: 16px;
  font-weight: 700;
  gap: 10px;
}
.btn-call::before {
  content: "\260E";
  font-size: 16px;
  line-height: 1;
}
@media (hover: hover) {
  .btn-call:hover { background: var(--teal-hover); transform: translateY(-1px); }
}

/* ---------- Credential chip row (home intro, phase 3) ---------- */
.credential-chips { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
.credential-chip {
  display: inline-flex;
  align-items: center;
  padding: 8px 16px;
  min-height: 32px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--off-white);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
}

/* ---------- Stats grid: 3-item override (warranty-claim removal, 2026-07-22) ----------
   css/styles.css:414-415 (frozen, never edited) sizes .stats for 4 items:
   repeat(2,1fr) under 700px, repeat(4,1fr) at 700px+. Removing the fabricated
   "30 Year Warranty" stat leaves only 3 real stats on index.html and quote.html
   (the only two pages using .stats), so the frozen 4-column desktop grid would
   reserve an empty 4th cell and the row would sit lopsided-left with a large
   trailing gap. Below 700px the native 2-column grid just leaves the 3rd stat
   alone on its own row (no overflow, no wrap, reads fine) so it is left as-is;
   only the 700px+ breakpoint is overridden here to match the real 3-item count. */
@media (min-width: 700px) {
  .stats { grid-template-columns: repeat(3, 1fr); }
}

/* ---------- Mobile sticky call bar ----------
   Hidden by default; js/main.js toggles .call-bar--visible via the same
   IntersectionObserver pattern already used for the IG-feed IO-gating and
   the Recent Work sweep's progPauseObserver (see js/main.js comments) --
   visible once the viewer has scrolled past the page's hero/page-header,
   hidden again whenever `.progression` (home page Recent Work sweep) is
   in view so it can never sit under the sweep's captions. Desktop
   (>=1024px) matches the existing .floating-actions breakpoint and never
   shows this bar at all -- desktop already has the header's phone link
   and the sitewide Call buttons in view. */
.call-bar {
  display: none;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 95;
  padding: 10px var(--frame);
  background: var(--charcoal-warm);
  border-top: 1px solid var(--border);
  box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.35);
  opacity: 0;
  transform: translateY(12px);
  pointer-events: none;
  transition: opacity var(--motion-fast) ease, transform var(--motion-fast) ease;
}
.call-bar.call-bar--eligible { display: block; }
.call-bar.call-bar--visible { opacity: 1; transform: translateY(0); pointer-events: auto; }
.call-bar .btn-call { width: 100%; min-height: 48px; }
@media (min-width: 1024px) {
  .call-bar { display: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  .call-bar { transition: none; }
}

/* Reserves room so the Book circle (css/styles.css .floating-actions,
   reinstated 2026-09-29 at the client's request -- the paired Call circle
   stays removed since the sticky call bar below already covers calling)
   never sits under the call bar on the same mobile breakpoint --
   floating-actions normally sits 16px from the bottom edge; the call bar
   occupies roughly the bottom 69px, so floating-actions is nudged up to
   clear it. styles.css itself is not modified; this rule only targets its
   existing class from this new file. */
@media (max-width: 1023px) {
  .floating-actions { bottom: 76px; }
}

/* ---------- F-001 fix (round 4 review): hero CTA glow-pulse restored ----------
   Phase 1's CTA standardization changed the hero's "Get a Free Quote" link from
   class="btn btn-teal" to class="btn btn-outline" (the sitewide secondary-CTA
   treatment), so styles.css's existing selector
   ".hero__content .btn-group.load-stagger.visible .btn-teal" stopped matching
   anything and the one-shot glow silently stopped firing. styles.css itself is
   untouched (byte-for-byte, per the CSS budget) -- this equivalent rule targets
   the button's actual current class instead, reusing the same
   cta-glow-pulse-once keyframe (defined once in styles.css, referenced by name)
   and the same --motion-glow / --motion-glow-delay tokens and reduced-motion
   override pattern already established there. */
.hero__content .btn-group.load-stagger.visible .btn-outline { animation: cta-glow-pulse-once var(--motion-glow) ease-out var(--motion-glow-delay) 1; }
@media (prefers-reduced-motion: reduce) {
  .hero__content .btn-group.load-stagger.visible .btn-outline { animation: none; }
}

/* ---------- D1 fix (defect pass 2026-07-22, verandahs.html template) ----------
   At 1440px the text-heavy sections sat in a single ~55ch .text-col, leaving
   over half the container empty. .split pairs that same measure with a real
   project photo at desktop, stacking to one column below 1024px (text first,
   image after -- matches this file's existing desktop breakpoint used for
   .call-bar / .floating-actions above). Reuses --radius-lg; no new motion or
   easing tokens. The wrapping element keeps the single .reveal already used
   on this page's text-col blocks, so the existing IntersectionObserver in
   js/main.js needs no changes. */
.split { display: grid; gap: 32px; align-items: center; }
.split__text-list { display: flex; flex-direction: column; gap: 16px; }
.split__media { border-radius: var(--radius-lg); overflow: hidden; aspect-ratio: 1 / 1; }
.split__media img { width: 100%; height: 100%; object-fit: cover; }
@media (min-width: 1024px) {
  .split { grid-template-columns: minmax(0, 55ch) 1fr; gap: 56px; }
}

/* ---------- D1 fix: process timeline, full-width desktop treatment ----------
   Scoped to .process--wide, added only on verandahs.html's process block --
   the shared .process class is left exactly as-is so alfrescoes-louvres.html
   and outdoor-blinds.html (not yet rebuilt to this template) are unaffected.
   Reuses --border/--teal already defined in styles.css. */
@media (min-width: 1024px) {
  .process--wide { grid-template-columns: repeat(4, 1fr); gap: 32px; }
  .process--wide .process__step { grid-template-columns: 1fr; border-top: none; border-left: 1px solid var(--border); padding: 0 24px; }
  .process--wide .process__step:first-child { border-left: none; padding-left: 0; }
}

/* ---------- F1 (client design feedback, 2026-07-22): breadcrumb cramped on
   mobile ----------
   Universal safeguard on all 4 breadcrumb pages (verandahs, alfrescoes-
   louvres, outdoor-blinds, service-areas): never wrap onto multiple lines;
   if a crumb trail is ever long enough to overflow, it scrolls horizontally
   within its own row instead of wrapping or breaking layout. */
.breadcrumb {
  white-space: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  max-width: 100%;
}
.breadcrumb::-webkit-scrollbar { display: none; }

/* Root cause (verified at runtime, not assumed): on the 3 subpage-hero pages
   (verandahs/alfrescoes-louvres/outdoor-blinds, all `.hero.hero--sub`),
   nav.breadcrumb and .hero__content are flex-row siblings inside .hero
   (styles.css: `.hero { display:flex; align-items:flex-end }`, row by
   default, untouched). That silently squeezed hero__content's width down to
   whatever room the breadcrumb text left, and forced the breadcrumb column
   itself to wrap onto 2-3 lines well before mobile (confirmed at 390/768/
   1440px via a layout probe: hero__content was only 279px wide of a 390px
   viewport). Scoped to .hero--sub only -- the home hero (.hero with no
   breadcrumb sibling) is untouched -- stack breadcrumb above hero__content
   instead, each full width on its own line, with real space below the
   breadcrumb before the heading. The hero's own bottom padding on
   .hero__content (72px, styles.css `.hero--sub .hero__content`) already
   gives clearance from the hero's bottom edge; .hero--sub's own 70svh height
   leaves plenty of image showing above, so no extra top spacing is needed
   there either. */
.hero--sub {
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-end;
}
.hero--sub .breadcrumb {
  padding: 0 var(--frame);
  margin-bottom: 24px;
}

/* ---------- F2 (client design feedback, 2026-07-22): bullet-list restyled to
   match the materials-card language (.materials__item above: bordered card,
   subtle raised background, radius, generous padding, teal accent marker)
   instead of a plain flat dot list. Stays a real <ul>/<li> -- no markup
   change, semantics/screen-readers unaffected, presentation only. Shared via
   the existing .bullet-list class across verandahs, alfrescoes-louvres and
   outdoor-blinds. ---------- */
.bullet-list { gap: 14px; }
.bullet-list li {
  align-items: center;
  gap: 14px;
  padding: 16px 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  transition: border-color var(--motion-fast) ease, transform var(--motion-fast) ease;
}
.bullet-list li::before {
  width: 8px;
  height: 8px;
  margin-top: 0;
}
@media (hover: hover) {
  .bullet-list li:hover { border-color: var(--teal); transform: translateY(-2px); }
}

/* ---------- F4 (client design feedback, 2026-07-22): FAQ redesign ----------
   Boxed cards (materials-card language), 2-col grid on desktop / 1-col
   mobile, real accordion. Shared by service-areas.html (generated by
   scripts/gen-price-faq-html.js) and verandahs.html (hand-authored) via the
   same .faq-grid/.faq-item/.faq-trigger/.faq-content classes -- style once,
   both benefit. */
.faq-grid {
  display: grid;
  gap: 16px;
  margin: 24px 0 0;
}
@media (min-width: 700px) {
  .faq-grid { grid-template-columns: repeat(2, 1fr); gap: 20px; align-items: start; }
}
.faq-item {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  padding: 4px 24px;
  transition: border-color var(--motion-fast) ease;
}
@media (hover: hover) {
  .faq-item:hover { border-color: var(--teal); }
}
/* .faq-trigger stays the <h3> (FAQPage schema + document outline intact);
   the real clickable control is the <button> added inside it. */
.faq-trigger { padding: 0; }
.faq-trigger__btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 44px;
  padding: 20px 0;
  background: none;
  border: none;
  color: var(--white);
  font-family: inherit;
  font-size: 16px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
}
.faq-trigger__btn:focus-visible { outline: 2px solid var(--teal); outline-offset: 4px; }
.faq-trigger__icon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--teal);
  transition: transform var(--motion-fast) ease;
}
.faq-trigger__icon::before { content: '\25BE'; font-size: 16px; line-height: 1; }
.faq-item--open .faq-trigger__icon { transform: rotate(180deg); }

/* No-JS baseline: every answer stays fully visible. Overrides styles.css's
   dormant `.faq-content { max-height:0; overflow:hidden }`, which nothing
   ever wired to a toggle -- left as-is that rule would hide AEO/GEO FAQ
   content from anyone browsing with JS disabled. Real accordion collapse
   only switches on once js/main.js has run and marked the grid
   .faq--enhanced (progressive enhancement, not a fallback -- the no-JS state
   is the correct default, JS only adds behaviour on top of it). */
.faq-content { max-height: none; overflow: visible; }
.faq--enhanced .faq-content {
  max-height: 0;
  overflow: hidden;
  transition: max-height var(--motion-base) var(--ease-inout);
}
@media (prefers-reduced-motion: reduce) {
  .faq--enhanced .faq-content { transition: none; }
  .faq-trigger__icon { transition: none; }
}

/* ---------- Service-area block (LOCKED, spec 2026-07-22-design-conversion-
   overhaul.md section 2a): region-grouped suburb chips, replacing the old
   single-paragraph suburb prose wall. Region label reuses .label (styles.css,
   untouched -- no duplicate class). Suburb chips are plain <li> text, never
   <a> -- per-suburb links are doorway-page spam and explicitly out of
   bounds. Shared by verandahs.html (inside .split), alfrescoes-louvres.html
   and outdoor-blinds.html (inside .text-col, no photo pairing there), and
   service-areas.html's own region-by-region breakdown (same treatment, the
   page's own .label/h2 section head already serves as the section's lead-in
   so no link back to itself is added there). ---------- */
.area-groups { display: flex; flex-direction: column; gap: 20px; margin-top: 24px; }
.area-group__suburbs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}
.area-chip {
  display: inline-flex;
  align-items: center;
  padding: 6px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--off-white);
  font-size: 13px;
  line-height: 1.4;
}
.area-hills-note { margin: 4px 0 0; color: var(--muted); font-size: 14px; }

/* ---------- Call-bar clearance (defect fix, 2026-07-22 rollout round) ----------
   Bug: at 390px the fixed .call-bar (69px tall, see .call-bar rule above) sat on
   top of the closing CTA band's reassurance paragraph ("Free consultation. No
   obligations...") because main's last section (always .cta, sitewide) ran right
   up against the footer with no reserved clearance -- the CTA paragraph could
   never be scrolled fully clear of the bar before hitting the end of the
   document. Fix (per spec: "bottom padding/scroll-margin on the page ... so
   content clears the bar"): reserve real clearance at the end of <main> equal to
   the bar's rendered height plus a visual buffer, mobile-only (<1024px, the same
   breakpoint .call-bar itself uses to appear at all -- desktop never shows the
   bar so needs no extra space). This is additive whitespace between the CTA
   section and the footer; it does not touch the CTA band's own markup, class or
   centred measure (both stay exactly as shipped). */
@media (max-width: 1023px) {
  main { padding-bottom: 96px; }
}

/* ---------- .section--tight: reduced padding for minimal-content sections
   (dead-space fix, 2026-07-23) ----------
   styles.css:239-243 (frozen, never edited) sizes every .section at
   64/96/160px vertical padding (base/768/1200) regardless of content --
   fine for a real content section, but three sections on the home page are
   deliberately minimal by design (a one-line link, a label + single button,
   a slim trust strip) and were sitting at 7-11% fill because the padding is
   sized for content they intentionally do not carry. Adding content there
   would contradict the design brief, so the padding is cut instead. Same
   768/1200 breakpoints as .section so behaviour stays coherent; only the
   three sections named in the fix (service-areas one-liner, Projects/See-
   All-Our-Work link, credential/stats strip) carry this modifier -- the
   services grid, calculator, Instagram section, CTA band and hero are real
   content sections and keep the full .section scale untouched. */
.section--tight { padding: 40px 0; }
@media (min-width: 768px) { .section--tight { padding: 56px 0; } }
@media (min-width: 1200px) { .section--tight { padding: 72px 0; } }

/* ---------- Defect fix (2026-09-21): mobile nav drawer clipped to header ----------
   Bug: styles.css:176-182 (frozen, never edited) gives .header backdrop-filter:
   blur(8px) whenever it is non-transparent, or transparent-and-scrolled.
   backdrop-filter establishes a containing block for fixed-position
   descendants (CSS spec), and .nav.active (styles.css:217-224, frozen) is
   position:fixed; top:0; right:0; bottom:0. With the header as its containing
   block instead of the viewport, top:0/bottom:0 resolve against the header's
   own ~77-92px box, not the viewport -- measured on production at 390x844:
   drawer rect height 132px, only the first link fully inside it, the other 4
   floating over page content with no drawer background behind them.
   Fix: while the drawer is open, drop backdrop-filter from .header (and
   transform, which creates the same containing-block effect and would also
   drag the header's own scroll-hide translateY onto the open drawer) so the
   header no longer establishes a containing block and .nav.active resolves
   against the viewport again, as authored. Background stays at its existing
   rgba(26, 26, 26, 0.92) (styles.css:178, untouched) so the header still
   reads solid/legible with the drawer open -- only the blur is dropped.
   .hamburger (now rendered as an X by its own .active class, styles.css:
   213-215) is later in the header's DOM than .nav, and neither sets z-index,
   so within the header's single stacking context it already paints above the
   drawer in document order -- no z-index change needed here.
   :has() is supported in WebKit/Safari since 15.4, so this is CSS-only; no
   JS class toggle needed. */
.header:has(.nav.active) {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  transform: none;
}

/* ---------- Defect fix (2026-09-21): fixed call bar covers footer's last
   row on mobile ----------
   Bug: below 1024px the fixed .call-bar (69px tall, see .call-bar rule
   above) sits at the very bottom of the viewport at max scroll and overlaps
   .footer__bottom (copyright + "Powered by RH Media" link) by ~37-40px.
   The existing `main { padding-bottom: 96px }` rule above (2026-07-22 call-
   bar clearance fix) only reserves clearance for the CTA band inside <main>
   -- the footer comes AFTER main in the document, so that rule does nothing
   for it. Fix: reserve the same clearance (bar height 69px + a visual
   buffer, matching the 96px the main-fix already uses for an identical
   69px bar) at the very end of the document by extending .footer's own
   bottom padding, mobile-only. styles.css:109 (frozen, never edited) sets
   `.footer { padding: 96px 0 32px }`; this overrides only the bottom value
   via the cascade (design-system.css loads after styles.css), 32px -> 128px
   (32 existing + 96 clearance), so .footer__bottom's own bottom edge clears
   the bar. Desktop (>=1024px, where .call-bar is display:none !important
   per the rule above) is untouched. */
@media (max-width: 1023px) {
  .footer { padding-bottom: 128px; }
}

/* ---------- .section-head--stacked: force label + CTA to stack (bug fix,
   2026-07-23) ----------
   styles.css:104 (frozen, never edited) sets .label { display: inline-block }
   globally -- correct everywhere it's currently used (hero, .progression__
   caption, .page-header, see the scoped overrides above/below) since those
   contexts want the label to sit inline with something else. But a bare
   .section-head is display:block with no rule forcing a line break between
   children, so an inline-block .label followed by an inline-block .btn just
   flows onto the same visual line like two words of text -- reads as a
   stray word ("PROJECTS [See All Our Work]") instead of a label over a
   button. Do NOT fix this by changing .label globally; it would break every
   intentional inline use above. Instead this modifier opts a single
   .section-head into stacked behaviour: flips its .label to block and
   centres + spaces the .label/.btn pair. Used once today: index.html's
   Projects / See All Our Work section. */
.section-head--stacked { text-align: center; }
.section-head--stacked .label { display: block; }
.section-head--stacked .btn { margin-top: 20px; }
