/* Green & Co. - global base. Tokens live in tokens.css (:root vars). */

*, *::before, *::after { box-sizing: border-box; }
:root { --nav-h: 68px; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: var(--nav-h); }

/* Lenis smooth scroll (required rules; JS falls back to native when reduced-motion). */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }
.lenis.lenis-smooth iframe { pointer-events: none; }

body {
  margin: 0;
  /* clip, not hidden: `overflow-x: hidden` forces overflow-y to `auto`, making <body> a
     scroll container, which breaks position:fixed on mobile Chrome (the mobile menu
     detached from the viewport after scrolling). `clip` stops horizontal overflow the
     same way without turning body into a scroller, so fixed stays viewport-relative. */
  overflow-x: clip;
  font-family: var(--gc-font-sans);
  font-size: var(--gc-fs-body);
  line-height: var(--gc-leading-body);
  font-weight: var(--gc-weight-body);
  color: var(--gc-text-on-light);
  background: var(--gc-bg-light);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-kerning: normal;
  font-feature-settings: "kern" 1, "liga" 1;
}

h1, h2, h3 {
  font-family: var(--gc-font-serif);
  font-weight: var(--gc-weight-display);
  letter-spacing: var(--gc-tracking-heading);
  line-height: 1.1;
  text-wrap: balance;
  margin: 0;
}

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
ul { margin: 0; padding: 0; list-style: none; }

.container {
  width: 100%;
  max-width: var(--gc-maxw);
  margin-inline: auto;
  padding-inline: var(--gc-gutter);
}

/* Buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5em;
  min-height: var(--gc-target-min); padding: 0 1.5em;
  border: 1px solid transparent; border-radius: var(--gc-radius);
  font-family: var(--gc-font-sans); font-weight: var(--gc-weight-label);
  font-size: .82rem; letter-spacing: .1em; text-transform: uppercase;
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: background var(--gc-motion-fast) var(--gc-motion-ease),
              color var(--gc-motion-fast) var(--gc-motion-ease),
              border-color var(--gc-motion-fast) var(--gc-motion-ease);
}
/* Smaller through type and padding, NOT through height: the 40px min-height this
   used to carry undercut the brand's own 44px target floor, and the header (its
   only consumer) has room for 44 without growing. */
.btn-sm { padding: 0 1.1em; font-size: .74rem; }
.btn-primary { background: var(--gc-cta-bg); color: var(--gc-cta-text); }
.btn-primary:hover { background: var(--gc-gold-soft); }
.btn-ghost { background: transparent; color: var(--gc-text-on-dark); border-color: rgba(245,245,245,.55); }
.btn-ghost:hover { border-color: var(--gc-gold); color: var(--gc-gold); }
.btn-outline { background: transparent; color: var(--gc-text-on-light); border-color: rgba(13,13,13,.48); }
.btn-outline:hover { border-color: var(--gc-black); background: var(--gc-black); color: var(--gc-offwhite); }

/* Focus + skip link */
:focus-visible { outline: 2px solid var(--gc-focus-dark); outline-offset: 3px; }
/* On light surfaces the gold ring under-contrasts; use the dark focus token. */
/* Any light surface, not a hand-listed set. The remodel page's light chapter was
   not in this list, so its CTA's focus ring resolved to gold on off-white at
   2.2:1, under the 3:1 that WCAG 2.2 requires for a non-text indicator. A list of
   specific sections silently excludes every light section added later, which is
   how that happened. */
.commercial :focus-visible, .contact :focus-visible, .about__wrap :focus-visible,
.ch--light :focus-visible { outline-color: var(--gc-focus-light); }
/* Sticky bar hugs 3 viewport edges: inset the ring so it isn't clipped. */
.call-bar__btn:focus-visible { outline-offset: -3px; }
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--gc-black); color: var(--gc-offwhite);
  padding: 10px 16px; text-decoration: none;
}
.skip-link:focus { left: 8px; top: 8px; }

