/* ==========================================================================
   AST General Contracting -- shared site styles

   Standalone: this file is AST's own copy of the house conventions (CSS
   variables, .wrap container, BEM-ish class names). It does not import,
   @use or otherwise depend on any other client's stylesheet.

   Every page links this file plus assets/favicon.ico.
   ========================================================================== */

/* ---------- theme ---------- */
:root{
  --black:#111111;
  --bg:#f7f7f7;
  --panel:#ffffff;
  --muted:#5f6472;
  --border:#e8e8e8;
  --gold:#FBBC04;
  --text:#1b1d22;
  --shadow:0 18px 40px rgba(17,17,17,.08);

  /* brand -- from clients/AST/assets/base.md */
  --brand-primary:#333333;
  --brand-secondary:#a8a8a8;
  --brand-dark:#181818;

  /* header ink: inactive nav is white, hover + active are #3D3D3D */
  --header-ink:#ffffff;
  --header-ink-accent:#3D3D3D;

  /* white tag behind a hovered/active nav link, so the #3D3D3D ink stays
     readable wherever the slideshow photo happens to be light */
  --nav-tag-bg:#FFFFFF;
  --nav-pad-x:14px;
  --nav-pad-y:9px;

  /* social icon container fill */
  --social-bg:#3D3D3D;

  /* grey button fill (Learn More) */
  --btn-gray:#3D3D3D;

  /* the surface immediately below the roof section -- drives the shape
     divider fill so the edge reads seamless. Now the white
     .recognized-section, so the divider is white too. */
  --next-surface:#ffffff;

  /* the footer's own top divider: matches the surface ABOVE the footer.
     Kept separate from --next-surface so the two dividers stay independent. */
  --footer-shape-fill:#ffffff;

  /* footer ink */
  --footer-ink:#D4D4D4;

  /* header is ~10% of the viewport, with a floor so a short window
     (or a laptop with a big browser chrome) still fits the logo */
  --header-h:max(12vh, 130px);
}

/* ---------- base ---------- */
*{box-sizing:border-box}
html{scroll-behavior:smooth}
/* Poppins site-wide. Everything inherits from body, except form controls,
   which browsers give their own system font unless told otherwise. */
body{margin:0;font-family:"Poppins",sans-serif;color:var(--text);background:var(--bg);line-height:1.6}
button,input,select,textarea,optgroup{font-family:inherit}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
.wrap{width:min(1600px,calc(100% - 48px));margin:0 auto}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* ---------- header ----------
   Translucent + backdrop-filter:blur(3px), the same background pattern the
   house header uses -- but tinted dark rather than white, because this
   header's nav ink is white and white-on-white is invisible. The header
   overlays the hero, so the blur has something to act on. */
.site-header{position:absolute;top:0;left:0;right:0;z-index:100;width:100%;background:transparent}

/* Three columns: logo | nav | actions.
   space-between pushes them to maximum separation; the gap is allowed to
   grow toward the specced ~1000px on ultra-wide screens but clamps down
   instead of overflowing on normal ones. */
.header-inner{width:min(1800px,calc(100% - 32px));margin:0 auto;display:flex;align-items:center;justify-content:space-between;gap:clamp(24px,6vw,1000px);min-height:var(--header-h)}

/* --- column 1: logo, always links home --- */
.brand{display:inline-flex;align-items:center;flex:0 0 auto}
.brand img{height:clamp(72px,10vh,110px);width:auto;object-fit:contain}

/* --- column 2: nav --- */
/* flex:1 lets the nav take the middle band and centre itself in it, so the
   logo->nav and nav->actions gaps come out roughly equal (the spec's two
   ~1000px gaps) instead of the nav hugging the logo. */
.nav{display:flex;align-items:center;justify-content:center;flex:1 1 auto;flex-wrap:wrap}
/* 15px between items, kept as the specced expression */
.nav > a,.nav > .nav-item{margin-left:calc(30px / 2);margin-right:calc(30px / 2)}
.nav > a:first-child,.nav > .nav-item:first-child{margin-left:0}
.nav > a:last-child,.nav > .nav-item:last-child{margin-right:0}

.nav-item{position:relative;display:inline-flex;align-items:center;height:52px}
/* nav link typography -- specced in px, do not convert to rem.
   The box is padded rather than a fixed 52px tall so the hover/active
   white background hugs the text instead of becoming a tall slab.
   .nav-item keeps its 52px, so the dropdown menu still anchors the same. */
.nav > a,.nav .dropdown{position:relative;display:inline-flex;align-items:center;padding:var(--nav-pad-y) var(--nav-pad-x);font-size:16px;font-weight:400;font-style:normal;text-transform:capitalize;text-decoration:none;line-height:1em;letter-spacing:0px;color:var(--header-ink);background:transparent;border-radius:6px;transition:color .15s ease,background-color .15s ease;white-space:nowrap}

/* hover and active share the white tag behind the text -- the #3D3D3D ink
   is unreadable against a light photo without it. */
.nav > a:hover,.nav > a:focus-visible,.nav > a.active,.nav-item:hover > .dropdown,.nav-item:focus-within > .dropdown,.nav > .nav-item > .dropdown.active{color:var(--header-ink-accent);background-color:var(--nav-tag-bg)}

/* No underline on the active link -- the white tag above already marks it. */

/* dropdown caret -- extra right padding holds it clear of the text. */
.nav .dropdown{padding-right:calc(var(--nav-pad-x) + .9rem)}
.nav .dropdown::after{content:"\25BE";position:absolute;right:var(--nav-pad-x);top:50%;transform:translateY(-50%);font-size:.8rem;transition:transform .18s ease,color .15s ease}
.nav-item:hover > .dropdown::after,.nav-item:focus-within > .dropdown::after{transform:translateY(-50%) rotate(180deg)}

