/* Shark Heavy Construction — site styles */
/* Inter 700/800/900 loaded deliberately — the eyebrow labels are heavy, and
   without real weights the browser synthesises faux-bold, which smears caps.
   900 is the heaviest weight the format supports; there is no "1400". */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@500;600;700;800&family=Inter:wght@400;500;600;700;800;900&display=swap');

:root{
  --navy:#040404;
  --navy-2:#161618;
  --amber:#0339D5;
  --amber-dark:#022BA8;
  --bg:#93969C;
  /* Brand blue lightened to the same hue (220°) for use on the near-black
     panels. The full-strength --amber only reaches ~2.2:1 there, which is why
     the hero and endorsements labels were hard to read. */
  --accent-on-dark:#5B90FF;
  --gray-light:#F5F6F7;
  --gray-border:#D9DDE1;
  /* Both blacked out for the dark background. --text-muted was #5C6670, which
     only reached 2.9:1 against the page and would have been far worse here.
     --text follows it to black so secondary copy can't end up darker than the
     body copy it sits under. Hierarchy now comes from size and weight. */
  --text:#000000;
  --text-muted:#000000;
  --white:#FFFFFF;
  --radius:6px;
}
*{box-sizing:border-box;margin:0;padding:0;}
/* Belt-and-suspenders against page-level horizontal scroll/drift on mobile.
   The infinite-scrolling .roller-track (home page "Our Work" and the
   Favorites gallery) is thousands of px wide by design; .roller's own
   overflow:hidden clips it visually, but combined with its mask-image that
   doesn't reliably stop the *document* from registering the extra width on
   phones — so the page itself became sideways-scrollable, and once dragged
   off-center there was nothing to snap it back. This guarantees the html/body
   scrollable area never exceeds the viewport width, regardless of which
   descendant is technically overwide. */
html{scroll-behavior:smooth;overflow-x:hidden;}
body{
  font-family:'Inter',sans-serif;
  color:var(--text);
  background:var(--bg);
  line-height:1.6;
  font-size:16px;
  overflow-x:hidden;
}
h1,h2,h3,h4{font-family:'Poppins',sans-serif;font-weight:700;line-height:1.2;color:var(--navy);}
/* h2 had no size of its own and fell back to the browser default of 24px,
   which left it smaller than the enlarged eyebrow labels sitting above it.
   Explicit responsive size so headings clearly lead their eyebrow again. */
h2{font-size:clamp(1.9rem,3.2vw,2.5rem);}
a{color:inherit;text-decoration:none;}
img{max-width:100%;display:block;}
/* z-index:1 keeps every piece of real content (text, cards, buttons, photos)
   painting above the tread-plate backdrop layers, which sit at z-index 0. */
.wrap{max-width:1180px;margin:0 auto;padding:0 24px;position:relative;z-index:1;}
.btn{
  display:inline-flex;align-items:center;gap:8px;
  padding:14px 28px;border-radius:var(--radius);
  font-weight:600;font-size:0.95rem;border:2px solid transparent;
  transition:transform .18s,box-shadow .18s,background-color .18s,color .18s;cursor:pointer;
}
.btn:hover{transform:translateY(-2px);box-shadow:0 10px 22px rgba(22,35,46,0.18);}
.btn-amber{background:var(--navy);color:var(--white);}
.btn-amber:hover{background:var(--amber);}
.btn-outline{border-color:var(--white);color:var(--white);}
.btn-outline:hover{background:var(--white);color:var(--navy);}
.btn-outline-dark{border-color:var(--navy);color:var(--navy);}
.btn-outline-dark:hover{background:var(--navy);color:var(--white);}

/* Header */
.site-header{background:var(--navy);position:sticky;top:0;z-index:100;transition:box-shadow .25s,padding .25s;}
.site-header.scrolled{box-shadow:0 4px 18px rgba(0,0,0,0.28);}
.nav{position:relative;display:flex;align-items:center;justify-content:space-between;padding:16px 24px;max-width:1180px;margin:0 auto;transition:padding .25s;}
.site-header.scrolled .nav{padding:10px 24px;}
.brand{display:flex;align-items:center;gap:10px;color:var(--white);font-family:'Poppins',sans-serif;font-weight:800;font-size:1.15rem;}
.brand .mark{width:38px;height:38px;border-radius:6px;object-fit:cover;}
/* gap trimmed from 28px when Customer Resources was added to the nav — at
   28px, "About Us"/"Contact Us"/"Get An Estimate" had no room left and the
   browser shrank them below their text width, wrapping mid-phrase. nowrap
   below means if space ever runs out again the row overflows visibly
   instead of silently wrapping like that. */