/* Site header (sticky charcoal bar) */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: var(--gc-charcoal);
  border-bottom: 1px solid var(--gc-rule-soft);
}
.site-header .container {
  display: flex; align-items: center; justify-content: space-between;
  min-height: var(--nav-h); padding-block: 12px;
}
.wordmark {
  display: inline-flex; align-items: center; gap: 12px;
  font-family: var(--gc-font-serif); color: var(--gc-text-on-dark);
  font-size: 1.4rem; font-weight: 500; letter-spacing: .14em;
  text-decoration: none; line-height: 1;
  /* The logo must never be squeezed. Its children are now <img>, and an img with width:auto
     contributes ~0 to min-content, so min-width:auto CANNOT hold this open the way live text
     did: the flex parent would shrink the anchor below its content and the art would silently
     overflow into the nav. Measured: anchor clientWidth 170px vs scrollWidth 197px. */
  flex-shrink: 0;
}
/* Emblem + wordmark are approved vector art (brand/logo-greenco-final/), not live text.
   Sized by height; width follows. The old .amp gold rule is gone: the wordmark's ampersand
   is white in the art itself, matching the brand board. */
.wordmark__mark { display: block; height: 44px; width: auto; }
.wordmark__text { display: block; height: 16px; width: auto; }
/* Gaps were 30px. Restoring the emblem widened the lockup by ~25px (the mark costs 54.7 + a
   12px gap; swapping live text for the wordmark art gave back ~41), and the header had NO room
   to give: usable width is 1032px (--gc-maxw 1080 less two 24px gutters) and lockup + nav wanted
   1058.6, i.e. it overlapped.

   30 -> 24 stopped the overlap but left only 9px between the wordmark and "Services", so the
   logo read as the first nav item rather than as the logo. 16/20 frees 40px and gives it ~49px
   of clearance. The two values are a deliberate hierarchy, keep it: 16 within the links < 20
   between the nav's three groups < ~49 logo-to-nav. Tightening the links also helps on purpose,
   it groups the nav as one unit against the logo instead of one long even-spaced row.

   The logo is NOT the lever here: the mark stays 44px because that is both the board's ~2.8x
   wordmark-cap ratio and the exact header content box. Shrinking it buys gap by weakening the
   thing the gap exists to set apart. */
/* Spacing hierarchy, 2026-09-09. Was 16 within the links and 20 between the three
   groups - a 4px difference nobody can see, so links + phone + CTA read as one
   911px run of tracked caps rather than three groups. Gage called it cramped and
   he was right; the 6th link exposed it rather than caused it. 28/32 makes the
   grouping legible, funded by dropping the desktop Contact link (it pointed at
   #contact, the same place as the gold button beside it) and shortening that
   button's label.

   The header is brand | navigation | actions. Read the gaps as one scale:
   28 within the links < 32 phone-to-button < the outer gaps either side of the
   link cluster, which are equal and computed (see the min-width:1241px block
   below). Do NOT go back to letting one gap absorb all the slack. */
.main-nav { display: flex; align-items: center; gap: 32px; }
.nav-links { display: flex; gap: 28px; }
.main-nav a.nav, .nav-links a {
  color: var(--gc-text-on-dark); text-decoration: none;
  font-size: .78rem; letter-spacing: .16em; text-transform: uppercase;
  font-weight: 500; opacity: .82;
  /* The brand's own floor (tokens.css) is a 44px target; these were 20px tall.
     Free to fix: the 44px logo art plus 12px padding already sets the header to
     68px, so a 44px target fits inside it without changing --nav-h. */
  display: inline-flex; align-items: center; min-height: var(--gc-target-min);
}
.nav-links a:hover { color: var(--gc-gold); opacity: 1; }

.nav-phone {
  display: inline-flex; align-items: center; gap: .45em;
  color: var(--gc-text-on-dark); text-decoration: none;
  font-weight: 600; font-size: .92rem; letter-spacing: .02em;
  min-height: var(--gc-target-min);   /* was ~23.5px tall; same free fit as the links above */
}
.nav-phone__icon { color: var(--gc-gold); flex: none; }
.nav-phone:hover { color: var(--gc-gold); }