.nav-menu{position:absolute;top:calc(100% - 4px);left:50%;transform:translateX(-50%);min-width:200px;max-width:calc(100vw - 32px);padding:10px 0;background:rgba(255,255,255,.98);border:1px solid var(--border);border-radius:12px;box-shadow:var(--shadow);opacity:0;visibility:hidden;pointer-events:none;z-index:50;transition:opacity .18s ease,visibility .18s ease}
.nav-menu::before{content:"";position:absolute;top:-8px;left:0;right:0;height:8px}
.nav-item:hover .nav-menu,.nav-item:focus-within .nav-menu{opacity:1;visibility:visible;pointer-events:auto}
/* submenu items match the nav link typography above */
.nav-menu a{display:block;padding:10px 16px;font-size:16px;font-weight:400;font-style:normal;text-transform:capitalize;text-decoration:none;letter-spacing:0px;white-space:nowrap;color:var(--text);transition:background .15s ease,color .15s ease}
.nav-menu a:hover{background:var(--black);color:#fff}
.nav-menu a::after,.nav-menu a::before{display:none;content:none}

/* --- column 3: socials over CTA, two rows --- */
.header-actions{display:flex;flex-direction:column;align-items:center;flex:0 0 auto;margin-left:auto}

/* row 1: a single horizontal run of 14px icons, 8px apart, centred.
   grid-auto-flow:column is the working form of the specced
   grid-template-columns:repeat(0,auto) -- repeat() needs a count >= 1, so
   an implicit column track per icon is what actually produces the row. */
.social-links{display:grid;grid-auto-flow:column;grid-auto-columns:auto;justify-content:center;align-items:center;text-align:center;column-gap:8px;row-gap:0}
.social-link{width:26px;height:26px;border-radius:50%;background:var(--social-bg);display:inline-flex;align-items:center;justify-content:center;text-decoration:none;transition:transform .2s ease,filter .2s ease}
.social-link:hover,.social-link:focus-visible{transform:translateY(-1px);filter:brightness(1.35)}
.social-link svg{width:14px;height:14px;display:block;fill:#fff}

/* row 2: CTA, ~10px under the icons */
.header-actions .btn-primary{margin-top:10px}
/* Rounded rectangle, deliberately NOT a pill -- 8px keeps the corners soft
   while the rectangular shape stays obvious. Typography follows the nav:
   capitalize, weight 500, no letter-spacing. */
.btn-primary{display:inline-flex;align-items:center;justify-content:center;min-height:40px;padding:0 22px;background:var(--black);color:#fff;border:none;border-radius:8px;font-family:inherit;font-size:14px;font-weight:500;font-style:normal;text-transform:capitalize;text-decoration:none;line-height:1em;letter-spacing:0px;white-space:nowrap;cursor:pointer}
.btn-primary:hover,.btn-primary:focus-visible{background:var(--brand-primary)}

/* ---------- mobile header: hamburger + off-canvas drawer ----------
   Below 980px (the breakpoint .page-hero already uses) the header collapses
   to logo + hamburger, and the nav, socials and CTA move into a drawer that
   slides in from the right. Without this the 9 nav links wrap onto a third
   and fourth header row and eat most of a phone screen.

   All of this is inert above the breakpoint: .nav-toggle is display:none,
   and a min-width:981px rule below takes the drawer and backdrop out
   entirely, so no desktop behaviour changes. Behaviour lives in
   assets/site-nav.js. */
.nav-toggle{display:none;flex:0 0 auto;align-items:center;justify-content:center;width:44px;height:44px;padding:0;margin-left:auto;background:transparent;border:1px solid rgba(255,255,255,.28);border-radius:8px;color:var(--header-ink);cursor:pointer;-webkit-appearance:none;appearance:none;transition:background-color .15s ease}
.nav-toggle:hover,.nav-toggle:focus-visible{background:rgba(255,255,255,.14)}
.nav-toggle svg{width:20px;height:20px;fill:currentColor;display:block}
/* the X replaces the bars while the drawer is open -- the same icon swap the
   retired just-call button used. Both selectors have to be at least as
   specific as `.nav-toggle svg` above (0,1,1) or the display:block there wins
   and the two icons render stacked on top of each other. */
.nav-toggle .nav-toggle-close{display:none}
.nav-toggle.is-open .nav-toggle-open{display:none}
.nav-toggle.is-open .nav-toggle-close{display:block}

/* z-index 200/201 clears .site-header (100); the centred .modal-overlay
   (10000) still wins, which is correct -- it is a blocking dialog. */
/* visibility is delayed on the way OUT (so the panel stays visible while it
   slides away) but flips instantly on the way IN -- hence the 0s duration
   with a delay, not a plain transition. Transitioning visibility itself would
   leave it still computed `hidden` for the first frames after opening, and a
   hidden element cannot take focus, so site-nav.js could not move focus into
   the drawer. */
.nav-backdrop{position:fixed;inset:0;z-index:200;background:rgba(0,0,0,.55);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .22s ease,visibility 0s linear .22s}
.nav-backdrop.is-open{opacity:1;visibility:visible;pointer-events:auto;transition:opacity .22s ease,visibility 0s linear 0s}

/* visibility (not just the transform) is what keeps the links out of the tab
   order while closed -- an off-canvas panel that is merely translated is
   still focusable. */
.nav-drawer{position:fixed;top:0;right:0;bottom:0;z-index:201;width:min(320px,86vw);display:flex;flex-direction:column;background:#141414;border-left:1px solid rgba(255,255,255,.14);box-shadow:-18px 0 46px rgba(0,0,0,.45);transform:translateX(100%);visibility:hidden;overflow-y:auto;overscroll-behavior:contain;transition:transform .26s ease,visibility 0s linear .26s}
.nav-drawer.is-open{transform:translateX(0);visibility:visible;transition:transform .26s ease,visibility 0s linear 0s}

.drawer-nav{display:flex;flex-direction:column;padding:14px 0 6px}
/* full-width rows, 48px+ of touch target each */
.drawer-nav a,.drawer-sub-toggle{display:flex;align-items:center;width:100%;min-height:48px;padding:12px 22px;background:transparent;border:none;font-family:inherit;font-size:1.05rem;font-weight:400;font-style:normal;text-transform:capitalize;text-align:left;text-decoration:none;letter-spacing:0;color:var(--header-ink);cursor:pointer;transition:background-color .15s ease,color .15s ease}
.drawer-nav a:hover,.drawer-nav a:focus-visible,.drawer-sub-toggle:hover,.drawer-sub-toggle:focus-visible{background:rgba(255,255,255,.1)}
/* matches the desktop nav's active treatment */
.drawer-nav a.active{color:var(--header-ink-accent);background:var(--nav-tag-bg)}

/* the Contact dropdown becomes an expand/collapse row rather than a hover
   menu -- there is no hover on touch */
.drawer-sub-toggle{justify-content:space-between}
.drawer-sub-toggle::after{content:"\25BE";margin-left:12px;font-size:.85rem;transition:transform .18s ease}
.drawer-sub-toggle[aria-expanded="true"]::after{transform:rotate(180deg)}
.drawer-sub{display:flex;flex-direction:column;background:rgba(255,255,255,.05)}
/* has to beat the display:flex above, since the script toggles [hidden] */
.drawer-sub[hidden]{display:none}
.drawer-sub a{padding-left:38px;font-size:1rem}

/* margin-top:auto pins this to the bottom however short the link list is */
.drawer-foot{margin-top:auto;display:flex;flex-direction:column;align-items:center;gap:16px;padding:22px;border-top:1px solid rgba(255,255,255,.14)}
/* socials keep the shared .social-link styling; only the size and spacing
   open up, because 26px is under the touch-target floor */
.drawer-foot .social-links{column-gap:14px}
.drawer-foot .social-link{width:34px;height:34px}
.drawer-foot .social-link svg{width:17px;height:17px}
/* .btn-primary is #111 on a #141414 drawer -- invisible. Inverted here. */
.drawer-cta{width:100%;min-height:48px;background:#ffffff;color:var(--black);font-size:15px}
.drawer-cta:hover,.drawer-cta:focus-visible{background:#e6e6e6;color:var(--black)}

/* the page behind must not scroll while the drawer is up. Kept separate from
   body.modal-open so the two cannot untoggle each other. */
body.nav-open{overflow:hidden}

/* ---------- hero / background slideshow ----------
   This section is the shared backdrop for the header and the hero copy:
   .site-header is position:absolute and sits on top of it.

   Slideshow mechanism copied from the house pattern unchanged -- 5s
   interval (JS), .5s opacity cross-fade, 6s scale drift from 1 to 1.1,
   and an rgba(17,17,17,.45) overlay to hold the copy readable. */
/* padding-top reserves the overlaying header's own height so the copy
   centres in the visible area below it and can never slide under it */
.hero-section{position:relative;width:100%;min-height:80vh;background:#111111;display:flex;align-items:center;justify-content:center;padding-top:var(--header-h);padding-bottom:24px;overflow:hidden}

.hero-slideshow{position:absolute;inset:0;z-index:0;overflow:hidden}
.hero-slide{position:absolute;inset:0;background-size:cover;background-position:center;opacity:0;transform:scale(1);transition:opacity .5s ease,transform 6s ease-out}
.hero-slide.is-active{opacity:1;transform:scale(1.1)}
/* one overlay treatment shared by the home hero and the inner-page banner */
.hero-overlay,.banner-overlay{position:absolute;inset:0;background:rgba(17,17,17,.45);z-index:1}

/* copy block: horizontally centred by .wrap, contents centred on the axis */
.hero-content{position:relative;z-index:2;display:flex;flex-direction:column;align-items:center;text-align:center}
.hero-content h1{margin:0 0 22px;font-family:"Poppins",sans-serif;font-size:56px;font-weight:600;text-transform:uppercase;font-style:oblique;color:#FFFFFF;line-height:1.1;letter-spacing:.01em}
/* house .lead conventions, re-inked for a dark photo backdrop */
.hero-content .lead{max-width:720px;margin:0 0 30px;font-size:1.45rem;font-weight:400;line-height:1.55;letter-spacing:.03em;color:rgba(255,255,255,.92)}

/* two-column row: Google review card + Get Started */
.reviews-row{display:flex;align-items:center;justify-content:center;gap:20px;flex-wrap:wrap}
.review-card{display:flex;align-items:center;gap:18px;background:#fff;border:1px solid var(--border);border-radius:20px;padding:16px 24px;box-shadow:var(--shadow);min-height:92px;text-align:left}
.google-badge{width:44px;height:44px;border-radius:50%;background:linear-gradient(135deg,#4285F4 0 25%,#34A853 25% 50%,#FBBC04 50% 75%,#EA4335 75% 100%);display:inline-flex;align-items:center;justify-content:center;color:#fff;font-size:1.4rem;font-weight:900;font-family:Arial,sans-serif}
.review-copy{line-height:1.2}
.review-copy strong{display:block;font-size:1rem;color:var(--black);letter-spacing:.02em}
.review-copy span{display:block;font-size:1rem;color:var(--muted);margin-top:3px}
.review-score{display:flex;align-items:baseline;gap:8px;font-weight:900;color:var(--black);font-size:2.4rem;line-height:1}
.stars{color:var(--gold);letter-spacing:.12em;font-size:1.05rem}
/* hero CTA keeps the AST rounded-rectangle shape, sized up for the hero */
/* stretches to the review card's height beside it, with its corner radius */
.hero-section .btn-primary{align-self:stretch;min-height:48px;padding:0 44px;border-radius:20px;font-size:18px;font-weight:600}

/* ---------- "learn about" section ----------
   White band under the hero, inset further from the edges than the rest of
   the page (which uses .wrap). */
.learn-section{width:100%;min-height:50vh;background:#ffffff;display:flex;align-items:center;padding:40px 0}

/* 450px of side margin, but only where the viewport can actually spare it:
   below ~1500px the inset shrinks so ~600px of content always survives, and
   it never drops under 24px. At 1500px+ this is exactly 450px a side. */
.learn-section .wrap{width:auto;max-width:none;margin:0 min(450px, max(24px, calc((100vw - 600px) / 2)))}
/* specced in caps; done here so the markup keeps readable text */
.learn-head{margin:0 0 70px;font-family:"Poppins",sans-serif;font-size:40px;font-weight:700;color:#717171;line-height:1.2;text-align:left;text-transform:uppercase}

/* row 2: media + links side by side. The media column is minmax(0,1fr) so it
   can never overflow the narrower inset container; the links column is a
   fixed track so the label->arrow spread stays readable. */
.learn-grid{display:grid;grid-template-columns:minmax(0,1fr) 240px;gap:clamp(24px,3vw,48px);align-items:center}

/* rounded/contained media, following the house .review-card treatment
   (20px radius + var(--shadow)) since there is no existing video convention.

   Why aspect-ratio is 2.4 and not 16/9: the source file is 1920x1080 but the
   picture is letterboxed inside it -- 116px of black at the top and 136px at
   the bottom, leaving 1920x828 (= 2.3188:1) of actual image, constant for the
   whole clip. object-fit:cover crops symmetrically, so a 2.3188 container
   would trim 126px a side: enough for the 116px top bar but leaving a 10px
   sliver of the 136px bottom one. 2.4 trims 140px a side, clearing both.
   max-width caps the height at 300px -- 46px below the previous 346px. */
.learn-media{width:100%;max-width:720px;aspect-ratio:2.4 / 1;border-radius:20px;overflow:hidden;box-shadow:var(--shadow);background:#111111}
.learn-media video{display:block;width:100%;height:100%;object-fit:cover}

/* pressable rows: label left, arrow right */
.learn-links{display:flex;flex-direction:column;gap:50px}
.learn-link{display:flex;align-items:center;justify-content:space-between;gap:24px;font-size:20px;font-weight:500;line-height:1.2;color:#717171;padding:6px 10px;border-radius:6px;transition:color .15s ease,background-color .15s ease}
/* hover reuses the header's interactive accent (#3D3D3D) plus a faint tint,
   and nudges the arrow -- see note in the handover if you want this changed */
.learn-link:hover,.learn-link:focus-visible{color:var(--header-ink-accent);background-color:#f1f1f1}
.learn-arrow{transition:transform .18s ease}
.learn-link:hover .learn-arrow,.learn-link:focus-visible .learn-arrow{transform:translateX(4px)}

/* ---------- "roof services" parallax section ----------
   Static single image (not a slideshow) behind a dark overlay.

   The image lives on its own .roof-bg layer rather than on the section's
   own background, because the parallax script translates it -- and a
   transform on the section itself would move the copy and the shape
   divider too. The layer is oversized (160% tall, pulled up 30%) so it can
   travel without exposing an edge. */
.roof-section{position:relative;width:100%;min-height:80vh;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111111;text-align:center}
/* path is relative to THIS file (assets/), not to the page */
.roof-bg{position:absolute;left:0;right:0;top:-30%;height:160%;background:url('ast_bg2.png') center / cover no-repeat;will-change:transform;z-index:0}
/* same technique as the hero overlay, a little denser (.55 vs .45) because
   this section carries a long paragraph rather than one short line */
.roof-overlay{position:absolute;inset:0;background:rgba(17,17,17,.55);z-index:1}

.roof-content{position:relative;z-index:2}
/* specced in caps; done here so the markup keeps readable text */
.roof-content h2{margin:0 0 15px;font-family:"Poppins",sans-serif;font-size:55px;font-weight:600;letter-spacing:10px;color:#FFFFFF;line-height:1.2;text-transform:uppercase}
/* 1.15rem is one of the site's own .lead steps; line-height opened to 1.7
   because this is long-form copy rather than a one-line lead */
.roof-copy{max-width:860px;margin:0 auto 50px;font-size:1.15rem;font-weight:400;line-height:1.7;letter-spacing:.02em;color:rgba(255,255,255,.92)}
/* grey variant of the established button -- shape and type come from
   .btn-primary, only the fill changes */
.btn-gray{background:var(--btn-gray)}
.btn-gray:hover,.btn-gray:focus-visible{background:var(--brand-primary)}
.roof-section .btn-primary{min-height:48px;padding:0 28px;font-size:16px}

/* --- Elementor shape divider (bottom edge) ---
   Elementor's own geometry: the path fills the TOP of its 1000x100 box, so
   a bottom divider is rotated 180deg to make it rise from the bottom. */
.elementor-shape{position:absolute;left:0;width:100%;overflow:hidden;line-height:0;direction:ltr;pointer-events:none;z-index:3}
.elementor-shape-bottom{bottom:0}
/* top dividers need no rotation -- the path already fills the top of its box */
.elementor-shape-top{top:0}
.elementor-shape svg{display:block;width:100%;height:100px;position:relative;left:50%;transform:translateX(-50%)}
.elementor-shape-bottom svg{transform:translateX(-50%) rotate(180deg)}
/* Matches the surface directly below this section. Nothing follows it yet,
   so this is the page background; change to #ffffff when a white section
   is added underneath. */
.elementor-shape-fill{fill:var(--next-surface)}

/* ---------- "recognized by the best" band ----------
   White, ~450px tall, one centred heading. min-height rather than height so
   the heading can wrap on narrow screens without being clipped. */
.recognized-section{width:100%;min-height:450px;background:#ffffff;display:flex;align-items:center;justify-content:center;padding:40px 0}
.recognized-section h2{margin:0;font-family:"Poppins",sans-serif;font-size:34px;font-weight:600;color:#565656;letter-spacing:.02em;line-height:1.3;text-align:center}

/* ---------- footer ----------
   Black, with a white top shape divider that reads as the white section
   above dipping into it. Column layout is flex-column so the 3-column row
   can absorb the leftover height instead of leaving a gap at the bottom. */
.site-footer{position:relative;width:100%;min-height:42vh;background:#000000;display:flex;flex-direction:column;overflow:hidden;color:var(--footer-ink)}
/* matches the surface above the footer, independent of --next-surface */
.site-footer .elementor-shape-fill{fill:var(--footer-shape-fill)}

/* 350px of side margin, same responsive pattern as .learn-section */
/* padding-top clears the 100px divider hanging into the footer */
.footer-main{flex:1 0 auto;display:flex;align-items:center;padding:130px 0 20px}
.footer-grid{width:100%;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:45px;align-items:start}

/* shared column heading */
.footer-head{margin:0;font-family:"Poppins",sans-serif;font-size:23px;font-weight:500;color:var(--footer-ink);line-height:1.3}

/* columns 2 and 3 are left-aligned */
.footer-col{display:flex;flex-direction:column;align-items:flex-start;gap:14px}
/* column 1 is centred */
.footer-col--brand{align-items:center;text-align:center;gap:16px}
/* logo: 25% larger than the header's clamp(48px,7vh,72px) */
.footer-logo{display:inline-flex}
.footer-logo img{height:clamp(60px,8.75vh,90px);width:auto;object-fit:contain}

/* contact rows -- house .footer-contact-item pattern, re-inked for black */
.footer-contact-item{display:flex;align-items:flex-start;gap:10px;color:var(--footer-ink);font-size:1rem;line-height:1.5;margin:0}
/* fixed 16px slot so the three different icon aspect ratios still line the
   text up; the viewBox keeps each glyph correctly proportioned inside it */
.footer-contact-item svg{flex:0 0 16px;width:16px;height:16px;fill:var(--footer-ink);margin-top:.2em}
a.footer-contact-item:hover,a.footer-contact-item:focus-visible{color:#ffffff}
a.footer-contact-item:hover svg,a.footer-contact-item:focus-visible svg{fill:#ffffff}

/* column 3: a row of three links, then Terms on its own row */
.footer-linkrow{display:flex;flex-wrap:wrap;column-gap:50px;row-gap:12px}
.footer-link{color:var(--footer-ink);font-size:1rem;line-height:1.5;transition:color .15s ease}
.footer-link:hover,.footer-link:focus-visible{color:#ffffff}

/* thin rule, inset from the footer edges (not from the 350px content margin) */
.footer-divider{height:2px;margin:0 55px;background:rgba(255,255,255,.4)}

/* bottom bar */
.footer-bottom{flex:0 0 auto;min-height:70px;margin-top:10px;display:flex;align-items:center;justify-content:center;text-align:center}
.footer-bottom p{margin:0;font-size:.95rem;line-height:1.5;color:var(--footer-ink)}

/* ---------- inner-page banner ----------
   Static single image behind the overlaying header, same treatment as the
   home page's slideshow backdrop minus the slideshow.
   min-height has a floor because the header (up to 108px) plus the label
   (90px) needs ~200px; a bare 25vh would collide on a short window. */
.page-banner{position:relative;width:100%;min-height:max(25vh,200px);background:#111111 center / cover no-repeat;overflow:hidden}
/* one modifier per page so the image is declared where it belongs rather than
   baked into the shared rule */
.page-banner--promotions{background-image:url('ast_bg4.webp')}
.page-banner--services{background-image:url('ast_services_bg.webp')}
/* reuses index.html's roof-services image */
.page-banner--commercial{background-image:url('ast_bg2.png')}
/* reuses the promotions banner image */
.page-banner--blogs{background-image:url('ast_bg4.webp')}
.page-banner--about{background-image:url('ast_bg4.webp')}
.page-banner--privacy{background-image:url('ast_bg5.webp')}
.page-banner--terms{background-image:url('ast_bg3.png')}
.page-banner--contact{background-image:url('ast_bg1.png')}
.page-banner--team{background-image:url('ast_bg4.webp')}
/* reuses the promotions/blogs/about/team banner image */
.page-banner--gallery{background-image:url('ast_bg4.webp')}
/* reuses the promotions/blogs/about/team/gallery banner image */
.page-banner--review{background-image:url('ast_bg4.webp')}
/* ---------- services: two-column body ----------
   100px of side margin where the viewport can spare it, same responsive
   pattern as .learn-section. Floors at ~800px of content so the three cards
   in column 1 never collapse below ~150px each. */
/* blogs.html uses the identical 60:40 shell, so both share one declaration --
   changing the margin here moves both pages. */
.services-body,.blogs-body{width:100%;background:#ffffff;padding:45px 0 60px}
.services-grid,.blogs-grid,.contact-grid,.contact-map-row{display:grid;grid-template-columns:60fr 40fr;gap:32px;align-items:start;margin:0 min(100px, max(24px, calc((100vw - 800px) / 2)))}

/* ------TITLE------ : the pseudo-elements each take an equal share of the
   leftover space, so the rules always meet the column edges */
.services-head{display:flex;align-items:center;gap:16px;margin:0 0 22px;font-family:"Poppins",sans-serif;font-size:2.3vw;font-weight:600;color:#000000;line-height:1.2;white-space:nowrap}
.services-head::before,.services-head::after{content:"";flex:1 1 0;height:1px;background:rgba(0,0,0,.25)}

/* three cards, 15px apart. Shadow matches the promo cards on promotions.html
   -- the section is white too, so the shadow is what defines the card. */
.services-cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:15px}
/* margin:0 resets the UA's default figure margin (1em 40px) */
.service-card{margin:0;background:#ffffff;border-radius:16px;overflow:hidden;box-shadow:0 10px 30px rgba(0,0,0,.22);display:flex;flex-direction:column}
/* sources are all portrait 2:3, so the box matches and cover never crops */
.service-card img{width:100%;aspect-ratio:2 / 3;object-fit:cover;display:block}
/* Specced at 1.5vw, but capped at 20px: at 500px insets a card is only ~165px
   wide (~141px inside the padding) and "Installation" renders 162px at 1.5vw
   of 1920 -- it was clipping. 20px keeps the longest word inside even at the
   narrowest card. overflow-wrap is a backstop for any longer word later.
   Widening the section inset is the alternative -- see the handover note. */
.service-card figcaption{padding:14px 12px;font-family:"Poppins",sans-serif;font-size:min(1.5vw,20px);font-weight:500;color:#000000;line-height:1.3;text-align:center;overflow-wrap:break-word}

/* column 2: form goes here later */
.form-placeholder{width:100%;height:800px;border:2px dashed rgba(0,0,0,.3);border-radius:16px}

/* ---------- embedded lead form ----------
   A class rather than the vendor snippet's #fillout-form id, so one rule
   styles every instance while each iframe keeps a unique id for its own
   height-listener script. 680px is a fallback only: the embed posts its real
   height back and the script overwrites this inline. */
.fillout-form-embed{display:block;width:100%;height:680px;border:none;border-radius:1rem}
/* matches the .commercial-head measure above it so the two edges align */
.fillout-form-embed--commercial{width:100%;max-width:var(--commercial-w)}

/* ---------- blogs: posts placeholder ----------
   Stands in for the feed that will come from AST's own blog API. Same dashed
   treatment as the form placeholders; 800px matches column 2 so the row reads
   as a deliberate pair. */
.blog-posts-placeholder{width:100%;height:800px;border:2px dashed rgba(0,0,0,.3);border-radius:16px;display:flex;align-items:center;justify-content:center;text-align:center;padding:24px;font-family:"Poppins",sans-serif;font-size:1rem;font-weight:400;color:rgba(0,0,0,.45)}

/* ---------- blog feed (rendered by blogs.html from the mirror API) ----------
   Structure follows LICH's blog listing; colours are AST's own -- LICH's pink
   #d13983 accent becomes black, per the palette convention used throughout. */
.blogs-feed{width:100%}
/* loading / empty / error state. Shares the dashed treatment above so the
   column keeps its shape while the fetch is in flight. */
.blogs-status{width:100%;min-height:420px;display:flex;align-items:center;justify-content:center;padding:24px;border:2px dashed rgba(0,0,0,.3);border-radius:16px;background:rgba(0,0,0,.02);text-align:center;font-family:"Poppins",sans-serif;font-size:1rem;font-weight:400;line-height:1.6;color:rgba(0,0,0,.55)}
/* 2 across, so serve.py's PAGE_SIZE of 6 lands as a clean 2x3 block. The rows
   are implicit -- 6 items fill three of them without the count being stated
   here, so an odd last page just leaves a short final row. minmax(0,1fr)
   rather than 1fr: a long unbroken word in a title would otherwise set the
   track's floor and push the grid wider than the column. */
.post-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:22px}
/* cards stay on the page: "Read more" swaps the feed for .post-detail below,
   rendered from the mirror's content_html, rather than leaving for WordPress.
   flex column + margin-top:auto on .post-more pins every "Read more" in a row
   to the same line, whatever the title and excerpt above it measure. */
.post-card{display:flex;flex-direction:column;background:#fff;border:1px solid var(--border);border-radius:16px;overflow:hidden;box-shadow:0 10px 30px rgba(0,0,0,.22);transition:transform .2s ease,box-shadow .2s ease;color:inherit;text-decoration:none}
.post-card:hover,.post-card:focus-within{transform:translateY(-3px);box-shadow:0 14px 36px rgba(0,0,0,.28)}
/* half of the old 220px: two of these sit side by side in the 60% column, so
   the image reads at roughly the width it used to at full column span */
.post-card-img{width:100%;height:150px;object-fit:cover;display:block}
.post-card-body{display:flex;flex-direction:column;flex:1;padding:16px 18px 18px}
.post-card-date{margin:0;font-family:"Poppins",sans-serif;font-size:.72rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.post-card-title{margin:6px 0 0;font-family:"Poppins",sans-serif;font-size:1.1rem;font-weight:600;line-height:1.35;letter-spacing:.01em;color:#000000}
/* clamped to 3 lines: the mirror's excerpts run to a full paragraph, which at
   this card width would be ~8 lines and swamp the title */
.post-card-excerpt{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;overflow:hidden;margin:8px 0 0;font-size:.88rem;line-height:1.6;color:var(--muted)}
/* a real button: it opens the in-page detail view instead of navigating */
.post-more{align-self:flex-start;margin-top:auto;padding:14px 0 0;background:none;border:none;border-bottom:2px solid #000000;font-family:"Poppins",sans-serif;font-size:.75rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:#000000;cursor:pointer;transition:color .15s ease,border-color .15s ease}
.post-card:hover .post-more,.post-more:hover,.post-more:focus-visible{color:var(--btn-gray);border-bottom-color:var(--btn-gray)}
.post-pager{display:flex;align-items:center;justify-content:center;gap:18px;margin-top:32px}
.post-pager button{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;padding:0 14px;background:#fff;border:1px solid var(--border);border-radius:8px;font-family:inherit;font-size:1.1rem;font-weight:700;color:#000000;cursor:pointer;transition:background .15s ease,color .15s ease}
.post-pager button:hover:not(:disabled),.post-pager button:focus-visible:not(:disabled){background:#000000;color:#fff}
.post-pager button:disabled{opacity:.35;cursor:default}
.post-pager-status{font-family:"Poppins",sans-serif;font-size:.95rem;font-weight:600;letter-spacing:.02em;color:var(--muted)}

/* ---------- single post, rendered in place ----------
   Same structure as LICH's detail view; the accent is black, and the card
   picks up AST's 16px radius and heavier shadow rather than LICH's.

   Unlike LICH's, this one is capped to the height of the lead form beside it
   and scrolls internally, so opening a post does not push the page taller than
   the list view was. The cap arrives as --blogs-detail-h, which blogs.html
   sets from the form column's MEASURED height: .fillout-form-embed declares
   680px, but the embed posts an ast-form-height message and resizes itself to
   ~1067px, so the declared value is not the one on screen. The 680px fallback
   here only applies if that script never runs.

   max-height rather than height: a post shorter than the form should stay
   short rather than sit in a tall box of white space. */
.post-view{display:flex;flex-direction:column;max-height:var(--blogs-detail-h,680px)}
.post-back{flex:none;align-self:flex-start;display:inline-flex;align-items:center;gap:8px;margin-bottom:20px;padding:0;background:none;border:none;font-family:"Poppins",sans-serif;font-size:.85rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--muted);cursor:pointer;transition:color .15s ease}
.post-back:hover,.post-back:focus-visible{color:#000000}
/* min-height:0 is what lets this shrink below its content so the scroll box
   inside it can take the overflow -- without it a flex item floors at its
   content height and the cap does nothing. */
.post-detail{display:flex;flex-direction:column;min-height:0;overflow:hidden;background:#fff;border:1px solid var(--border);border-radius:16px;padding:26px 30px 26px 34px;box-shadow:0 10px 30px rgba(0,0,0,.22)}
/* pinned: the date and title stay put while the article scrolls under them.
   The rule needs the divider -- without it the first paragraph slides up
   against the title with nothing to read as an edge. */
.post-detail-head{flex:none;padding-bottom:16px;border-bottom:1px solid var(--border)}
/* the scrolling region. The featured image lives in here rather than in the
   pinned header on purpose: at this column width it renders ~460px tall, which
   would leave almost none of the box for the text. */
.post-detail-scroll{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:20px 14px 4px 0}
.post-detail-img{width:100%;height:auto;border-radius:12px;display:block;margin-bottom:22px}
.post-detail h1{margin:8px 0 0;font-family:"Poppins",sans-serif;font-size:2rem;font-weight:600;line-height:1.25;letter-spacing:.01em;color:#000000}
/* the project styles no scrollbars anywhere else (.modal takes the default),
   but that is a transient overlay -- this one sits in the page next to the
   form, where a full-width chrome scrollbar reads as heavy against the card.
   Thin and grey; delete these two lines to go back to the browser default. */
.post-detail-scroll{scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.28) transparent}
.post-detail-scroll::-webkit-scrollbar{width:8px}
.post-detail-scroll::-webkit-scrollbar-track{background:transparent}
.post-detail-scroll::-webkit-scrollbar-thumb{background:rgba(0,0,0,.22);border-radius:8px}
.post-detail-scroll::-webkit-scrollbar-thumb:hover{background:rgba(0,0,0,.36)}
.post-detail-body{font-size:1.02rem;line-height:1.8;color:var(--text)}
.post-detail-body h2,.post-detail-body h3{margin:28px 0 10px;font-family:"Poppins",sans-serif;font-weight:600;line-height:1.3;color:#000000}
.post-detail-body h2{font-size:1.5rem}
.post-detail-body h3{font-size:1.2rem}
.post-detail-body p{margin:0 0 16px}
.post-detail-body ul,.post-detail-body ol{margin:0 0 16px;padding-left:26px}
.post-detail-body li{margin-bottom:8px}
.post-detail-body img{max-width:100%;height:auto;border-radius:12px;margin:12px 0}
.post-detail-body a{color:#000000;text-decoration:underline;text-underline-offset:2px}
.post-detail-body a:hover,.post-detail-body a:focus-visible{color:var(--btn-gray)}

/* ---------- about: story + stats row ----------
   80:10:10. The two 10% columns have to hold 45px numbers, and "Years" alone
   measures 120px at that size -- so a 10% column needs >=121px, meaning >=1202px
   of content. The inset therefore floors the content at 1200px: 350px is held
   on a ~1900px display and shrinks below that rather than crushing the columns.
   Row 2 is not built yet. */
.about-body{width:100%;background:#ffffff;padding:40px 0 60px}
.about-grid{display:grid;grid-template-columns:80fr 10fr 10fr;gap:32px;align-items:start}
/* Both rows share ONE inset so they can never drift out of alignment.
   margin-inline, not the margin shorthand, so .story-row2 keeps its 20px
   margin-top. */
.about-grid,.story-row2{margin-inline:min(250px, max(24px, calc((100vw - 1200px) / 2)))}
/* align-self centres the block vertically in the row; text-align keeps the
   text itself left-aligned */
.about-col-story{text-align:left;align-self:center}
/* specced in caps; done here so the markup keeps readable text */
.about-head{margin:0 0 16px;font-family:"Poppins",sans-serif;font-size:34px;font-weight:600;color:#000000;line-height:1.3;text-transform:uppercase}
.about-copy{margin:0;font-size:1.05rem;font-weight:400;line-height:1.7;color:var(--text)}
/* column 2 holds one stat block, column 3 splits into two equal rows */
.about-stat{display:grid;gap:28px;align-content:start}
.about-stat--split{grid-template-rows:1fr 1fr}
/* column 2 only: centre it against the row's height so its single block lines
   up with the midpoint of column 3's two blocks, rather than sitting at the top */
.about-stat:not(.about-stat--split){align-self:center}
.stat-block{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:6px}
.stat-num{margin:0;font-family:"Poppins",sans-serif;font-size:45px;font-weight:600;color:#000000;line-height:1.1;overflow-wrap:break-word}
.stat-label{margin:0;font-family:"Poppins",sans-serif;font-size:18px;font-weight:400;color:#000000;line-height:1.35;overflow-wrap:break-word}

/* ---------- about row 2: form + mission ----------
   55:45, sitting 20px under row 1. align-items:stretch lets column 1's
   placeholder match whatever height column 2's content comes out at. */
.story-row2{display:grid;grid-template-columns:55fr 45fr;gap:32px;margin-top:20px;align-items:stretch}
.story-form-col{display:flex;align-items:center;justify-content:center}
.form-placeholder--about{width:100%;height:100%;min-height:520px}

/* column 2: everything centred on both axes */
.story-mission{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:22px}
/* radius follows the site's own rounded-media convention (16px, as on the
   service and promo cards) */
.story-image{width:100%;max-width:560px;height:auto;border-radius:16px;display:block}
/* text reads left-aligned, but the block itself is centred by the flex above */
.story-copy{margin:0;max-width:560px;text-align:left;font-size:1.05rem;font-weight:400;line-height:1.7;color:var(--text)}

/* Two award items, icon above a short heading. Self-contained to AST: the
   icon fill is #000000, not the navy used on the site this pattern came from,
   and it depends on nothing outside this stylesheet. */
.story-awards{display:grid;grid-template-columns:1fr 1fr;gap:10px;width:100%;max-width:560px}
.story-award{background:#ffffff;border:2px solid var(--border);border-radius:16px;padding:28px 20px;box-shadow:0 3px 8px rgba(17,17,17,.10);text-align:center}
.story-award-icon{width:64px;height:64px;margin:0 auto 20px;display:flex;align-items:center;justify-content:center}
.story-award-icon svg{width:100%;height:100%;fill:#000000}
.story-award h3{margin:0;font-family:"Poppins",sans-serif;font-size:1.35rem;font-weight:600;letter-spacing:.02em;line-height:1.3;color:#000000}

/* ---------- privacy policy: intro block ----------
   Written independently into AST: every size, spacing and weight value is
   reproduced, but no font stack is copied -- these elements inherit AST's
   Poppins body rule. --black / --bg / --text are AST's own variables, so
   nothing here reaches outside this stylesheet. */
/* white, set explicitly. overflow-x lives here rather than on
   .policy-describes so the checklist divider can run wider than the 960px
   content column while still being clipped at the section edge (no page scroll). */
.page-hero{padding:0 24px 96px;background:#FFFFFF;text-align:center;overflow-x:hidden}
.page-hero-inner{max-width:960px;margin:0 auto}
.page-hero h1{margin:0 0 20px;font-size:clamp(2.7rem,5vw,4.1rem);line-height:1.06;font-weight:600;letter-spacing:.02em;color:var(--black)}
.title-divider{border:none;border-top:1px solid var(--black);width:70%;margin:16px auto 32px}
/* The divider and the policy body both hang symmetrically outside the 960px
   column by --policy-overhang, so they share identical left/right edges.
   144px each side = +288px = the specced +30% on 960px. It is clamped against
   the viewport (1008 = 960 + 48px of gutters) because the body carries TEXT:
   a fixed 130% width put the copy 31px off-screen on each side at 1200px and
   the words were being cut off. */
.policy-describes{--policy-overhang:max(0px, min(144px, calc((100vw - 1008px) / 2)))}
.checklist-divider{border:none;border-top:2px solid var(--black);margin:16px 0 32px}
/* The overhang only applies to a divider that sits BESIDE .policy-content
   (privacy page). On the terms page the dividers sit INSIDE .policy-content,
   which already carries the overhang -- applying it again made them 1536px,
   288px wider than the text. Direct-child scoping keeps both at 1248px. */
.policy-describes > .checklist-divider{margin-left:calc(-1 * var(--policy-overhang));margin-right:calc(-1 * var(--policy-overhang))}
/* Higher specificity than .policy-checklist (0,1,1 vs 0,1,0), so this wins on
   margin and display -- the list ends up inline-block and shrink-to-fit,
   centred by .page-hero's text-align. Reproduced to match the source layout;
   note it also cancels .policy-checklist's grid gap. */
.policy-describes > ul{list-style:none;padding:0;margin:16px auto 0;display:inline-block;text-align:left}
.page-hero-subtitle{margin:0 0 18px;font-size:35px;font-weight:600;letter-spacing:.02em;color:var(--black);text-align:center}
.policy-checklist{list-style:none;padding:0;margin:0 auto 24px;max-width:700px;display:grid;gap:14px;text-align:left}
.policy-checklist li{display:flex;align-items:flex-start;gap:12px;color:var(--text);font-size:1.02rem;line-height:1.7}
.policy-checklist .checkmark{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;min-width:20px;flex-shrink:0;margin-top:2px;color:var(--black);font-weight:800;line-height:1}

/* --- policy body ---
   Structural only for now, per the brief: AST branding pass still to come.
   Two values from the source were deliberately NOT carried over -- its pink
   link colour (#d13983) and border-radius:0 on the button, both of which
   belong to that site's identity, not AST's. */
/* same overhang as .checklist-divider -> identical left/right edges */
.policy-content{text-align:left;margin-left:calc(-1 * var(--policy-overhang));margin-right:calc(-1 * var(--policy-overhang))}
.policy-section-title{margin:50px 0 16px;font-size:35px;font-weight:600;letter-spacing:.02em;color:var(--black);text-align:left;line-height:1.2}
.policy-content p{margin:0 0 16px}
.policy-content ul{margin:0 0 16px;padding-left:40px;list-style:disc;list-style-position:outside}
.policy-content li{margin-bottom:8px;font-size:1rem;line-height:1.7}
/* Every link in the policy body -- external opt-out links on the privacy page
   and the internal Privacy Policy link on the terms page -- gets the same flat
   pink: no underline, no hover change. The CTA button is unaffected because
   .policy-content .btn-primary (0,2,0) outranks this selector (0,1,1). */
.policy-content a{color:#CC3370;text-decoration:none;transition:none}
.policy-contact-row{display:flex;align-items:flex-start;gap:32px}
.policy-contact-row p{flex:1 1 0;min-width:0;margin:0}
.policy-contact-row .btn-primary{align-self:flex-start;flex-shrink:0}
/* CTA buttons in this section only. The :hover pair is needed because the
   base .btn-primary:hover would otherwise repaint them #333333. */
/* text-decoration:none because .policy-content a underlines every anchor in
   this section, and the CTA is an <a> */
.policy-content .btn-primary{background:#618AC1;color:#ffffff;text-decoration:none}
.policy-content .btn-primary:hover,.policy-content .btn-primary:focus-visible{background:#4F76A9}

/* ---------- contact: row 1 ----------
   Structure adapted independently into AST. The source panel is a dark block
   with white text and an #FFA300 accent on every icon; AST's palette puts it
   on white with #000/#393939 ink, so the icons take the ink colour instead of
   carrying over the orange. Row 2 is not built yet.
   The 60:40 shell is the shared .services-grid rule. */
.contact-body{width:100%;background:#ffffff;padding:50px 0 60px}
/* align-self:center centres the whole column against the taller form column,
   the same treatment .about-col-story uses against its stat columns */
.contact-col-main{display:flex;flex-direction:column;align-items:flex-start;align-self:center}
.contact-title{margin:0;font-family:"Poppins",sans-serif;font-size:70px;font-weight:500;line-height:80px;letter-spacing:.02em;color:#000000}
.contact-lead{margin:20px 0 0;max-width:620px;font-size:1.05rem;font-weight:400;line-height:1.7;letter-spacing:.01em;color:var(--text)}
/* the whole phone row is the tap target, icon included */
.contact-phone{margin:20px 0 0;font-family:"Poppins",sans-serif;font-size:30px;font-weight:600;line-height:1.3;color:#393939}
.contact-phone a{display:inline-flex;align-items:center;gap:10px;color:inherit;text-decoration:none}
.contact-phone svg{width:30px;height:30px;min-width:30px;fill:currentColor}
.contact-meta{display:flex;align-items:center;gap:10px;margin:14px 0 0;font-family:"Poppins",sans-serif;font-size:18px;font-weight:600;line-height:1.4;color:#393939}
.contact-meta svg{width:20px;height:20px;min-width:20px;fill:currentColor}
.contact-meta a{color:inherit;text-decoration:none}
/* Accepted payment methods: six brand marks, left-aligned in the column.
   Static by design -- pointer-events:none keeps the row unclickable.
   Sizes/gaps mirror the source: 80px icons above 1024px, 40px at or below it;
   20px gaps, dropping to 5px and wrapping at or below 767px. */
.contact-cards{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;align-self:stretch;gap:20px;padding:10px;margin-top:20px;pointer-events:none;user-select:none}
.contact-cards img{display:block;flex:none;width:80px;height:80px}
@media (max-width:1024px){.contact-cards img{width:40px;height:40px}}
@media (max-width:767px){.contact-cards{flex-wrap:wrap;gap:5px}}

/* --- row 2: map ---
   Joins the shared inset rule above so it lines up with row 1's edges, then
   overrides to a single full-width column. */
.contact-map-row{grid-template-columns:minmax(0,1fr);margin-top:32px}
/* No position:relative needed -- the embed supplies its own "open in Maps"
   control, so there is nothing absolutely positioned over the map. */
.map-frame{background:#252525;border-radius:16px;padding:22px}
.map-frame iframe{display:block;width:100%;height:420px;border:0;border-radius:10px}

/* ---------- commercial: centred estimate block ----------
   34px heading matches .recognized-section h2, the site's other single
   centred heading in a white band. */
/* --commercial-w is the shared measure for the heading and the form below it,
   so their edges line up. 620px clears the heading's natural 614px at 34px,
   which keeps it on one line. */
.commercial-body{width:100%;background:#ffffff;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:22px 24px 60px;text-align:center;--commercial-w:620px}
.commercial-head{width:100%;max-width:var(--commercial-w);margin:0 0 10px;font-family:"Poppins",sans-serif;font-size:34px;font-weight:600;color:#000000;line-height:1.3}
/* same dashed treatment as the services placeholder, 500px wide instead of full */
.form-placeholder--commercial{width:500px;max-width:100%;height:800px}

/* ---------- our team ----------
   50px below the banner, matching .contact-body. */
.team-body{width:100%;background:#ffffff;padding:50px 0 60px}
/* ~80% of the viewport, centred, with a cap so it stops widening on very
   large screens and a 24px gutter floor on small ones. */
.team-grid{width:min(1600px,70%);margin:0 auto;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));column-gap:22px;row-gap:10px}
/* 7 cards into a 2-wide auto-flow grid gives 4 rows, the last one half full.
   min-height rather than height: 200px is the target, but a card that wraps
   an extra line grows instead of clipping. */
.team-card{display:grid;grid-template-columns:30fr 70fr;align-items:center;min-height:200px;padding:20px;background:#ffffff;border-radius:16px;box-shadow:0 10px 30px rgba(0,0,0,.22)}
/* card column 1: photo, centred on both axes */
.team-photo-col{display:flex;align-items:center;justify-content:center}
/* The source files are transparent canvases with a centred circular portrait,
   so cover crops away only the empty margin and the circle fills the frame.
   border-radius is still applied so the frame is round regardless of source. */
.team-photo{width:100px;height:100px;flex:none;border-radius:50%;object-fit:cover;object-position:50% 50%}
/* card column 2: text, left aligned */
.team-info{min-width:0;text-align:left}
.team-name{margin:0;font-family:"Poppins",sans-serif;font-size:23px;font-weight:600;color:#000000;line-height:1.25}
/* one step down from the 23px name. Tightened from 18px/20px so the stack
   clears 200px even when the longest role wraps to two lines. */
.team-role{margin:0 0 12px;font-family:"Poppins",sans-serif;font-size:16px;font-weight:700;color:#000000;line-height:1.35}
/* plain text, not links -- same icon + label pattern as .contact-meta.
   Hidden for now -- several members (Brody, Addison) are still missing a
   phone/email, so it's off for the whole team rather than showing an
   inconsistent mix. Markup is left in place; flip display back to flex
   once every member's details are filled in. */
.team-contact{display:none;align-items:center;gap:8px;margin:6px 0 0;font-family:"Poppins",sans-serif;font-size:14px;font-weight:400;line-height:1.5;color:var(--text)}
.team-contact svg{width:16px;height:16px;min-width:16px;fill:currentColor}
.team-contact span{overflow-wrap:break-word;min-width:0}
/* closing line under the grid */
.team-note{width:min(900px,calc(100% - 48px));margin:40px auto 0;font-family:"Poppins",sans-serif;font-size:1rem;font-weight:400;line-height:1.65;color:#000000;text-align:center}
/* Own breakpoint rather than the shared 900px one: below ~1000px the text
   column in a two-up card is too narrow to hold the longest role on two
   lines within 200px, so the cards go one-up while they can still keep the
   200px height. 70% also wastes too much width once they are stacked. */
@media (max-width:1000px){
  .team-grid{grid-template-columns:minmax(0,1fr);width:calc(100% - 48px)}
}

/* lower-left label; only the top-right corner is rounded */
.banner-label{position:absolute;bottom:0;left:0;z-index:2;width:min(400px,88vw);min-height:90px;display:flex;align-items:center;justify-content:center;padding:18px 32px;background:rgba(151,152,151,.85);border-top-right-radius:24px;border-top-left-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0}
.banner-title{margin:0;font-family:"Poppins",sans-serif;font-size:35px;font-weight:400;color:#FFFFFF;line-height:1.2;text-align:center}

/* ---------- promotions intro ----------
   White band under the banner. 1140px content column, centred on the page,
   with everything inside centred too -- the CTA is inline-flex, so the
   container's text-align centres it without needing its own margins. */
.promo-intro{width:100%;background:#ffffff;padding:50px 0 60px}
/* 1380px, not 1140: the 55px heading needs at least 1330px to break into two
   lines instead of three (measured), so this keeps ~50px of headroom. */
.promo-content{width:min(1380px,calc(100% - 48px));margin:0 auto;text-align:center}
/* both headings are specced in caps; done here so the markup keeps readable
   text (the subtitle is mixed case, so it gets no transform) */
.promo-title{margin:0;font-family:"Poppins",sans-serif;font-size:55px;font-weight:600;line-height:60px;letter-spacing:.02em;color:#363636;text-transform:uppercase}
.promo-subtitle{margin:0;font-family:"Poppins",sans-serif;font-size:20px;font-weight:600;line-height:60px;color:#363636}
/* black rounded-rectangle CTA, same shape logic as .btn-primary. text-transform
   is reset to none because .btn-primary capitalises, which would render the
   specced "to" as "To". */
.promo-cta{margin-top:8px;min-height:64px;padding:0 32px;gap:14px;font-size:25px;font-weight:500;text-transform:none}
/* mirrored so the handset faces into the label rather than away from it */
.promo-cta svg{flex:0 0 24px;width:24px;height:24px;fill:#fff;transform:scaleX(-1)}
/* auto side margins so the 900px measure is centred too, not just its text */
.promo-copy{margin:26px auto 0;max-width:900px;font-size:1.05rem;font-weight:400;line-height:1.7;color:var(--text)}
.promo-copy strong{font-weight:700}
.promo-offers-head{margin:45px 0 0;font-family:"Poppins",sans-serif;font-size:40px;font-weight:600;color:#000000;line-height:1.2;text-transform:uppercase}

/* ---------- promotional offer cards ----------
   20:80 is honoured as a PROPORTION, not fixed heights: the head is pinned to
   84px against a 420px min card (= exactly 20:80) so the three title bars line
   up, and the body takes the remainder. Card 3's paragraph is ~50% longer than
   the others, so a literal 20%/80% of a fixed height would either clip it or
   leave cards 1-2 half empty. align-self:stretch keeps all three equal height
   whichever one is tallest. */
.promo-cards{display:flex;flex-direction:row;justify-content:center;align-items:center;flex-wrap:wrap;gap:24px;margin-top:30px}
/* The body is white and so is the section behind it, so the shadow is what
   separates the card from the page. It sits on the outer container so it
   wraps both rows as one unit. */
.promo-card{flex-grow:1;flex-shrink:1;flex-basis:0;min-width:280px;align-self:stretch;display:flex;flex-direction:column;min-height:420px;border-radius:16px;overflow:hidden;box-shadow:0 10px 30px rgba(0,0,0,.22)}
/* row 1 (~20%) -- min-height rather than a hard basis so a title that wraps on
   a narrow card grows the bar instead of being clipped */
.promo-card-head{flex:0 0 auto;min-height:84px;display:flex;align-items:center;justify-content:center;padding:14px 22px;background:#2D2D2D}
.promo-card-title{margin:0;font-family:"Poppins",sans-serif;font-size:29px;font-weight:700;color:#FFFFFF;letter-spacing:.01em;line-height:1.15;text-align:center}
/* row 2 (~80%) */
/* row 2 -- white surface, black ink. color:#000 is what drives the icons,
   which are fill:currentColor. */
.promo-card-body{flex:1 1 auto;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:14px;padding:28px 24px;background:#FFFFFF;color:#000000;text-align:center}
/* card 3's icon is a raster (ast_promo_card3.jpg), so it is matched to the
   inline SVGs' 88px box. It is black line art on a white ground, which is why
   a JPEG with no alpha still sits flush on the white row. */
.promo-card-body svg,.promo-card-body img{width:88px;height:88px;flex:0 0 auto;object-fit:contain}
.promo-card-body svg{fill:currentColor}
.promo-card-sub{margin:0;font-family:"Poppins",sans-serif;font-size:20px;font-weight:600;line-height:1.3;color:#000000}
.promo-card-copy{margin:0;font-size:1rem;font-weight:400;line-height:1.65;color:#000000}

/* ---------- centred modal ----------
   A true blocking dialog -- dimmed overlay, aria-modal, body scroll locked.
   z-index 10000 clears .site-header (100) and .nav-menu (50) by a wide
   margin; it does NOT clear JustCall's floating widget, which sets
   2147483647 on itself, but that sits in the bottom corner and does not
   overlap the centred panel. Transition follows the house .18s ease
   opacity/visibility pair, with the panel itself easing in on transform. */
.modal-overlay{position:fixed;inset:0;z-index:10000;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(0,0,0,.5);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .18s ease,visibility .18s ease}
.modal-overlay.is-open{opacity:1;visibility:visible;pointer-events:auto}
.modal{position:relative;width:min(520px,100%);max-height:calc(100vh - 48px);overflow-y:auto;padding:32px;background:var(--panel);border:1px solid var(--border);border-radius:16px;box-shadow:0 24px 60px rgba(17,17,17,.28);transform:translateY(12px) scale(.98);transition:transform .18s ease}
.modal-overlay.is-open .modal{transform:translateY(0) scale(1)}
.modal-close{position:absolute;top:12px;right:12px;width:36px;height:36px;display:inline-flex;align-items:center;justify-content:center;padding:0;background:none;border:none;border-radius:50%;font-family:inherit;font-size:1.5rem;line-height:1;color:var(--muted);cursor:pointer;transition:background .15s ease,color .15s ease}
.modal-close:hover,.modal-close:focus-visible{background:#f1f1f1;color:var(--black)}
.modal-title{text-align:center;margin:0 0 16px;font-family:"Poppins",sans-serif;font-weight:700;font-size:22px;line-height:1.3;color:var(--black)}
/* the page behind must not scroll while a blocking dialog is up */
body.modal-open{overflow:hidden}
.form-placeholder--modal{height:360px}

/* The floating contact control is JustCall's own widget, loaded by
   assets/justcall-widget.js. It injects its own markup on document.body and
   carries its own styling, positioning (bottom-left, per the account's
   buttontype setting) and z-index, so there is deliberately nothing for this
   stylesheet to declare for it. AST's hand-built .just-call button and
   .jc-panel-wrap modal used to live here and were a replica of that same
   widget; they were retired rather than kept alongside it. */

/* ---------- responsive ---------- */
/* Nav stays at the specced 16px at every width -- only the between-item
   margin tightens, then the row wraps below 1100px. */
@media (max-width:1400px){
  .nav > a,.nav > .nav-item{margin-left:calc(20px / 2);margin-right:calc(20px / 2)}
}
@media (max-width:1100px){
  .header-inner{flex-wrap:wrap;gap:16px;padding:12px 0}
  .nav{order:3;width:100%;justify-content:center}
  .header-actions{margin-left:0}
}
/* Below this the wrapped nav row plus the socials/CTA column is taller than
   the hero copy it sits over, so the header becomes logo + hamburger and the
   rest moves into .nav-drawer. Must stay after the 1100px block above, which
   it overrides (flex-wrap, and the nav it hides). */
@media (max-width:980px){
  .header-inner{flex-wrap:nowrap;gap:16px;padding:10px 0;min-height:96px}
  .nav,.header-actions{display:none}
  .nav-toggle{display:inline-flex}
  /* the logo comes down with the shorter bar */
  .brand img{height:clamp(60px,9vh,80px)}
}
/* Above the breakpoint the drawer must be unreachable even if an is-open
   class survives a resize. The script also closes it on resize; this is the
   belt to that braces. */
@media (min-width:981px){
  .nav-drawer,.nav-backdrop{display:none}
}
/* 56px is the specced desktop size; below this it would wrap badly and
   overflow the section, so it steps down. */
@media (max-width:760px){
  .hero-content h1{font-size:38px}
  .hero-content .lead{font-size:1.15rem}
  .review-card,.hero-section .btn-primary{width:100%}
  .hero-section .btn-primary{justify-content:center}
}
/* Below this the content can no longer hold 1200px, so the 10% columns would
   drop under the 121px the 45px numbers need -- stack instead of crushing. */
@media (max-width:1240px){
  .about-grid{grid-template-columns:minmax(0,1fr);gap:36px}
  .about-stat--split{grid-template-rows:auto auto}
  .story-row2{grid-template-columns:minmax(0,1fr);gap:28px}
  .form-placeholder--about{height:520px}
}
/* privacy intro: the same two step-downs the pattern uses */
/* padding-top stays 0 here too -- only the bottom steps down */
@media (max-width:980px){
  .page-hero{padding-bottom:72px}
}
@media (max-width:640px){
  .page-hero h1{font-size:2.6rem}
  .policy-checklist li{font-size:.96rem}
  /* PRE-EXISTING OVERFLOW, unrelated to the header/footer work: the awards
     pair is `1fr 1fr`, and 1fr's implicit minimum is auto, so "Workmanship"
     (~204px at 1.35rem, unbroken) floored the second track and pushed the
     card ~2px past the viewport at 375px -- a real horizontal scroll. Two
     cards need ~474px of viewport to hold that word, so below this they go
     one per row, where 327px is ample. */
  .story-awards{grid-template-columns:minmax(0,1fr)}
  /* 30% of the remaining width is now under the 100px photo, so stack the
     card: photo on top, text still left aligned beneath it */
  .team-card{grid-template-columns:minmax(0,1fr);row-gap:16px;justify-items:start;padding:20px}
  .team-photo-col{justify-content:flex-start}
}
/* ---------- blog grid: where two cards across stops paying off ----------
   The feed column's width is NOT monotonic in viewport width, because
   .blogs-grid drops its 60:40 split at 900px: at 880px the feed has the full
   ~800px inset width, but at 920px it is back to 60% of it, or ~460px. So the
   two narrow cases are a band in the middle, not just small screens:

     >=1141px   60% of the inset is >=540px   two cards, >=259px each
     901-1140px 60% of the inset is  <540px   ONE card  (would be ~219px)
     641-900px  feed is full width, ~590-800px  two cards, >=285px each
     <=640px    full width but the inset caps it  ONE card

   Both single-column cases want the same roomier card, so they share a rule
   rather than the 640px block carrying its own copy. 260px per card is the
   floor being enforced -- below it the title starts taking three lines. */
@media (max-width:640px), (min-width:901px) and (max-width:1140px){
  .post-list{grid-template-columns:minmax(0,1fr);gap:20px}
  .post-card-img{height:200px}
  .post-card-body{padding:20px 22px 22px}
  .post-card-date{font-size:.78rem}
  .post-card-title{font-size:1.25rem}
  .post-card-excerpt{-webkit-line-clamp:4;line-clamp:4;font-size:.95rem}
  .post-more{font-size:.8rem}
}
/* the two learn columns stop fitting side by side well before this */
@media (max-width:900px){
  .learn-grid{grid-template-columns:minmax(0,1fr);gap:40px}
  .learn-media{max-width:none}
  .learn-head{font-size:30px;margin-bottom:40px}
  .learn-links{gap:32px}
  /* three cards no longer fit across, and 2+1 would leave a lone stretched
     card on the second row -- stack them one per row instead */
  .promo-card{flex-basis:100%;min-height:0}
  /* 60:40 stops working once the column is narrower than the cards need, and
     the vw type would fall to ~9px, so both get pinned here */
  .services-grid,.blogs-grid,.contact-grid{grid-template-columns:minmax(0,1fr);gap:36px}
  /* the form is below the post now, not beside it, so there is no longer a
     column to match -- and a capped scroll box inside a scrolling page is the
     nested-scroll trap on touch. Let the post run to its natural height. */
  .post-view{max-height:none}
  .post-detail{overflow:visible}
  .post-detail-scroll{overflow-y:visible;padding-right:0}
  .map-frame{padding:14px}
  .map-frame iframe{height:320px}
  .contact-title{font-size:38px;line-height:46px}
  .blog-posts-placeholder{height:480px}
  .services-head{font-size:24px}
  .service-card figcaption{font-size:15px}
  .form-placeholder{height:520px}
  .commercial-head{font-size:24px}
  .form-placeholder--commercial{height:560px}
}
/* 55px + 10px tracking is ~1000px wide -- it has to come down early */
@media (max-width:1100px){
  .roof-content h2{font-size:38px;letter-spacing:6px}
  .elementor-shape svg{height:70px}
  /* divider is 70px here, so the clearance padding comes down with it */
  .footer-main{padding-top:100px}
}
/* three columns stop fitting once the inset has eaten the width */
@media (max-width:860px){
  .footer-grid{grid-template-columns:minmax(0,1fr);gap:36px}
  .footer-col--brand{align-items:flex-start;text-align:left}
  .footer-divider{margin:0 24px}
}
@media (max-width:760px){
  .roof-content h2{font-size:28px;letter-spacing:4px}
  .roof-copy{font-size:1.05rem;margin-bottom:40px}
  .elementor-shape svg{height:50px}
  .recognized-section{min-height:340px}
  .recognized-section h2{font-size:26px}
  .banner-label{width:100%;min-height:72px;padding:14px 20px;border-top-right-radius:18px}
  .banner-title{font-size:26px}
  /* 55px would wrap to six lines and the nowrap CTA would overflow */
  .promo-title{font-size:30px;line-height:36px}
  .promo-subtitle{font-size:18px;line-height:40px}
  .promo-cta{font-size:17px;min-height:54px;padding:0 20px;white-space:normal;text-align:center}
  .promo-offers-head{font-size:26px;margin-top:36px}
  .footer-main{padding-top:80px}
  .footer-head{font-size:20px}
}
/* ---------- footer at phone widths ----------
   The grid already stacked at 860px, where the columns stay left-aligned
   because they are still wide. At phone widths a single narrow column of
   left-aligned text with a centred logo above it reads as misaligned, so
   everything centres instead.

   This block has to stay AFTER the 860px block: it re-centres
   .footer-col--brand, which that block sets to flex-start at the same
   specificity, so source order is what decides it. */
@media (max-width:640px){
  .footer-main{padding-top:64px}
  .footer-grid{gap:30px}
  .footer-col,.footer-col--brand{align-items:center;text-align:center}
  /* these are flex rows (icon + text), so centring needs the main axis */
  .footer-contact-item{justify-content:center}
  .footer-linkrow{justify-content:center;column-gap:28px}
  .footer-head{font-size:19px}
  .footer-contact-item,.footer-link{font-size:.95rem}
  .footer-logo img{height:clamp(52px,7vh,72px)}
  /* 24px each side against ~330px of content left a stubby line; 16px keeps
     it reading as a full-width rule */
  .footer-divider{margin:0 16px}
  .footer-bottom{min-height:60px}
  .footer-bottom p{font-size:.9rem}
}
/* the drawer slide is decorative -- honour a reduced-motion preference */
@media (prefers-reduced-motion:reduce){
  .nav-drawer,.nav-backdrop{transition:none}
}

/* ---------- gallery page ----------
   Category-card + modal-carousel + lightbox, matching the old WordPress
   site's actual pattern (one card per Pinterest board mirrored -- AST has
   exactly one, "Roofing" -- opening a modal with a photo carousel and a
   click-to-enlarge lightbox). Colors/spacing use AST's own tokens
   (--black/--panel/--shadow/--gold/--bg/--muted etc.), not WordPress's
   hardcoded navy (#0a4d8c/#062a52). .gallery-status is shared with the
   carousel's own loading/empty states below. */
.gallery-body{padding:64px 0}
.gallery-status{padding:40px 0;text-align:center;color:var(--muted)}

/* -- card grid -- */
/* auto-fit (not auto-fill) + a bounded max track (360px, not 1fr) + justify-content
   are what make this centre when the row isn't full -- auto-fill would still lay
   out as many ~280px columns as the container fits, leaving a lone card pinned to
   column 1 instead of centred, and a 1fr max would swallow the leftover width
   before justify-content ever saw it. */
.gallery-feed{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,360px));justify-content:center;gap:24px}
.gallery-card{position:relative;display:block;width:100%;aspect-ratio:3/4;margin:0;padding:0;border:none;border-radius:16px;overflow:hidden;background:var(--panel);box-shadow:var(--shadow);cursor:pointer;font:inherit;color:inherit;text-align:left}
.gallery-card[aria-disabled="true"]{cursor:default}
.gallery-card-img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .3s ease}
.gallery-card:not([aria-disabled="true"]):hover .gallery-card-img,
.gallery-card:not([aria-disabled="true"]):focus-visible .gallery-card-img{transform:scale(1.04)}
.gallery-card-overlay{position:absolute;inset:0;background:linear-gradient(to top,rgba(17,17,17,.65) 0%,rgba(17,17,17,0) 48%);pointer-events:none}
.gallery-card-title{position:absolute;left:20px;bottom:18px;z-index:2;color:#fff;font-family:"Poppins",sans-serif;font-size:24px;font-weight:700;text-shadow:0 1px 3px rgba(0,0,0,.4)}
.gallery-card-arrow{position:absolute;right:18px;bottom:18px;z-index:2;width:46px;height:46px;border-radius:50%;background:rgba(255,255,255,.15);border:1.5px solid #fff;display:flex;align-items:center;justify-content:center;color:#fff}
.gallery-card-arrow svg{width:20px;height:20px}
@media (max-width:600px){
  .gallery-feed{grid-template-columns:1fr}
}

/* -- modal: title, carousel, CTA banner -- */
.gallery-modal{display:none;position:fixed;inset:0;z-index:10000;background:rgba(17,17,17,.85)}
.gallery-modal.is-open{display:block}
.gallery-modal-inner{position:relative;width:95%;max-width:1200px;max-height:90vh;margin:4vh auto;box-sizing:border-box;padding:32px;background:var(--panel);border-radius:16px;overflow-y:auto;box-shadow:0 24px 60px rgba(17,17,17,.28)}
.gallery-modal-close{position:absolute;right:16px;top:8px;width:40px;height:40px;display:inline-flex;align-items:center;justify-content:center;padding:0;background:none;border:none;border-radius:50%;font-family:inherit;font-size:1.75rem;line-height:1;color:var(--muted);cursor:pointer;transition:background .15s ease,color .15s ease}
.gallery-modal-close:hover,.gallery-modal-close:focus-visible{background:#f1f1f1;color:var(--black)}
.gallery-modal-title{text-align:center;margin:0 0 24px;font-family:"Poppins",sans-serif;font-weight:700;font-size:32px;letter-spacing:.01em;color:var(--black)}
.gallery-modal-cta{margin-top:32px;padding:24px 28px;border-radius:16px;background:var(--bg);display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:20px}
.gallery-modal-cta h3{margin:0 0 6px;font-size:20px;font-weight:700;color:var(--black)}
.gallery-modal-cta p{margin:0;font-size:15px;color:var(--muted)}
@media (max-width:600px){
  .gallery-modal-inner{width:100%;height:100%;max-height:none;margin:0;border-radius:0;padding:24px 16px}
  .gallery-modal-title{font-size:26px}
}

/* -- carousel (inside the modal) -- */
.gallery-carousel{position:relative;display:block;margin:12px 0;padding:0 44px;box-sizing:border-box}
.gallery-carousel-track-wrap{overflow:hidden}
.gallery-carousel-track{display:flex;transition:transform .35s ease}
.gallery-carousel-track img{aspect-ratio:4/5;object-fit:cover;display:block;box-sizing:border-box;flex:0 0 auto;cursor:pointer;transition:opacity .2s ease}
.gallery-carousel-track img:hover{opacity:.9}
.gallery-carousel-nav{background:var(--panel);border:none;border-radius:50%;padding:0;color:var(--black);cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:var(--shadow)}
.gallery-carousel-nav:hover,.gallery-carousel-nav:focus-visible{background:var(--bg);color:var(--black)}
.gallery-carousel-nav svg{display:block;pointer-events:none}
.gallery-carousel .gallery-carousel-nav{position:absolute;top:50%;transform:translateY(-50%);width:56px;height:56px;min-width:56px}
.gallery-carousel .gallery-carousel-nav svg{width:22px;height:22px}
.gallery-carousel .gallery-carousel-nav.gallery-prev{left:8px}
.gallery-carousel .gallery-carousel-nav.gallery-next{right:8px}
@media (max-width:600px){
  .gallery-carousel{padding:0 36px}
  .gallery-carousel .gallery-carousel-nav{width:40px;height:40px;min-width:40px}
  .gallery-carousel .gallery-carousel-nav svg{width:18px;height:18px}
  .gallery-carousel .gallery-carousel-nav.gallery-prev{left:2px}
  .gallery-carousel .gallery-carousel-nav.gallery-next{right:2px}
}

/* -- lightbox: click-to-enlarge, independent of the carousel's own position -- */
.gallery-lightbox{position:fixed;inset:0;z-index:20000;background:rgba(0,0,0,.9);display:none;align-items:center;justify-content:center;padding:40px;box-sizing:border-box}
.gallery-lightbox.is-open{display:flex}
.gallery-lightbox-img-wrap{position:relative;width:100%;max-width:1000px}
.gallery-lightbox-img-wrap img{width:100%;height:auto;max-height:85vh;object-fit:contain;display:block;margin:0 auto}
.gallery-lightbox-close{position:fixed;top:20px;right:30px;z-index:10;font-size:40px;line-height:1;color:#fff;background:none;border:none;cursor:pointer}
.gallery-lightbox .gallery-carousel-nav{position:fixed;top:50%;transform:translateY(-50%);width:64px;height:64px;min-width:64px}
.gallery-lightbox .gallery-carousel-nav svg{width:28px;height:28px}
.gallery-lightbox .gallery-carousel-nav.gallery-prev{left:30px}
.gallery-lightbox .gallery-carousel-nav.gallery-next{right:30px}
@media (max-width:600px){
  .gallery-lightbox{padding:20px}
  .gallery-lightbox-close{top:10px;right:15px;font-size:32px}
  .gallery-lightbox .gallery-carousel-nav{width:44px;height:44px;min-width:44px}
  .gallery-lightbox .gallery-carousel-nav svg{width:20px;height:20px}
  .gallery-lightbox .gallery-carousel-nav.gallery-prev{left:8px}
  .gallery-lightbox .gallery-carousel-nav.gallery-next{right:8px}
}

/* ---------- reviews page ---------- */
.reviews-body{padding:64px 0}
.reviews-summary{margin-bottom:32px;font-size:1.2rem;font-weight:600;color:var(--black)}
.reviews-status{padding:40px 0;text-align:center;color:var(--muted)}
.reviews-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:20px}
.review-tile{margin:0;border-radius:16px;padding:24px;background:var(--panel);box-shadow:var(--shadow)}
.review-tile .stars{color:var(--gold);font-size:1.1rem;letter-spacing:.12em}
.review-text{margin:12px 0;color:var(--text);line-height:1.5}
.review-author{margin:0;font-weight:600;color:var(--black)}