.nav-links{display:flex;gap:20px;list-style:none;}
.nav-links a{color:#C9D2DA;font-weight:500;font-size:0.93rem;white-space:nowrap;transition:color .15s;}
.nav-links a:hover,.nav-links a.active{color:var(--amber);}
/* Duplicate Resources entry for the hamburger dropdown — hidden except on
   true phone widths (see the max-width:540px block below), where it swaps
   places with the top-bar .nav-resources pill so the top bar stops
   overflowing (brand + Get An Estimate + Resources + hamburger no longer
   all fit side by side that narrow). */
.nav-links-resources{display:none;}
/* margin-left guarantees real separation from "Contact Us" — .nav's
   justify-content:space-between alone isn't reliable here: it splits
   whatever slack width is left across every item in the row, and that gap
   collapsed to 0px once Customer Resources took up more of the row. */
.nav-cta{background:var(--amber);color:var(--white);padding:10px 20px;border-radius:var(--radius);font-weight:600;font-size:0.9rem;white-space:nowrap;margin-left:24px;transition:transform .15s,background .15s;border:1px solid rgba(255,255,255,0.15);}
.nav-cta:hover{background:var(--amber-dark);transform:translateY(-2px);}
/* Customer Resources — sits immediately right of the CTA, not in the main
   nav-links list, so it stays visible even with the mobile menu collapsed.
   Label shortened to "Resources" (full name still in the title attribute
   and on the page itself) to keep its footprint small in this already-tight row. */
.nav-resources{
  display:flex;align-items:center;gap:6px;margin-left:8px;
  color:#C9D2DA;font-weight:600;font-size:0.85rem;white-space:nowrap;
  padding:8px 11px;border-radius:var(--radius);border:1px solid rgba(255,255,255,0.18);
  transition:color .15s,border-color .15s;
}
.nav-resources span{color:#F2B705;font-size:0.95rem;line-height:1;}
.nav-resources:hover,.nav-resources.active{color:var(--white);border-color:#F2B705;}
.menu-toggle{display:none;background:none;border:none;color:var(--white);font-size:1.6rem;cursor:pointer;}

/* Page hero (interior pages) */
/* Solid dark panels must clear the tread-plate layer, or the plate tiles over
   the black and muddies it. Any section with its own opaque background needs
   this — see also .testimonial and footer. */
.page-hero{background:var(--navy);color:var(--white);padding:64px 0;text-align:center;position:relative;z-index:1;}
.page-hero h1{color:var(--white);font-size:clamp(1.8rem,4vw,2.6rem);}
.page-hero p{color:#C9D2DA;margin-top:10px;}
.page-hero .gallery-warning{
  display:inline-block;background:#FFC800;font-weight:800;
  padding:10px 20px;border-radius:6px;margin:16px 0 4px;
  max-width:640px;
}
.page-hero .gallery-warning-text{color:#000;font-size:0.95rem;font-weight:800;margin:0;}
.page-hero .gallery-warning-copyright{color:#000;font-size:0.7rem;font-weight:600;margin:8px 0 0;opacity:.75;}

/* Home hero */
/* z-index:1 lifts the whole hero — photo, overlay and text — above the
   tread-plate backdrop. Without it the plate tiles over the hero photo,
   because .hero-bg sits at z-index:auto and the fixed fx layers come
   later in the DOM. */
.hero{
  position:relative;z-index:1;padding:60px 0 60px;color:var(--white);overflow:hidden;
  display:flex;min-height:939px;
}
/* Single hero photo tile that cycles through all three photos, crossfading
   in place (stacked, full-size layers) rather than showing all three at
   once. Cycling is JS-driven (assets/js/site.js) so the dots below can jump
   to a photo directly; this CSS only defines the crossfade transition and
   the active state. Each photo shows in full (uncropped, no stretching): a
   blurred oversized cover copy fills the frame, with the real uncropped
   photo layered on top. Hovering pauses only the crisp photo's zoom and the
   auto-advance — the blurred backdrop keeps moving regardless. */
.hero-photos{position:absolute;inset:0;}
.hero-photo-pair{position:absolute;inset:0;opacity:0;z-index:0;}
.hero-photo-pair.is-active{opacity:1;z-index:1;}
/* Venetian-blinds reveal: 8 solid slats sit over each photo, closed by
   default (scaleY:1). The instant a pair is promoted to .is-active (and to
   the top via z-index), its slats retract top-down with a per-slat stagger,
   opening to reveal the photo beneath. Plain transform/opacity only — no
   custom-property animation, which this environment doesn't reliably run. */
.hero-blinds{position:absolute;inset:0;display:flex;flex-direction:column;pointer-events:none;}
.hero-blinds span{flex:1;background:#040404;transform:scaleY(1);transform-origin:top;transition:transform 1s ease;}
.hero-photo-pair.is-active .hero-blinds span{transform:scaleY(0);}
.hero-blinds span:nth-child(1){transition-delay:0s;}
.hero-blinds span:nth-child(2){transition-delay:.1s;}
.hero-blinds span:nth-child(3){transition-delay:.2s;}
.hero-blinds span:nth-child(4){transition-delay:.3s;}
.hero-blinds span:nth-child(5){transition-delay:.4s;}
.hero-blinds span:nth-child(6){transition-delay:.5s;}
.hero-blinds span:nth-child(7){transition-delay:.6s;}
.hero-blinds span:nth-child(8){transition-delay:.7s;}
.hero-photo-blur{
  position:absolute;inset:0;background-size:cover;background-position:center;
  filter:blur(32px) brightness(.55) saturate(1.1);transform:scale(1.15);
  animation:heroZoom 24s ease-in-out infinite alternate;
}
.hero-photo{
  position:absolute;inset:0;background-size:contain;background-repeat:no-repeat;background-position:center;
  animation:heroZoom 20s ease-in-out infinite alternate;
}
.hero:hover .hero-photo{animation-play-state:paused;}
/* Small manual slide-selector dots, bottom-center of the photo layer, sitting
   in the hero's own bottom padding so they clear the button row above them. */
.hero-dots{
  position:absolute;left:50%;bottom:16px;transform:translateX(-50%);z-index:2;
  display:flex;gap:10px;
}
.hero-dot{
  width:10px;height:10px;border-radius:50%;padding:0;border:none;cursor:pointer;
  background:rgba(255,255,255,.4);transition:background .25s,transform .25s;
}
.hero-dot:hover{background:rgba(255,255,255,.75);}
.hero-dot.is-active{background:#fff;transform:scale(1.3);}
.hero-overlay{
  position:absolute;inset:0;
  background:none;
}
.hero .wrap{
  position:relative;z-index:1;text-align:center;width:100%;
  display:flex;flex-direction:column;align-items:center;
}
.hero h1,.hero p.lede{margin-left:auto;margin-right:auto;}
.hero .btn-row{justify-content:center;}
/* Heading, subtext and buttons are one evenly-spaced group filling the space
   below the eyebrow — the gap above the subtext equals the gap below it. */
.hero-lower-group{
  flex:1;width:100%;
  display:flex;flex-direction:column;align-items:center;justify-content:flex-end;
}
/* Heading + subtext slowly fade to transparent and back so the photo shows
   through, using the spark backdrop's white-to-blue palette: color tracks
   opacity directly (white at full visibility, logo-blue at zero), so the
   fade-out half reads white->blue and the fade-in half reads blue->white —
   the reverse of a spark's one-way white->blue lifetime fade. 8s total,
   matching the 8s-per-photo hero photo cycle so the two stay in step: 4s
   (50%) hold visible + 1s fade out + 2s hold invisible + 1s fade in. */
.hero-fade-cycle h1,.hero-fade-cycle .lede{animation:heroFadeCycle 8s ease-in-out 1.1s infinite;}
@keyframes heroFadeCycle{
  0%{opacity:1;color:#fff;}
  50%{opacity:1;color:#fff;}
  62.5%{opacity:0;color:#0339D5;}
  87.5%{opacity:0;color:#0339D5;}
  100%{opacity:1;color:#fff;}
}
@keyframes heroZoom{from{transform:scale(1);}to{transform:scale(1.09);}}
@media(prefers-reduced-motion:reduce){
  .hero-blinds span{transition:none;}
  .hero-photo-blur,.hero-photo{animation:none;}
  .hero-fade-cycle h1,.hero-fade-cycle .lede{animation:none;}
}
/* Mobile: the 939px min-height + "contain" photo below are tuned for wide
   desktop screens, where the blurred backdrop fills the letterboxed space
   around an uncropped portrait photo on purpose. On a narrow phone that same
   939px box (with the heading anchored to its bottom via .hero-lower-group)
   left a huge stretch of pure blur above the fold before any photo or text
   appeared — read by visitors as a broken/loading page. Below this width the
   crisp photo switches to "cover" (cropped, fills the frame) so the blur
   layer is fully hidden behind it, and the box shrinks to a normal mobile
   hero height instead of the desktop letterbox height. */
@media(max-width:768px){
  .hero{min-height:640px;padding:40px 0;}
  .hero-photo{background-size:cover;}
}
@media(max-width:480px){
  .hero{min-height:560px;}
}
/* Colour reverted to the original brand blue at the owner's request. Note this
   measures ~2.2:1 on the dark hero; the doubled size below offsets it somewhat
   but it stays below the 3:1 large-text threshold. --accent-on-dark is the
   lighter same-hue alternative if legibility ever needs to win. */
.eyebrow{color:#000;font-weight:900;letter-spacing:0.06em;text-transform:uppercase;font-size:1.7rem;margin-bottom:14px;display:block;}
/* Doubled size for the location line, requested on the home page only. A
   modifier (not a change to .eyebrow itself) since nothing else uses it. */
.eyebrow.eyebrow-lg{font-size:3.4rem;}
/* Full-width brand-blue bar behind the location line (owner picked this from
   6 mocked-up options). Background goes on the <section> itself, not .wrap,
   so it spans the full viewport while the text still centers inside .wrap. */
.eyebrow-bar{background:var(--amber);padding:36px 0;}
.eyebrow-bar .eyebrow{color:var(--white);margin-bottom:0;}
.hero h1{color:var(--white);font-size:clamp(2.1rem,5vw,3.4rem);max-width:760px;}
/* 'auto' side margins, not 0 — this rule comes after the centring block above
   and would otherwise win and knock the lede back to the left. */
.hero p.lede{color:#D7DEE4;font-size:1.1rem;max-width:520px;margin:22px auto 32px;}
.btn-row{display:flex;gap:14px;flex-wrap:wrap;}

section{padding:80px 0;}
/* Matched to the hero eyebrow's --amber so every eyebrow on the site is the
   same blue. This was a deeper navy (#001240) purely for contrast; consistency
   was chosen over that. At 26px/900 these count as large text, where the
   threshold is 3:1 rather than 4.5:1 — this sits just under it. */
.section-eyebrow{color:var(--amber);font-weight:900;text-transform:uppercase;letter-spacing:0.06em;font-size:1.64rem;margin-bottom:10px;display:block;}
/* Doubled size for "What We Do" / "Why SHC" / "Our Work" only — a modifier
   class so "Customer Endorsements" and "Why Choose Us" (also
   .section-eyebrow, further down this page) stay at the normal size. */
.section-eyebrow.eyebrow-lg{font-size:3.28rem;}
/* Centred by default so every section matches the "What We Do" treatment. */
.section-head{max-width:680px;margin:0 auto 48px;text-align:center;}
.section-head p{color:var(--text-muted);margin-top:14px;}
/* Bounded card for specific home-page headings that otherwise sit bare on
   the diamond-plate texture (unlike every other page, which keeps text off
   the bare plate). Background is translucent white, not opaque --gray-light
   — the plate still reads through, softened rather than fully masked (an
   opaque card read as "too clean"/a hard-edged box floating over the
   texture). Matches the site's own existing guidance elsewhere: pick
   something translucent, not opaque white. Scoped to body.page-home and
   opted into per element (not applied to every .section-head — the Customer
   Endorsements one further down sits on the dark testimonial section and is
   already high-contrast as-is). */
body.page-home .section-head-card{
  background:rgba(255,255,255,.7);border-radius:var(--radius);padding:32px 28px;
}
body.page-home .stats{background:rgba(255,255,255,.7);border-radius:var(--radius);}
/* Transparent so the diamond-plate background runs unbroken down the page.
   This used to paint --gray-light (#F5F6F7) as a subtle alternating tint back
   when the page was white; against the steel background it read as a large
   pale slab washing the plate out. Set a colour here again if section banding
   is ever wanted back — but pick something translucent, not opaque white. */
.bg-light{background:transparent;}

/* Feature cards */
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:28px;}
.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:24px;}
.card{background:var(--white);border:1px solid var(--gray-border);border-radius:var(--radius);padding:30px;transition:transform .2s,box-shadow .2s,border-color .2s;}
.card:hover{transform:translateY(-4px);box-shadow:0 16px 32px rgba(22,35,46,0.1);border-color:transparent;}
/* Holds an inline SVG rather than an emoji glyph. `color` here drives the
   icon's currentColor, so the whole mark recolours from one property. */
.card .icon{
  width:62px;height:62px;
  background:rgba(3,57,213,0.09);
  border:1px solid rgba(3,57,213,0.16);
  border-radius:16px;
  display:flex;align-items:center;justify-content:center;
  margin-bottom:18px;
  color:var(--amber);
  transition:background .2s,color .2s,transform .2s;
}
.card .icon svg{width:34px;height:34px;display:block;}
.card:hover .icon{background:var(--amber);color:#fff;transform:translateY(-2px);}
.card h3{font-size:1.1rem;margin-bottom:10px;}
.card p{color:var(--text-muted);font-size:0.95rem;}

/* Services tile grid (Services page) — huge title-first tiles, centered,
   semi-transparent so the full-page photo backdrop shows through. Bullets
   are hidden by default and only reveal via the explicit "+ Show Details"
   button (not hover) — growing the tile in place, not an absolute overlay,
   so the grid row reflows around whichever tile is open; align-items:start
   keeps that from stretching its still-collapsed neighbors to match. */
.service-tile-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:56px 44px;align-items:start;}
.service-tile{
  background:rgba(255,255,255,.5);border:1px solid var(--gray-border);border-radius:var(--radius);
  padding:34px 26px;text-align:center;
  transition:transform .3s ease,box-shadow .3s ease;
}
.service-tile:hover,.service-tile.is-open{
  transform:translateY(10px);
  box-shadow:0 24px 44px rgba(4,4,4,.22);
}
.service-tile h3{
  font-size:clamp(1.9rem,3.4vw,2.7rem);font-weight:800;color:var(--navy);
  line-height:1.05;letter-spacing:-0.01em;
}
.service-tile-toggle{
  display:inline-block;width:auto;margin-top:14px;padding:6px 16px;
  background:none;border:1px solid var(--navy);border-radius:20px;
  color:var(--navy);font-size:0.8rem;font-weight:700;cursor:pointer;
  transition:background .2s ease,color .2s ease;
}
.service-tile-toggle:hover{background:var(--navy);color:#fff;}
.service-tile-detail{max-height:0;overflow:hidden;transition:max-height .4s ease;}
.service-tile.is-open .service-tile-detail{max-height:690px;}
/* All detail text left-aligned (the tile/title above stays centered — this
   only touches what's inside .service-tile-detail). Each li is a flex row
   with align-items:center, so the logo is vertically centered against its
   text; ul's align-items:stretch makes every li span the same full width so
   every logo — and the text starting right after it — lines up at one
   consistent left edge instead of each row centering independently. */
.service-tile-detail .intro{color:var(--text-muted);font-size:0.92rem;line-height:1.5;margin:16px 0 10px;font-weight:700;text-align:left;}
.service-tile-detail p{color:var(--text-muted);font-size:0.92rem;line-height:1.55;margin:16px 0 0;font-weight:700;text-align:left;}
.service-tile-detail ul{
  display:flex;flex-direction:column;align-items:stretch;gap:10px;
  list-style:none;margin:16px 0 0;padding:0;text-align:left;
}
.service-tile-detail li{
  color:var(--text-muted);font-size:1.6rem;line-height:1.3;font-weight:700;
  display:flex;align-items:center;justify-content:flex-start;gap:10px;
  text-align:left;
}
.service-tile-detail .bullet-logo{width:26px;height:26px;border-radius:6px;flex-shrink:0;}

/* Services page: the equipment photo (content.json services.image, set via
   the inline style block in services.php since it's admin-editable) is the
   backdrop for the whole page, not just one band — fixed so it stays put
   as the tile grid scrolls over it. The page-hero's normal solid navy is
   turned transparent here so the photo shows through it too; the dark
   gradient baked into the same background-image keeps the white heading
   and hero text readable regardless of what part of the photo sits behind
   them. Switches to a plain scrolling background on phones — background-
   attachment:fixed is unreliable/janky on mobile Safari. */
body.page-services{background-size:cover;background-position:center;background-attachment:fixed;}
body.page-services .page-hero{background:transparent;}
@media(max-width:768px){body.page-services{background-attachment:scroll;}}

/* Gallery grid */
.gallery-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;}
/* Favorites page static grid — wider container so the 4-across photos render
   ~2x larger than the standard 1180px content width, without touching the
   shared .gallery-grid column/gap rules used by gallery.php. */
.favorites-grid-wrap{max-width:2270px;}
/* Favorites page captions scale up 2x to match the doubled photo size above. */
.favorites-grid-wrap .gallery-item .cap{padding:20px 24px;font-size:1.56rem;}
.gallery-item{position:relative;overflow:hidden;border-radius:var(--radius);aspect-ratio:1/1;}
.gallery-item img{width:100%;height:100%;object-fit:cover;transition:transform .3s;}
.gallery-item:hover img{transform:scale(1.06);}
.gallery-item .cap{position:absolute;left:0;right:0;bottom:0;padding:10px 12px;background:linear-gradient(0deg,rgba(0,0,0,0.7),transparent);color:#fff;font-size:0.78rem;font-weight:600;}
.job-group{margin-bottom:56px;}
.job-group h2{font-size:1.4rem;}
.job-meta{color:var(--text-muted);font-size:0.92rem;margin:6px 0 22px;}

/* Gallery category buttons */
.cat-grid{display:grid;grid-template-columns:1fr 1fr;gap:22px;}
.cat-btn{
  position:relative;display:block;overflow:hidden;border-radius:var(--radius);
  aspect-ratio:16/9;background:var(--navy);
}
.cat-mosaic{position:absolute;inset:0;display:grid;gap:2px;}
.cat-mosaic img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .5s ease;}
.cat-mosaic.n1{grid-template-columns:1fr;}
.cat-mosaic.n2{grid-template-columns:1fr 1fr;}
.cat-mosaic.n3{grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;}
.cat-mosaic.n3 img:first-child{grid-row:1 / span 2;}
.cat-mosaic.n4{grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;}
.cat-btn:hover .cat-mosaic img{transform:scale(1.06);}
.cat-tile-media{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .5s ease;}
.cat-btn:hover .cat-tile-media{transform:scale(1.06);}
.cat-overlay{position:absolute;inset:0;background:rgba(4,4,4,.4);transition:background .3s;}
.cat-btn:hover .cat-overlay{background:rgba(4,4,4,.55);}
.cat-title{
  position:absolute;left:50%;top:30%;transform:translate(-50%,-50%);
  color:#fff;font-family:'Poppins',sans-serif;font-weight:700;
  font-size:1.5rem;letter-spacing:.03em;text-transform:uppercase;
  text-align:center;text-shadow:0 2px 10px rgba(0,0,0,.6);white-space:nowrap;
}
.cat-btn.is-empty{opacity:.7;}
.cat-soon{
  position:absolute;left:50%;bottom:16px;transform:translateX(-50%);
  background:rgba(4,4,4,.7);color:#C9D2DA;font-size:.75rem;
  padding:4px 12px;border-radius:20px;letter-spacing:.02em;
}

/* Gallery category filtered view */
.cat-view{display:none;}
.cat-view.is-active{display:block;}
.cat-back{
  display:inline-flex;align-items:center;gap:6px;color:var(--amber);font-weight:600;
  font-size:.9rem;margin-bottom:18px;cursor:pointer;background:none;border:none;padding:0;
  font-family:inherit;
}
.cat-back:hover{text-decoration:underline;}
.cat-empty-msg{color:var(--text-muted);}

/* Testimonial */
.testimonial{background:var(--navy);color:var(--white);padding:70px 0;position:relative;z-index:1;}
.testimonial blockquote{font-family:'Poppins',sans-serif;font-size:clamp(1.2rem,2.4vw,1.6rem);max-width:820px;font-weight:600;line-height:1.4;}
.testimonial-who{display:flex;align-items:center;gap:14px;margin-top:28px;}
.testimonial-who img{width:50px;height:50px;border-radius:50%;object-fit:cover;}
.testimonial-who .role{color:#A9B4BD;font-size:0.88rem;}

/* Stats */
/* Also transparent — same reason as .bg-light. The plate shows through from
   the layer beneath; .stat children keep their own z-index so text stays above it. */
.stats{display:grid;grid-template-columns:repeat(3,1fr);background:transparent;position:relative;z-index:1;}
.stat{padding:50px 24px;text-align:center;border-right:1px solid var(--gray-border);position:relative;z-index:1;}
.stat:last-child{border-right:none;}
.stat .num{font-family:'Poppins',sans-serif;font-weight:800;font-size:2.6rem;color:var(--amber-dark);}
.stat .label{color:var(--text-muted);margin-top:6px;font-size:1.84rem;font-weight:700;}

/* Contact */
/* Call/Email/Hours — three uniformly-spaced columns side by side at the top
   of the hero (replaces the old side-by-side icon+text .contact-item
   layout). Text centers automatically under each title via .page-hero's own
   text-align:center; color/opacity is inherited from .page-hero/.page-hero p. */
.contact-hero-rows{display:grid;grid-template-columns:repeat(3,1fr);gap:32px;margin-top:28px;}
.contact-hero-row .ic{width:44px;height:44px;background:var(--gray-light);border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 10px;}
/* h4 defaults to the near-black heading color site-wide, which is unreadable
   on the hero's navy background — override to white like .page-hero h1. */
.contact-hero-row h4{color:var(--white);margin-bottom:4px;}
/* Below the hero: intro copy and the request form sit side by side as two
   columns (replaces the earlier stacked-and-centered version). align-items
   is `center` (not `start`) so the shorter text column doesn't pin to the
   top and leave empty space under it beside the taller form. */
.contact-lower{display:grid;grid-template-columns:1fr 1.1fr;gap:56px;align-items:center;max-width:1100px;margin:0 auto;}
/* Light card backdrop so the text reads clearly against the page's grey
   tread-plate background, matching the request form's own light panel. */
.contact-lower-text{text-align:center;background:var(--gray-light);border-radius:var(--radius);padding:32px;}
/* Contact page body copy — bold + 15% larger, everywhere on the page except
   the request-box form itself and the site header/footer. `body.page-contact`
   keys off the per-page body class from includes/header.php so this can't
   leak to other pages. Scoping the bold/size rules to .contact-lower-text
   keeps the sibling .contact-lower-form column untouched. */
body.page-contact .page-hero h1{font-size:clamp(2.07rem,4.6vw,2.99rem);}
body.page-contact .contact-hero-row{font-weight:700;}
body.page-contact .contact-hero-row h4,
body.page-contact .contact-hero-row p{font-size:1.09rem;}
body.page-contact .contact-lower-text>h3{font-weight:700;font-size:1.35rem;}
body.page-contact .contact-lower-text>p{font-weight:700;font-size:1.15rem;}
form.contact-form{display:grid;gap:14px;background:var(--gray-light);padding:32px;border-radius:var(--radius);}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:14px;}
input,textarea,select{width:100%;border:1px solid var(--gray-border);border-radius:var(--radius);padding:13px 14px;font-family:'Inter',sans-serif;font-size:0.95rem;background:var(--white);}
input:focus,textarea:focus,select:focus{outline:2px solid var(--amber);outline-offset:0;}
textarea{min-height:120px;resize:vertical;}

/* About */
.about-grid{display:grid;grid-template-columns:1fr 1fr;gap:56px;align-items:start;}
.about-grid img{border-radius:var(--radius);}
.about-grid h3{margin-top:22px;font-size:1.05rem;}
.about-grid p{color:var(--text-muted);margin-top:8px;}
.about-meta{display:flex;gap:28px;margin:18px 0 26px;}
.about-meta div span{display:block;}
.about-meta .num{font-family:'Poppins',sans-serif;font-weight:800;font-size:1.5rem;color:var(--navy);}
.about-meta .lbl{color:var(--text-muted);font-size:0.85rem;}

/* Footer */
footer{background:var(--navy);color:#C9D2DA;padding:60px 0 30px;position:relative;z-index:1;}
.footer-grid{display:grid;grid-template-columns:1.4fr 1fr 1fr;gap:44px;}
footer h4{color:var(--white);font-family:'Poppins',sans-serif;font-size:0.88rem;text-transform:uppercase;letter-spacing:0.06em;margin-bottom:16px;}
footer p{font-size:0.92rem;margin-bottom:8px;}
footer ul{list-style:none;}
footer ul li{margin-bottom:10px;}
footer ul a{font-size:0.92rem;}
footer ul a:hover{color:var(--amber);}
footer ul a.admin-link{font-size:0.46rem;color:#8892A0;}
footer ul a.admin-link:hover{color:var(--amber);}
.footer-bottom{margin-top:44px;padding-top:22px;border-top:1px solid rgba(255,255,255,0.12);display:flex;justify-content:space-between;flex-wrap:wrap;gap:10px;font-size:0.82rem;}

/* Own breakpoint, higher than the general 900px content one below — once
   Customer Resources joined "Get An Estimate" in the top bar, the full nav
   (brand + 7 links + CTA + Resources) stopped fitting until ~1070px, well
   above where photo grids etc. still have room to stay 2-up. Collapsing the
   links into the hamburger menu earlier keeps the top bar from overflowing
   in that in-between range. */
@media(max-width:1080px){
  .nav-links{display:none;flex-direction:column;gap:0;position:absolute;top:100%;left:0;right:0;background:var(--navy);padding:8px 24px 18px;box-shadow:0 12px 20px rgba(0,0,0,0.25);}
  .nav-links.open{display:flex;}
  .nav-links li{width:100%;}
  .nav-links a{display:block;padding:12px 0;border-top:1px solid rgba(255,255,255,0.08);}
  .menu-toggle{display:block;}
}
/* Phone widths only — brand + "Get An Estimate" + Resources + the hamburger
   button stop fitting in the top bar below here (measured overflow starting
   ~485px), so Resources moves into the hamburger dropdown instead. Even with
   Resources gone, brand + CTA + hamburger alone can still be too tight: the
   brand text is a flex item with the default min-width:auto, so instead of
   wrapping cleanly it can render past its shrunk box and get visually
   covered by the CTA button's background (reported as the button "covering"
   the header text). Shrinking the brand text/logo and the CTA's padding
   here frees enough width that nothing overlaps, down to a 320px-wide phone. */
@media(max-width:540px){
  .nav-resources{display:none;}
  .nav-links-resources{display:block;}
  .brand{font-size:0.95rem;gap:8px;}
  .brand .mark{width:32px;height:32px;}
  .nav-cta{padding:8px 14px;font-size:0.82rem;margin-left:12px;}
}
@media(max-width:900px){
  .grid-3,.grid-4{grid-template-columns:1fr 1fr;}
  .gallery-grid{grid-template-columns:1fr 1fr;}
  .about-grid{grid-template-columns:1fr;}
  .contact-hero-rows,.contact-lower{grid-template-columns:1fr;}
  .stats{grid-template-columns:1fr;}
  .stat{border-right:none;border-bottom:1px solid var(--gray-border);}
  .footer-grid{grid-template-columns:1fr;}
  .form-row{grid-template-columns:1fr;}
}

/* Lightbox (gallery.php / favorites.php photo grids) */
.lightbox-overlay{
  position:fixed;inset:0;background:rgba(10,16,20,0.92);z-index:1000;
  display:none;align-items:center;justify-content:center;flex-direction:column;
  padding:40px 20px;cursor:zoom-out;
}
.lightbox-overlay.open{display:flex;}
.lightbox-overlay .lightbox-img{max-width:min(90vw,1100px);max-height:78vh;object-fit:contain;border-radius:6px;box-shadow:0 20px 60px rgba(0,0,0,0.5);cursor:default;}
.lightbox-overlay .lightbox-cap{color:#D7DEE4;margin-top:16px;font-size:0.95rem;text-align:center;max-width:700px;}
.lightbox-close{
  position:absolute;top:22px;right:28px;background:none;border:none;color:#fff;
  font-size:2.2rem;line-height:1;cursor:pointer;opacity:0.8;
}
.lightbox-close:hover{opacity:1;}

/* Service photo tiles (home) */
.tile-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;}
.tile{
  position:relative;display:block;overflow:hidden;border-radius:var(--radius);
  aspect-ratio:4/3;background:var(--navy);
}
.tile img{width:100%;height:100%;object-fit:cover;transition:transform .5s ease;}
.tile:hover img{transform:scale(1.07);}
.tile .tile-label{
  position:absolute;inset:0;display:flex;align-items:flex-end;
  padding:22px;color:var(--white);
  background:linear-gradient(0deg,rgba(4,4,4,.82) 0%,rgba(4,4,4,.25) 45%,transparent 75%);
}
.tile .tile-label h3{
  color:var(--white);font-size:1.15rem;letter-spacing:.02em;
  text-transform:uppercase;transition:transform .3s ease;
}
.tile:hover .tile-label h3{transform:translateY(-4px);}

/* Rolling featured gallery (home) */
/* A mask fades the photos to transparent at both edges. The old approach
   painted a gradient the same colour as the section on top, which only works
   while that colour is known — a mask fades against whatever is behind it,
   including the tread plate. */
.roller{
  overflow:hidden;position:relative;z-index:1;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 14%,#000 86%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 14%,#000 86%,transparent 100%);
}
.roller-track{
  display:flex;gap:16px;width:max-content;
  will-change:transform;
  animation:rollerScroll 45s linear infinite;
}
.roller:hover .roller-track{animation-play-state:paused;}
.roller-item{width:280px;flex:0 0 auto;border-radius:var(--radius);overflow:hidden;aspect-ratio:4/3;background:#ddd;}
.roller-item img{width:100%;height:100%;object-fit:cover;}
/* The track holds the list twice, so -50% lands exactly on the seam. */
@keyframes rollerScroll{from{transform:translateX(0);}to{transform:translateX(-50%);}}
@media(prefers-reduced-motion:reduce){
  .roller-track{animation:none;}
  .roller{overflow-x:auto;}
}

/* Endorsement carousel (home) */
.review-carousel{position:relative;max-width:820px;margin:0 auto;text-align:center;}
.review-slide{display:none;}
.review-slide.is-active{display:block;}
.review-carousel .endorse-stars{font-size:1.3rem;color:var(--amber);letter-spacing:.12em;margin-bottom:18px;}
.review-carousel blockquote{
  font-family:'Poppins',sans-serif;font-size:clamp(1.05rem,2vw,1.35rem);
  font-weight:500;line-height:1.5;color:var(--white);
}
.review-carousel .review-who{margin-top:20px;color:#C9D2DA;font-size:.92rem;}
.review-carousel .review-who strong{color:var(--white);display:block;font-size:1rem;}
.review-nav{
  background:none;border:1px solid rgba(255,255,255,.3);color:var(--white);
  width:38px;height:38px;border-radius:50%;cursor:pointer;font-size:1rem;
  position:absolute;top:50%;transform:translateY(-50%);transition:background .2s,border-color .2s;
}
.review-nav:hover{background:rgba(255,255,255,.12);border-color:var(--white);}
.review-nav[data-review-nav=prev]{left:-8px;}
.review-nav[data-review-nav=next]{right:-8px;}

/* Endorsements page */
.endorse-wrap{max-width:820px;}
.endorse-cta{text-align:center;margin-bottom:40px;}
.endorse-cta.is-open{display:none;}
.endorse-thanks{
  background:#fff;border:1px solid var(--gray-border);border-left:4px solid var(--amber);
  border-radius:var(--radius);padding:32px;margin-bottom:40px;
}
.endorse-thanks h2{font-size:1.3rem;margin-bottom:14px;}
.endorse-thanks p{color:var(--text-muted);margin-bottom:12px;}
.endorse-sign{font-family:'Poppins',sans-serif;font-weight:600;color:var(--text) !important;margin-top:20px;}
.endorse-sign span{font-family:'Inter',sans-serif;font-weight:400;font-size:.88rem;color:var(--text-muted);}
.endorse-note{font-size:.85rem;color:var(--text-muted);margin-top:12px;}
.endorse-errors{
  background:#FBEAEA;border:1px solid #F0C2C2;color:#8A2222;
  padding:16px 20px;border-radius:var(--radius);margin-bottom:28px;
}
.endorse-errors ul{margin:8px 0 0 20px;font-size:.92rem;}

.endorse-form{
  display:none;background:#fff;border:1px solid var(--gray-border);
  border-radius:var(--radius);padding:32px;margin-bottom:48px;
}
.endorse-form.is-open{display:block;}
.endorse-form h2{font-size:1.25rem;margin-bottom:22px;}
.endorse-form h3{font-size:1.05rem;margin-bottom:6px;}
.endorse-form .field{margin-bottom:20px;}
.endorse-form label,.endorse-form .field-label{
  display:block;font-size:.9rem;font-weight:600;margin-bottom:8px;color:var(--text);
}
.endorse-form .req{color:#8A2222;}
.endorse-form .opt{font-weight:400;color:var(--text-muted);}
.choice-row{display:flex;gap:10px;flex-wrap:wrap;}
.choice{
  display:inline-flex;align-items:center;gap:8px;margin:0;font-weight:500 !important;
  border:1px solid var(--gray-border);border-radius:var(--radius);
  padding:10px 16px;cursor:pointer;transition:border-color .15s,background .15s;
}
.choice:hover{border-color:var(--amber);}
.choice input{width:auto;margin:0;}
.choice:has(input:checked){border-color:var(--amber);background:#EEF3FF;}

/* Star picker — laid out in reverse so CSS sibling selectors can fill leftward */
.star-pick{display:inline-flex;flex-direction:row-reverse;justify-content:flex-end;gap:4px;}
.star-pick input{position:absolute;opacity:0;width:0;height:0;}
.star-pick label{
  font-size:2rem;line-height:1;color:var(--gray-border);cursor:pointer;
  margin:0;transition:color .12s;
}
.star-pick input:checked ~ label,
.star-pick label:hover,
.star-pick label:hover ~ label{color:var(--amber);}
.star-pick input:focus-visible + label{outline:2px solid var(--amber);outline-offset:2px;}

.concern-block{
  border-top:1px solid var(--gray-border);margin-top:28px;padding-top:24px;
}
.concern-block.is-hidden,.contact-block.is-hidden{display:none;}
.concern-intro{font-size:.88rem;color:var(--text-muted);margin-bottom:18px;}
.contact-block{
  background:var(--gray-light);border-radius:var(--radius);padding:20px;margin-top:4px;
}
/* Honeypot: off-screen rather than display:none, which some bots skip */
.hp-field{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden;}

.endorse-list{display:grid;gap:20px;}
.endorse-card{
  background:#fff;border:1px solid var(--gray-border);border-radius:var(--radius);padding:26px;
}
.endorse-card .endorse-stars{color:var(--amber);letter-spacing:.1em;margin-bottom:10px;}
.endorse-card h3{font-size:1.05rem;margin-bottom:8px;}
.endorse-body{color:var(--text-muted);}
.endorse-extra{color:var(--text-muted);font-size:.92rem;margin-top:10px;font-style:italic;}
.endorse-meta{margin-top:16px;padding-top:14px;border-top:1px solid var(--gray-border);font-size:.9rem;}
.endorse-meta span{color:var(--text-muted);}
.endorse-empty{color:var(--text-muted);text-align:center;padding:30px 0;}

@media(max-width:900px){
  .tile-grid{grid-template-columns:1fr 1fr;}
  .service-tile-grid{grid-template-columns:1fr 1fr;}
}
@media(max-width:640px){
  .tile-grid{grid-template-columns:1fr;}
  .service-tile-grid{grid-template-columns:1fr;}
  .roller-item{width:220px;}
  .review-nav{display:none;}
  .cat-grid{grid-template-columns:1fr;}
  .cat-title{font-size:1.25rem;}
}

/* ---------------------------------------------------------------
   Interactive tread-plate backdrop
   ---------------------------------------------------------------
   Three fixed layers, all at z-index 0 and pointer-events:none, so they
   paint over flat section backgrounds but never over content (which is
   inside .wrap at z-index 1) and never intercept a click:
     .fx-plate   photographic diamond-plate texture
     .fx-sheen   slow diagonal light sweep — the "flowing" motion
     .fx-sparks  canvas of spark particles trailing the cursor / finger
   Sections with their own opaque background (.page-hero, .testimonial,
   .stats, footer, .hero) each carry z-index:1 so the plate never tints
   them. A cursor-following spotlight layer used to sit here too; it was
   removed because its glow pulled attention off the sparks. */
/* Vector diamond-plate tile — replaced the earlier photographic version so
   stud shape and density are exactly controllable instead of baked into a
   photo crop. Each stud is 3 stacked polygons (dark offset shadow, raised
   mid-tone body, bright offset highlight), 4 per tile in a pinwheel — the
   alternating rotation is what makes the pattern cross diagonally instead of
   reading as parallel rows. Verified by rasterizing this exact geometry
   before shipping it (not the shape actually used until confirmed on
   screen). Stud length/width were sized up once already to close gaps that
   read as sparse, then reduced 20% from that approved size on request —
   --fx-plate-size (tile scale / stud spacing) deliberately left unchanged. */
:root{
  --fx-plate-img:url("data:image/svg+xml,%3Csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20width=%2764%27%20height=%2764%27%3E%3Cg%20transform=%27translate(16,16)%20rotate(-35)%27%3E%3Cpolygon%20points=%270,-15.2%204.4,0%200,15.2%20-4.4,0%27%20fill=%27%23000%27%20opacity=%270.42%27%20transform=%27translate(1.2,1.4)%27/%3E%3Cpolygon%20points=%270,-13.984%204.048,0%200,13.984%20-4.048,0%27%20fill=%27%23fff%27%20opacity=%270.16%27/%3E%3Cpolygon%20points=%270,-10.944%201.848,0%200,10.944%20-1.848,0%27%20fill=%27%23fff%27%20opacity=%270.5%27%20transform=%27translate(-0.8,-1)%27/%3E%3C/g%3E%3Cg%20transform=%27translate(48,16)%20rotate(35)%27%3E%3Cpolygon%20points=%270,-15.2%204.4,0%200,15.2%20-4.4,0%27%20fill=%27%23000%27%20opacity=%270.42%27%20transform=%27translate(1.2,1.4)%27/%3E%3Cpolygon%20points=%270,-13.984%204.048,0%200,13.984%20-4.048,0%27%20fill=%27%23fff%27%20opacity=%270.16%27/%3E%3Cpolygon%20points=%270,-10.944%201.848,0%200,10.944%20-1.848,0%27%20fill=%27%23fff%27%20opacity=%270.5%27%20transform=%27translate(-0.8,-1)%27/%3E%3C/g%3E%3Cg%20transform=%27translate(48,48)%20rotate(-35)%27%3E%3Cpolygon%20points=%270,-15.2%204.4,0%200,15.2%20-4.4,0%27%20fill=%27%23000%27%20opacity=%270.42%27%20transform=%27translate(1.2,1.4)%27/%3E%3Cpolygon%20points=%270,-13.984%204.048,0%200,13.984%20-4.048,0%27%20fill=%27%23fff%27%20opacity=%270.16%27/%3E%3Cpolygon%20points=%270,-10.944%201.848,0%200,10.944%20-1.848,0%27%20fill=%27%23fff%27%20opacity=%270.5%27%20transform=%27translate(-0.8,-1)%27/%3E%3C/g%3E%3Cg%20transform=%27translate(16,48)%20rotate(35)%27%3E%3Cpolygon%20points=%270,-15.2%204.4,0%200,15.2%20-4.4,0%27%20fill=%27%23000%27%20opacity=%270.42%27%20transform=%27translate(1.2,1.4)%27/%3E%3Cpolygon%20points=%270,-13.984%204.048,0%200,13.984%20-4.048,0%27%20fill=%27%23fff%27%20opacity=%270.16%27/%3E%3Cpolygon%20points=%270,-10.944%201.848,0%200,10.944%20-1.848,0%27%20fill=%27%23fff%27%20opacity=%270.5%27%20transform=%27translate(-0.8,-1)%27/%3E%3C/g%3E%3C/svg%3E");
  --fx-plate-size:80px;
}
.fx-plate,.fx-sheen,.fx-sparks{
  position:fixed;inset:0;pointer-events:none;z-index:0;
}
.fx-plate{
  background-image:var(--fx-plate-img);
  background-size:var(--fx-plate-size) var(--fx-plate-size);
  /* Partial opacity lets --bg tint through, which is the knob for how dark
     the page reads. Raise for more metal, lower for more paper. */
  opacity:.68;
}
.fx-sheen{overflow:hidden;}
.fx-sheen::after{
  content:'';position:absolute;top:-60%;left:-60%;width:220%;height:220%;
  background:linear-gradient(115deg,
    transparent 38%,
    rgba(3,57,213,0.12) 46%,
    rgba(255,255,255,0.16) 50%,
    rgba(3,57,213,0.12) 54%,
    transparent 62%);
  will-change:transform;
  animation:fxSheen 18s ease-in-out infinite;
}
@keyframes fxSheen{
  0%{transform:translate3d(-12%,-12%,0);}
  50%{transform:translate3d(12%,12%,0);}
  100%{transform:translate3d(-12%,-12%,0);}
}
@media(prefers-reduced-motion:reduce){
  .fx-sheen::after{animation:none;}
}
/* The texture is decoration, not information — drop it on small screens
   where there's no cursor to drive it and every pixel counts. */
@media(max-width:640px){
  .fx-plate,.fx-sheen{opacity:.22;}
}