/* Split the header's leftover width EQUALLY either side of the link cluster.
   Without this the container's space-between has only two children (logo and
   nav), so every spare pixel lands in one gap: measured 122px left of SERVICES
   against 32px right of ABOUT, which Gage caught on sight. It got worse the more
   width we freed, because freeing width was feeding a single gap.
   Mechanically: main-nav takes the slack, gap goes to 0 so the auto margins are
   the only thing distributing it, and the phone keeps its 32px to the button so
   the action pair stays a pair. Complement of the max-width:1240px collapse
   below, so it never touches the hamburger state. */
@media (min-width: 1241px) {
  .main-nav { flex: 1; gap: 0; }
  .nav-links { margin-inline: auto; }
  .nav-phone { margin-right: 32px; }
}

/* Hamburger toggle (mobile only). */
.nav-toggle {
  display: none;
  background: transparent; border: 0; cursor: pointer;
  width: 44px; height: 44px; padding: 10px; margin-right: -10px;
  color: var(--gc-text-on-dark);
}
.nav-toggle__box { display: block; position: relative; width: 24px; height: 16px; }
.nav-toggle__box span {
  position: absolute; left: 0; width: 100%; height: 2px; background: currentColor;
  border-radius: 2px; transition: transform .25s var(--gc-motion-ease), opacity .2s;
}
.nav-toggle__box span:nth-child(1) { top: 0; }
.nav-toggle__box span:nth-child(2) { top: 7px; }
.nav-toggle__box span:nth-child(3) { top: 14px; }
.menu-open .nav-toggle { color: var(--gc-gold); }
.menu-open .nav-toggle__box span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.menu-open .nav-toggle__box span:nth-child(2) { opacity: 0; }
.menu-open .nav-toggle__box span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Collapse to the hamburger before the full nav can overflow. This is the 6th-link case the
   old comment here warned about: adding "Remodeling" measured at 109.5px + a 16px gap, which
   would have overflowed the old 1080 --gc-maxw by ~56px past the old 1100 breakpoint. Fix was
   two numbers moving together, not just this one:
   - --gc-maxw (tokens.css) 1080 -> 1216, so wordmark + 6 links + phone + CTA (measured 200.1 +
     45.9 clearance + 911.4 nav = 1157.5 of usable) fits inside the new 1168 usable (1216 - two
     24px gutters) with the same ~46-56px logo clearance the original tuning protected.
   - This breakpoint 1100 -> 1240, kept above --gc-maxw (same margin relationship as before:
     original was maxw+20) so desktop nav only ever renders once the container is already
     capped at 1216, never mid-fluid-resize near the limit.
   Re-measure if the nav gains another item or the lockup grows: at 1216 there's only ~10px of
   slack above the 1157.5 requirement. */
@media (max-width: 1240px) {
  .nav-links, .nav-phone, .site-header .btn { display: none; }
  .nav-toggle { display: inline-flex; align-items: center; justify-content: center; }
}

/* Mobile menu overlay */
.mobile-menu[hidden] { display: none; }   /* author display:flex below would otherwise beat the UA [hidden] rule, leaving an invisible full-screen click-trap */
.mobile-menu {
  position: fixed; inset: var(--nav-h) 0 0 0; z-index: 48;
  background: var(--gc-black);
  display: flex; flex-direction: column; justify-content: space-between;
  padding: clamp(24px, 6vw, 44px) var(--gc-gutter) calc(env(safe-area-inset-bottom) + 32px);
  overflow-y: auto; -webkit-overflow-scrolling: touch;   /* short/landscape viewports: let the phone + CTA scroll into reach instead of clipping */
  opacity: 0; transform: translateY(-8px);
  transition: opacity .24s var(--gc-motion-ease), transform .24s var(--gc-motion-ease);
}
.menu-open { overflow: hidden; }
.menu-open .mobile-menu { opacity: 1; transform: none; }
.mobile-menu__nav { display: flex; flex-direction: column; gap: 4px; padding-top: 8px; }
.mobile-menu__nav a {
  color: var(--gc-text-on-dark); text-decoration: none;
  font-family: var(--gc-font-serif); font-weight: var(--gc-weight-display);
  font-size: 1.6rem; letter-spacing: .02em; padding: 12px 0;
  border-bottom: 1px solid var(--gc-rule-soft);
}
.mobile-menu__nav a:hover, .mobile-menu__nav a:focus-visible { color: var(--gc-gold); }
.mobile-menu__foot { display: grid; gap: 16px; }
.mobile-menu__phone {
  display: inline-flex; align-items: center; gap: .5em;
  color: var(--gc-gold); text-decoration: none;
  font-weight: 600; font-size: 1.15rem; letter-spacing: .02em;
}
.mobile-menu__foot .btn { width: 100%; }

/* Sticky mobile quick-contact bar: dark bar, gold accent (not a full gold slab). */
/* The sticky quick-contact bar takes over exactly where the header's own CTA and
   phone number leave off. It used to start at 700px while the header controls
   stopped at 1100px, which left every viewport from 701 to 1100 with no
   persistent way to call or request an estimate: measured across five widths,
   the gap covered all tablets and any half-width laptop window. On a page whose
   entire purpose is converting paid clicks, that is the most expensive 400px on
   the site. The two breakpoints are now the same number on purpose; if one moves
   the other has to move with it. */
.call-bar { display: none; }
/* First-visit homepage: reveal only at its measured consent-clear position.
   visibility preserves its box for ui.js; no-JS never adds this class. */
.gc-callbar-pending .call-bar { visibility: hidden; transition: none; }
/* The consent banner is fixed to the same viewport edge at z-index 999 (vendor
   klaro.css; klaro-theme.css sets no z-index), and this bar sits at 46, so until
   the visitor dismisses the banner it covered BOTH buttons on every width the bar
   is live at. Measured 2026-09-07 at 390x844: tapping Call hit the banner's
   "Choose" link and tapping Free Estimate hit its "Accept all" button, so the
   mobile conversion path did the banner's job instead of its own and read as a
   dead button. Raising this bar above 999 is NOT the fix: it would bury the
   banner's own controls and make consent impossible, which is a privacy bug
   traded for a conversion one. Instead we lift the bar by the banner's MEASURED
   height (scripts/ui.js sets --gc-consent-h) and drop back to 0 on dismiss. The
   height must be measured, never hardcoded: the banner is width:100% and its copy
   wraps to different heights across the 1240px range this bar is live at (moved from 1100
   with the nav breakpoint below, so the call bar and the header nav never disagree about
   which mode a given viewport is in). */
@media (max-width: 1240px) {
  .call-bar {
    display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
    position: fixed; inset: auto 0 var(--gc-consent-h, 0px) 0; z-index: 46;
    padding: 10px var(--gc-gutter) calc(env(safe-area-inset-bottom) + 10px);
    background: rgba(13,13,13,.94); backdrop-filter: blur(8px);
    border-top: 1px solid var(--gc-rule);
    transition: bottom .18s ease;
  }
  .call-bar__btn {
    display: inline-flex; align-items: center; justify-content: center; gap: .45em;
    min-height: 48px; border-radius: var(--gc-radius);
    font-weight: 600; font-size: .82rem; letter-spacing: .1em; text-transform: uppercase;
    text-decoration: none;
  }
  .call-bar__btn--call { background: transparent; color: var(--gc-gold); border: 1px solid var(--gc-gold); }
  .call-bar__btn--est { background: var(--gc-gold); color: var(--gc-black); }
  .menu-open .call-bar { display: none; }
}
/* v3 remodel-ad call-bar hide and Klaro top-left overrides retired with the v4
   template. That page renders its own .gc-callbar and carries Klaro (top band
   under 1024, top-right corner card at 1024+) in styles/remodel-ad.css. */

/* Only the full-width top notice shares the form's horizontal space. Keep
   the offset on the scroll container so anchor margins do not double it. */
@media (max-width: 1023px) {
  html { scroll-padding-top: max(var(--nav-h), var(--gc-notice-bottom, 0px)); }
}

/* Site footer (dark) */
.site-footer {
  background: var(--gc-black);
  color: var(--gc-text-on-dark);
  padding-block: clamp(48px, 7vw, 80px) 32px;
  border-top: 1px solid var(--gc-rule);
}
.site-footer__top {
  display: grid;
  grid-template-columns: 2fr 1fr 1.4fr;
  gap: clamp(28px, 5vw, 64px);
  padding-bottom: clamp(32px, 4vw, 48px);
  border-bottom: 1px solid var(--gc-rule-soft);
}
.wordmark--footer { margin-bottom: 14px; }
.wordmark--footer .wordmark__mark { height: 52px; }
.wordmark--footer .wordmark__text { height: 19px; }
.site-footer__tag { margin: 0; color: var(--gc-text-muted); font-size: .9rem; letter-spacing: .04em; }
.site-footer__nav { display: grid; gap: 11px; align-content: start; }
.site-footer__nav a {
  color: var(--gc-text-on-dark); text-decoration: none;
  font-size: .82rem; letter-spacing: .12em; text-transform: uppercase; opacity: .82;
}
.site-footer__nav a:hover { color: var(--gc-gold); opacity: 1; }
.site-footer__contact { display: grid; gap: 9px; align-content: start; }
.site-footer__contact a { color: var(--gc-text-on-dark); text-decoration: none; font-size: .95rem; }
.site-footer__contact a:hover { color: var(--gc-gold); }
.site-footer__contact p { margin: 6px 0 0; color: var(--gc-text-muted); font-size: .9rem; }
.site-footer__bottom {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px 24px;
  padding-top: 24px;
}
.site-footer__bottom p { margin: 0; color: var(--gc-text-muted); font-size: .8rem; letter-spacing: .03em; }
.site-footer__bottom a { color: var(--gc-text-muted); text-decoration: none; font-size: .8rem; letter-spacing: .03em; }
.site-footer__bottom a:hover { color: var(--gc-gold); }
.site-footer__legal { display: flex; align-items: center; gap: 20px; }
.site-footer__cookie-btn {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--gc-text-muted); font: inherit;
  font-size: .8rem; letter-spacing: .03em;
  font-family: var(--gc-font-sans);
}
.site-footer__cookie-btn:hover { color: var(--gc-gold); }
@media (max-width: 1240px) {
  .site-footer { padding-bottom: 92px; }   /* clear the fixed call-bar, same breakpoint as the bar itself */
}
@media (max-width: 700px) {
  .site-footer__top { grid-template-columns: 1fr; gap: 30px; }
}

/* Long-form document pages (privacy policy, terms). Readable measure + restored
   list markers, since the global reset strips them for the one-pager layout. */
.page-doc { padding-block: clamp(48px, 7vw, 88px) clamp(56px, 8vw, 104px); }
.container--reading { max-width: 760px; }
.page-doc__head { margin-bottom: clamp(28px, 4vw, 40px); padding-bottom: 24px; border-bottom: 1px solid var(--gc-rule); }
.page-doc__title { font-size: clamp(2rem, 5vw, 3rem); }
.page-doc__body { color: var(--gc-text-on-light); font-size: 1.02rem; line-height: 1.7; }
.page-doc__body > *:first-child { margin-top: 0; }
.page-doc__body h2 {
  font-size: clamp(1.15rem, 2.4vw, 1.4rem);
  letter-spacing: .06em; margin: 2.2em 0 .6em;
}
.page-doc__body p { margin: 0 0 1.1em; }
.page-doc__body ul { list-style: disc; padding-left: 1.4em; margin: 0 0 1.2em; }
.page-doc__body li { margin-bottom: .5em; }
.page-doc__body a { color: var(--gc-black); text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--gc-gold); }
.page-doc__body a:hover { color: var(--gc-gold); }
.page-doc__body code {
  font-size: .9em; background: rgba(13,13,13,.06);
  padding: .1em .4em; border-radius: 3px; word-break: break-word;
}
.page-doc__body strong { font-weight: 600; }

/* Scroll reveals (only active once ui.js confirms JS + motion allowed). */
.js-reveal-ready [data-reveal] {
  opacity: 0; transform: translateY(18px);
  transition: opacity .7s var(--gc-motion-ease), transform .7s var(--gc-motion-ease);
}
.js-reveal-ready [data-reveal].is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
  .js-reveal-ready [data-reveal] { opacity: 1 !important; transform: none !important; }
}


/* gc_picture() wraps content imgs in <picture> for AVIF/WebP negotiation.
   display:contents keeps the img's layout parent the figure, so every
   existing `figure img { height:100% }` / object-fit rule is unaffected. */
picture { display: contents; }
