/* ggr.css — GENERATED by build_css.py. DO NOT EDIT THIS FILE.
 * Edit a part in /root/ggr-scripts/css/ and re-run the script.
 * Parts, in cascade order:
 *   mockup_merged.css
 *   00-bridge.css
 *   10-contrast.css
 *   20-nav.css
 *   30-fixes.css
 *   40-container.css
 *   50-twocol.css
 *   60-elementor-widgets.css
 *   70-sgrid.css
 *   80-orphan-classes.css
 *   90-svc-icon-hover.css
 */


/* ==================== mockup_merged.css ==================== */
/* ============================================================
 * mockup_merged.css  -- GENERATED, do not edit by hand.
 * Source: the five client mockups in /root/ggr-scripts/mockups.
 * Rebuild with:  python3 /root/ggr-scripts/merge_css.py
 * Ownership: the first mockup FILE to define a selector owns it.
 * ============================================================ */

/* ---------- from home-page-mockup_27.html (218 selectors owned) ---------- */
:root{--navy:#0B2D4D;        
    --navy-band:#0C2E52;   
    --heading:#21295C;     
    --text:#7A7A7A;        
    --text-dark:#424240;   
    --link:#377190;        
    --blue2:#255A7F;       
    --blue-pale:#A2B3C1;   
    --light:#E5EBEF;       
    --light-btn:#E2EAEC;   
    --cred:rgba(162,179,193,.3);
    --line:#E6EAEE;}
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:'Roboto',sans-serif;color:var(--text);background:#DDE3E9;line-height:1.7;font-size:17px;}
.page{width:100%;background:#fff;overflow:hidden;}
.wrap{max-width:1140px;margin:0 auto;padding:0 20px;}
h1,h2,h3,h4{font-family:'Poppins',sans-serif;color:var(--heading);line-height:1.25;}
h1{font-size:44px;font-weight:700;}
h2{font-size:30px;font-weight:600;}
h3{font-size:22px;font-weight:600;}
h4{font-size:17px;font-weight:600;}
a{color:inherit;text-decoration:none;}
section{position:relative;padding:80px 0;}
.center{text-align:center;}
.center p{max-width:820px;margin-left:auto;margin-right:auto;}
p + p{margin-top:16px;}
.btn{display:inline-flex;align-items:center;justify-content:center;font-family:'Poppins',sans-serif;font-weight:500;font-size:15px;white-space:nowrap;
    padding:0 35px;height:52px;border-radius:15px;border:2px solid transparent;cursor:pointer;transition:.15s;}
.btn-navy{background:var(--navy);color:#fff;}
.btn-navy:hover{background:var(--blue2);}
.btn-light{background:var(--light-btn);color:var(--navy);}
.btn-light:hover{background:#fff;}
.btn-white{background:#fff;color:#000;}
.btn-outline{background:transparent;color:#fff;border-color:rgba(255,255,255,.7);}
.btn-outline:hover{background:#fff;color:var(--navy);}
.btn-outline-navy{background:#fff;color:var(--navy);border-color:var(--navy);}
.btn-outline-navy:hover{background:var(--navy);color:#fff;}
.row-btn{display:flex;gap:14px;flex-wrap:wrap;}
.wf-label{position:absolute;top:10px;left:10px;background:#111;color:#BFD8F0;font:600 10px/1.4 'Roboto',sans-serif;letter-spacing:.08em;text-transform:uppercase;padding:5px 9px;border-radius:4px;z-index:6;opacity:.85;max-width:70%;}
.mob-note{position:absolute;top:10px;right:10px;background:#0B2D4D;color:#CFE0F0;font:600 10px/1.4 'Roboto',sans-serif;letter-spacing:.06em;text-transform:uppercase;padding:5px 9px;border-radius:4px;z-index:6;opacity:.9;}
.ph-img{position:relative;border:2px dashed var(--link);border-radius:6px;
    background:repeating-linear-gradient(45deg,#EEF2F5,#EEF2F5 9px,#E3E9EE 9px,#E3E9EE 18px);
    display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;
    padding:22px;color:#5A6B7A;font-size:13.5px;min-height:200px;}
.ph-img b{display:block;font-family:'Poppins',sans-serif;font-weight:600;font-size:14px;color:var(--navy);margin-bottom:4px;}
.ph-img .dim{font-size:11.5px;color:#8A98A5;margin-top:8px;letter-spacing:.04em;}
.ph-img::before{content:'Photo placeholder';position:absolute;top:-11px;left:14px;background:var(--link);color:#fff;font:600 9.5px/1 'Roboto',sans-serif;letter-spacing:.1em;text-transform:uppercase;padding:5px 8px;border-radius:3px;}
.real-img{width:100%;height:100%;object-fit:cover;display:block;}
header.nav{display:flex;align-items:center;justify-content:space-between;padding:10px 40px;background:#fff;position:sticky;top:0;z-index:20;gap:20px;box-shadow:0 1px 0 var(--line);}
.logo img{height:80px;width:auto;display:block;}
nav ul{display:flex;gap:30px;list-style:none;font-family:'Poppins',sans-serif;font-size:17px;font-weight:400;color:var(--heading);align-items:center;}
nav li{white-space:nowrap;cursor:pointer;}
nav li.active{font-weight:600;}
nav li.call{font-weight:600;}
.hero{position:relative;overflow:hidden;padding:0;min-height:760px;display:flex;align-items:center;
    background:none center 60%/cover no-repeat var(--navy);}
.hero::before{content:'';position:absolute;inset:0;z-index:1;background:linear-gradient(90deg,rgba(11,45,77,.78) 0%,rgba(11,45,77,.55) 40%,rgba(11,45,77,.05) 75%);}
.hero .wrap{position:relative;z-index:2;width:100%;}
.hero-copy{max-width:560px;}
.hero h1{color:#fff;margin-bottom:14px;text-shadow:0 2px 18px rgba(0,0,0,.35);}
.hero h3{color:#fff;font-weight:500;font-size:22px;margin-bottom:28px;text-shadow:0 1px 12px rgba(0,0,0,.35);}
.hero-sub{display:flex;gap:26px;flex-wrap:wrap;margin-top:34px;padding-top:18px;border-top:1px solid rgba(255,255,255,.35);color:#fff;font-family:'Poppins',sans-serif;font-size:13.5px;}
.hero-sub span::before{content:'\2713';margin-right:8px;font-weight:700;}
.eyebrow{display:block;font-family:'Roboto',sans-serif;font-size:13px;letter-spacing:.14em;text-transform:uppercase;color:var(--link);margin-bottom:10px;}
.svc-head{display:grid;grid-template-columns:1fr 1.1fr;gap:60px;align-items:center;}
.svc-head h2{font-size:38px;line-height:1.2;}
.svc-head p{font-size:16px;}
.svc-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:0;margin-top:56px;}
.svc{display:block;position:relative;padding:44px 36px 40px;border-radius:40px 8px 40px 8px;background:transparent;transition:background .25s ease,color .25s ease,transform .25s ease,box-shadow .25s ease;cursor:pointer;}
.svc + .svc::before{content:'';position:absolute;left:0;top:40px;bottom:40px;width:1px;background:var(--line);transition:opacity .2s;}
.svc img.ic{width:56px;height:56px;display:block;margin-bottom:26px;transition:filter .25s;}
.svc h3{margin-bottom:16px;font-size:22px;line-height:1.25;transition:color .25s;}
.svc p{font-family:'Poppins',sans-serif;color:var(--text-dark);font-size:14.5px;line-height:1.75;transition:color .25s;}
.svc .more{display:inline-flex;align-items:center;gap:8px;margin-top:22px;color:var(--link);font-family:'Poppins',sans-serif;font-weight:500;font-size:14px;transition:color .25s;}
.svc .more i{font-style:normal;width:22px;height:22px;border-radius:50%;background:var(--link);color:#fff;display:inline-flex;align-items:center;justify-content:center;font-size:12px;transition:.25s;}
.svc:hover{background:var(--blue2);transform:translateY(-6px);box-shadow:0 24px 50px rgba(11,45,77,.25);z-index:2;}
.svc:hover::before,.svc:hover + .svc::before{opacity:0;}
.svc:hover img.ic{filter:brightness(0) invert(1);}
.svc:hover h3,.svc:hover p,.svc:hover .more{color:#fff;}
.svc:hover .more i{background:#fff;color:var(--blue2);}
.svc-cta{margin-top:56px;text-align:center;font-family:'Poppins',sans-serif;color:var(--text-dark);font-size:18px;}
.svc-cta b{color:var(--heading);font-weight:600;}
.fin{background:linear-gradient(90deg,var(--navy-band),var(--blue2));padding:64px 0;text-align:center;}
.fin h2{color:#fff;margin-bottom:14px;}
.fin p{color:#C9D6E2;max-width:640px;margin:0 auto 26px;}
.fin-grid{display:grid;grid-template-columns:1.1fr .9fr;gap:50px;align-items:center;text-align:left;}
.fin-grid h2{text-align:left;}
.fin-grid p{margin:0 0 18px;max-width:none;}
.fin-list{list-style:none;margin:0 0 26px;display:grid;gap:8px;}
.fin-list li{color:#fff;font-family:'Poppins',sans-serif;font-size:15px;padding-left:26px;position:relative;}
.fin-list li::before{content:'\2713';position:absolute;left:0;color:var(--light-btn);font-weight:700;}
.fin-fine{display:block;margin-top:12px;font-size:12.5px;color:#9FB3C6;}
.fin-img{background:#fff;border-radius:6px;padding:10px;box-shadow:0 18px 40px rgba(0,0,0,.25);}
.fin-img img{width:100%;height:auto;display:block;border-radius:4px;}
.map{position:relative;border-radius:6px;overflow:hidden;box-shadow:0 12px 30px rgba(11,45,77,.14);background:#fff;min-height:460px;}
.map iframe{width:100%;height:460px;border:0;display:block;}
.map-note{position:absolute;left:12px;bottom:12px;right:12px;background:rgba(11,45,77,.9);color:#fff;font-size:12px;padding:8px 12px;border-radius:4px;}
body.client-view .map-note{display:none;}
.light{background:var(--light);}
.g-cols{display:grid;grid-template-columns:repeat(3,1fr);gap:40px;margin-top:54px;text-align:center;}
.g-col img{width:130px;height:130px;border-radius:50%;object-fit:cover;background:#fff;border:3px solid var(--blue2);margin:0 auto 20px;display:block;box-shadow:0 8px 20px rgba(11,45,77,.12);}
.g-col h3{font-size:20px;margin-bottom:10px;}
.g-col p{font-family:'Poppins',sans-serif;color:var(--text-dark);font-size:15.5px;line-height:1.7;}
.gallery{background:var(--blue2);padding:100px 0;overflow:hidden;position:relative;color:#fff;}
.gallery::before{content:'';position:absolute;inset:0;background:none center/cover no-repeat;opacity:.18;}
.gallery::after{content:'';position:absolute;inset:0;background:linear-gradient(180deg,rgba(37,90,127,.55),rgba(11,45,77,.9));}
.gallery .wrap,.gallery .strip{position:relative;z-index:2;}
.gallery h2{color:#fff;font-size:46px;line-height:1.2;font-weight:600;}
.gallery h2 span{display:block;font-weight:400;color:#C9D6E2;}
.strip{display:flex;gap:30px;margin:48px 0 44px;padding:0 20px;width:max-content;animation:slide 40s linear infinite;}
.strip:hover{animation-play-state:paused;}
@keyframes slide{from{transform:translateX(0);}to{transform:translateX(-50%);}}
.strip .shot{width:270px;height:377px;flex:none;overflow:hidden;background:#123D66;border:1px solid rgba(255,255,255,.12);}
.strip .shot .ph-img{border-radius:0;min-height:377px;border-color:rgba(255,255,255,.45);background:repeating-linear-gradient(45deg,#163F68,#163F68 9px,#123659 9px,#123659 18px);color:#C9D6E2;}
.strip .shot .ph-img b{color:#fff;}
.strip .shot .ph-img::before{display:none;}
.gallery .row-btn{justify-content:center;}
.rev-slider{position:relative;max-width:860px;margin:40px auto 0;padding:0 70px;}
.rev-track{position:relative;min-height:280px;}
.rev{position:absolute;inset:0;opacity:0;visibility:hidden;transition:opacity .5s ease;border:1px solid var(--line);border-radius:6px;padding:40px 44px;text-align:center;background:#fff;}
.rev.active{opacity:1;visibility:visible;position:relative;}
.rev .stars{color:#F2B01E;letter-spacing:3px;font-size:20px;margin-bottom:16px;}
.rev p{font-size:19px;line-height:1.7;color:#4E5B68;}
.rev-arrow{position:absolute;top:50%;transform:translateY(-50%);width:48px;height:48px;border-radius:50%;border:1px solid var(--line);background:#fff;color:var(--navy);font-size:30px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:.15s;}
.rev-arrow:hover{background:var(--blue2);color:#fff;}
.rev-arrow.prev{left:0;}
.rev-arrow.next{right:0;}
.rev-dots{display:flex;justify-content:center;gap:8px;margin-top:22px;}
.rev-dots span{width:9px;height:9px;border-radius:50%;background:#C9D6E2;cursor:pointer;transition:.2s;}
.rev-dots span.active{background:var(--blue2);width:26px;border-radius:5px;}
.rev b{display:block;margin-top:16px;font-family:'Poppins',sans-serif;color:var(--heading);font-size:15px;}
.rev span{font-size:13px;}
.rating{margin-top:10px;font-family:'Poppins',sans-serif;color:var(--heading);font-weight:500;}
.rating i{color:#F2B01E;font-style:normal;letter-spacing:2px;}
.serve{display:grid;grid-template-columns:1fr 1fr;gap:50px;align-items:center;}
.serve h2{text-align:left;}
.serve .cities{display:grid;grid-template-columns:1fr 1fr;gap:6px 24px;margin-top:22px;}
.serve .cities div{font-family:'Poppins',sans-serif;font-weight:500;color:var(--heading);font-size:17px;padding:8px 0;border-bottom:1px solid #D5DEE5;}
.serve .cities div::before{content:'';display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--blue2);margin-right:12px;vertical-align:middle;}
.faq-wrap{max-width:860px;margin:40px auto 0;}
.faq{background:#fff;border:1px solid var(--line);border-radius:6px;margin-bottom:12px;overflow:hidden;}
.faq h3{font-size:18px;display:flex;justify-content:space-between;align-items:center;gap:20px;cursor:pointer;padding:18px 22px;}
.faq h3 span{width:28px;height:28px;border-radius:50%;background:var(--blue2);color:#fff;display:flex;align-items:center;justify-content:center;font-size:18px;flex:none;transition:.2s;}
.faq.open h3 span{transform:rotate(45deg);}
.faq p{display:none;padding:0 22px 20px;font-size:16px;}
.faq.open p{display:block;}
.cred{background:var(--cred);padding:56px 0;text-align:center;}
.cred-row{display:flex;justify-content:center;align-items:center;gap:40px;flex-wrap:wrap;margin-top:28px;}
.cred-row img{height:110px;width:auto;}
.cred-ph{height:96px;width:170px;border:2px dashed var(--link);border-radius:6px;font-size:12px;font-weight:600;color:var(--link);display:flex;align-items:center;justify-content:center;text-align:center;line-height:1.3;padding:0 12px;background:#fff;}
.cta{background:#fff;}
.cta-grid{display:grid;grid-template-columns:1fr 1fr;gap:60px;align-items:center;}
.cta-grid h2{margin-bottom:12px;}
.cta-info{margin-top:22px;font-family:'Poppins',sans-serif;color:var(--text-dark);font-size:16px;line-height:1.9;}
.cta-info b{color:var(--heading);font-weight:600;}
.lead-form{background:var(--light);border-radius:6px;padding:34px 32px;}
.lead-form label{display:block;font-family:'Poppins',sans-serif;font-size:13px;font-weight:500;color:var(--heading);margin-bottom:6px;}
.lead-form .fld{margin-bottom:14px;}
.lead-form .two{display:grid;grid-template-columns:1fr 1fr;gap:14px;}
.lead-form input,.lead-form select{width:100%;border:1px solid #CFD8E0;border-radius:6px;padding:12px 14px;font-family:'Roboto',sans-serif;font-size:15px;color:#333;background:#fff;}
.lead-form .btn{width:100%;margin-top:6px;}
footer.base{background:var(--navy);color:#fff;position:relative;padding:150px 0 0;margin-top:70px;}
.f-logos{position:absolute;top:-46px;right:0;left:50%;background:#fff;border-radius:115px 0 0 115px;height:92px;padding:15px 20px 15px 46px;display:flex;align-items:center;gap:28px;box-shadow:0 12px 30px rgba(0,0,0,.18);z-index:2;}
.f-logos img{height:60px;width:auto;}
.f-logos .cred-ph{height:56px;width:130px;background:#fff;font-size:10.5px;}
.f-logos .lbl{position:absolute;left:46px;top:-24px;font:600 10px/1 'Roboto',sans-serif;letter-spacing:.1em;text-transform:uppercase;color:#7F94AA;}
.f-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr 1.2fr;gap:36px;padding-bottom:140px;}
footer h4{color:#fff;font-size:17px;margin-bottom:16px;}
footer ul{list-style:none;font-size:16px;line-height:2;}
footer a{color:#fff;}
footer p{color:#C9D6E2;font-size:15px;}
.f-logo{height:90px;width:auto;display:block;margin-bottom:14px;}
.f-truck{position:absolute;right:0;bottom:42px;width:350px;height:111px;z-index:1;}
.f-truck .ph-img{min-height:111px;border-radius:0;border-color:rgba(255,255,255,.4);background:repeating-linear-gradient(45deg,#123D66,#123D66 9px,#0F3459 9px,#0F3459 18px);color:#C9D6E2;padding:10px;}
.f-truck .ph-img b{color:#fff;font-size:12px;}
.f-truck .ph-img .dim{font-size:10px;margin-top:2px;}
.f-truck .ph-img::before{display:none;}
.f-copy{background:#363636;padding:10px 0;font-size:12px;font-family:'Poppins',sans-serif;text-align:center;position:relative;z-index:2;}
.f-copy a{color:#fff;}
.callbar{display:none;}
.notes{background:#0A1420;color:#C6D1DC;padding:46px 40px;font-size:14px;}
.notes h3{color:#BFD8F0;font-size:15px;letter-spacing:.1em;text-transform:uppercase;margin-bottom:16px;}
.notes ul{margin:0 0 22px 20px;line-height:1.9;}
.notes b{color:#fff;}
.notes .flag{background:rgba(28,114,147,.18);border-left:3px solid var(--link);padding:14px 18px;border-radius:0 8px 8px 0;margin-bottom:22px;}
body.client-view .wf-label,body.client-view .mob-note,body.client-view .notes{display:none;}
.notes-toggle{position:fixed;right:20px;bottom:20px;z-index:50;background:#14212E;color:#fff;font-family:'Roboto',sans-serif;font-weight:600;font-size:12.5px;padding:11px 18px;border-radius:100px;box-shadow:0 10px 24px rgba(0,0,0,.28);cursor:pointer;border:1px solid rgba(255,255,255,.15);}
@media print{
  .notes-toggle{display:none;}
}
@media(max-width:980px){
  section{padding:56px 0;}
  h1{font-size:32px;}
  h2{font-size:26px;}
  header.nav{padding:8px 20px;}
  .logo img{height:60px;}
  nav ul{display:none;}
  .hero{min-height:560px;background-position:65% center;}
  .hero h3{font-size:18px;}
  .svc-grid,.svc-head,.g-cols,.steps,.serve,.cta-grid,.fin-grid{grid-template-columns:1fr;}
  .svc-head{gap:20px;}
  .svc-head h2{font-size:28px;}
  .svc{padding:30px 24px;}
  .svc + .svc::before{display:none;}
  .rev-slider{padding:0;}
  .rev{padding:28px 22px;}
  .rev p{font-size:16.5px;}
  .rev-arrow{top:auto;bottom:-6px;transform:none;}
  .rev-arrow.prev{left:calc(50% - 60px);}
  .rev-arrow.next{right:calc(50% - 60px);}
  .rev-dots{margin-top:70px;}
  .map iframe{height:320px;}
  .map{min-height:320px;}
  .gallery h2{font-size:32px;}
  .strip .shot{width:200px;height:280px;}
  .strip .shot .ph-img{min-height:280px;}
  .f-grid{grid-template-columns:1fr 1fr;}
  .f-logos{left:20px;border-radius:60px;padding:12px 16px;height:auto;gap:14px;flex-wrap:wrap;justify-content:center;top:-40px;}
  .f-logos .lbl{display:none;}
  .f-logos img{height:40px;}
  .f-logos .cred-ph{height:40px;width:100px;}
  .f-truck{display:none;}
  footer.base{padding-top:120px;}
  .lead-form .two{grid-template-columns:1fr;}
  .callbar{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:40;background:var(--navy);color:#fff;font-family:'Poppins',sans-serif;font-weight:600;font-size:15px;justify-content:center;align-items:center;padding:14px;box-shadow:0 -8px 24px rgba(0,0,0,.2);}
  .notes-toggle{bottom:70px;}
}

/* ---------- from services-page-mockup_6.html (29 selectors owned) ---------- */
.pg-title{background:linear-gradient(90deg,var(--navy),var(--blue2));padding:56px 0;}
.pg-title .crumb{font-family:'Poppins',sans-serif;font-size:13px;color:#C9D6E2;margin-bottom:10px;}
.pg-title .crumb b{color:#fff;font-weight:500;}
.pg-title h1{color:#fff;}
.two-col{display:grid;grid-template-columns:1fr 1fr;gap:60px;align-items:center;}
.two-col.flip > .media{order:-1;}
.two-col h2{margin-bottom:16px;}
.two-col p{font-size:16.5px;}
.two-col .media{border-radius:40px 8px 40px 8px;overflow:hidden;box-shadow:0 18px 40px rgba(11,45,77,.16);min-height:380px;}
.two-col .media img{width:100%;height:100%;min-height:380px;object-fit:cover;display:block;}
.two-col .media .ph-img{border-radius:0;border:none;min-height:380px;}
.two-col .media .ph-img::before{display:none;}
.pull{border-left:4px solid var(--blue2);padding:8px 0 8px 22px;margin-top:22px;font-family:'Poppins',sans-serif;font-size:19px;font-weight:500;color:var(--heading);line-height:1.45;}
.stat-row{display:flex;gap:36px;flex-wrap:wrap;margin-top:28px;padding-top:22px;border-top:1px solid var(--line);}
.stat b{display:block;font-family:'Poppins',sans-serif;font-size:32px;font-weight:700;color:var(--blue2);line-height:1;}
.stat span{font-size:13px;color:var(--text);}
.svc-block .ic{width:56px;height:56px;display:block;margin-bottom:18px;}
.svc-block h2{margin-bottom:14px;}
.svc-list{list-style:none;margin-top:20px;display:grid;gap:10px;}
.svc-list li{position:relative;padding-left:32px;font-family:'Poppins',sans-serif;font-weight:500;color:var(--heading);font-size:16px;}
.svc-list li::before{content:'\2713';position:absolute;left:0;top:0;width:22px;height:22px;border-radius:50%;background:var(--blue2);color:#fff;font-size:12px;display:flex;align-items:center;justify-content:center;}
.svc-block .row-btn{margin-top:26px;}
.soft{background:var(--light-btn);}
.cta-band{background:linear-gradient(90deg,var(--navy),var(--blue2));text-align:center;padding:64px 0;}
.cta-band h3{color:#fff;font-size:26px;max-width:760px;margin:0 auto 26px;font-weight:600;}
@media(max-width:980px){
  .two-col{grid-template-columns:1fr;gap:28px;}
  .two-col.flip > .media{order:0;}
  .two-col .media,.two-col .media img{min-height:240px;}
}

/* ---------- from residential-roofing-page-mockup_2.html (23 selectors owned) ---------- */
.inc-grid{display:grid;grid-template-columns:1fr 1fr;gap:28px;margin-top:44px;}
.inc{display:block;position:relative;padding:38px 34px;border-radius:40px 8px 40px 8px;background:#fff;border:1px solid var(--line);transition:background .25s,transform .25s,box-shadow .25s;}
.inc h3{margin-bottom:10px;font-size:22px;transition:color .25s;}
.inc p{font-family:'Poppins',sans-serif;color:var(--text-dark);font-size:15px;line-height:1.7;transition:color .25s;}
.inc ul{list-style:none;margin-top:16px;display:grid;gap:8px;}
.inc li{position:relative;padding-left:26px;font-family:'Poppins',sans-serif;font-size:14.5px;color:var(--heading);transition:color .25s;}
.inc li::before{content:'\2713';position:absolute;left:0;top:0;color:var(--blue2);font-weight:700;transition:color .25s;}
.inc .tag{display:inline-block;font-family:'Roboto',sans-serif;font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--link);margin-bottom:12px;transition:color .25s;}
.inc:hover{background:var(--blue2);border-color:var(--blue2);transform:translateY(-6px);box-shadow:0 24px 50px rgba(11,45,77,.25);}
.inc:hover h3,.inc:hover p,.inc:hover li,.inc:hover li::before,.inc:hover .tag{color:#fff;}
.signs{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin-top:40px;}
.sign{background:#fff;border-radius:6px;padding:26px 24px;border-left:4px solid var(--blue2);border-top:1px solid var(--line);border-right:1px solid var(--line);border-bottom:1px solid var(--line);transition:background .25s,transform .25s,box-shadow .25s,border-color .25s;cursor:default;}
.sign h4{font-size:16px;margin-bottom:6px;transition:color .25s;}
.sign p{font-size:14.5px;transition:color .25s;}
.sign:hover{background:var(--blue2);border-color:var(--navy);transform:translateY(-4px);box-shadow:0 18px 40px rgba(11,45,77,.22);}
.sign:hover h4,.sign:hover p{color:#fff;}
@media(max-width:980px){
  .inc-grid,.signs{grid-template-columns:1fr;gap:28px;}
}

/* ---------- from about-page-mockup_5.html (26 selectors owned) ---------- */
.team-grid{display:grid;grid-template-columns:1fr 1fr;gap:30px;margin-top:48px;}
.team{background:#fff;border-radius:40px 8px 40px 8px;overflow:hidden;display:grid;grid-template-columns:.8fr 1.2fr;box-shadow:0 12px 30px rgba(11,45,77,.10);}
.team .ph-img{border-radius:0;border:none;min-height:100%;}
.team .ph-img::before{display:none;}
.team-copy{padding:30px 30px;}
.team-copy .role{display:block;font-family:'Roboto',sans-serif;font-size:12.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--link);margin:4px 0 12px;}
.team-copy p{font-family:'Poppins',sans-serif;color:var(--text-dark);font-size:14.5px;}
.diff{display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-top:44px;}
.diff-col{border-radius:40px 8px 40px 8px;padding:36px 34px;}
.diff-col.them{background:#fff;border:1px solid var(--line);}
.diff-col.us{background:var(--blue2);color:#fff;}
.diff-col h3{margin-bottom:16px;}
.diff-col.us h3{color:#fff;}
.diff-col ul{list-style:none;display:grid;gap:10px;}
.diff-col li{position:relative;padding-left:28px;font-family:'Poppins',sans-serif;font-size:15px;line-height:1.55;}
.diff-col.them li{color:var(--text-dark);}
.diff-col.them li::before{content:'\2715';position:absolute;left:0;top:0;color:#B23A3A;font-weight:700;}
.diff-col.us li::before{content:'\2713';position:absolute;left:0;top:0;color:#fff;font-weight:700;}
.band-soft{background:var(--light-btn);text-align:center;padding:70px 0;}
.band-soft p{max-width:820px;margin:0 auto 14px;font-size:17px;}
.band-soft .lead{font-family:'Poppins',sans-serif;font-size:22px;font-weight:600;color:var(--heading);margin:18px auto 26px;}
@media(max-width:980px){
  .team-grid,.diff{grid-template-columns:1fr;gap:28px;}
  .two-col .media .ph-img{min-height:240px;}
  .team{grid-template-columns:1fr;}
  .team .ph-img{min-height:220px;}
}

/* ---------- from contact-page-mockup_5.html (36 selectors owned) ---------- */
.intro-grid{display:grid;grid-template-columns:1.1fr .9fr;gap:56px;align-items:center;}
.contact-copy h2{font-size:34px;line-height:1.2;margin-bottom:6px;}
.contact-copy h3{font-weight:500;color:var(--blue2);margin-bottom:18px;}
.contact-copy p{font-size:16.5px;}
.c-list{list-style:none;display:grid;gap:12px;}
.c-list.row{grid-template-columns:repeat(4,1fr);gap:20px;margin-top:44px;}
.c-list li{display:flex;gap:14px;align-items:flex-start;background:#fff;border:1px solid var(--line);border-left:4px solid var(--blue2);border-radius:6px;padding:18px;transition:background .25s,transform .25s,box-shadow .25s;}
.c-list li:hover{background:var(--blue2);transform:translateY(-3px);box-shadow:0 14px 30px rgba(11,45,77,.2);}
.c-list li:hover b,.c-list li:hover span,.c-list li:hover a{color:#fff;}
.c-list .ic{width:40px;height:40px;border-radius:50%;background:var(--light);display:flex;align-items:center;justify-content:center;flex:none;}
.c-list b{display:block;font-family:'Poppins',sans-serif;color:var(--heading);font-size:15px;transition:color .25s;}
.c-list span,.c-list a{display:block;font-size:14px;color:var(--text);transition:color .25s;line-height:1.5;}
.c-list .big{font-family:'Poppins',sans-serif;font-weight:600;font-size:19px;color:var(--navy);}
.contact-photo{border-radius:40px 8px 40px 8px;overflow:hidden;box-shadow:0 18px 40px rgba(11,45,77,.16);}
.contact-photo img{width:100%;height:360px;object-fit:cover;display:block;}
.storm{background:linear-gradient(90deg,var(--navy),var(--blue2));color:#fff;border-radius:40px 8px 40px 8px;padding:24px 28px;margin-top:24px;}
.storm b{display:block;font-family:'Poppins',sans-serif;font-size:18px;margin-bottom:6px;}
.storm p{color:#C9D6E2;font-size:15px;}
.storm a{color:#fff;font-weight:600;text-decoration:underline;}
.map-form{display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:start;}
.form-card{background:#fff;border-radius:40px 8px 40px 8px;padding:28px;box-shadow:0 12px 30px rgba(11,45,77,.10);}
.form-card .tag{display:block;font-family:'Roboto',sans-serif;font-size:12.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--link);margin-bottom:6px;}
.form-card h3{margin-bottom:14px;}
.form-card iframe{width:100%;min-height:720px;border:0;display:block;background:#fff;border-radius:6px;}
.form-note{font-size:12.5px;color:#8A98A5;margin-top:10px;}
.cities{display:grid;grid-template-columns:1fr 1fr;gap:4px 24px;margin-top:12px;}
.cities div{font-family:'Poppins',sans-serif;font-weight:500;color:var(--heading);font-size:16px;padding:7px 0;border-bottom:1px solid #D5DEE5;}
.cities div::before{content:'';display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--blue2);margin-right:12px;vertical-align:middle;}
@media(max-width:980px){
  .intro-grid,.map-form{grid-template-columns:1fr;gap:30px;}
  .c-list.row{grid-template-columns:1fr 1fr;}
  .form-card{padding:18px;order:-1;}
  .contact-photo img{height:240px;}
}

/* ==================== 00-bridge.css ==================== */
/* ============================================================
 * 00-bridge.css  —  mockup CSS <-> Elementor reconciliation.
 *
 * The mockups are standalone HTML documents. Their CSS uses bare element
 * selectors that also match Elementor's own wrapper markup, and class names
 * that the widgetizer copies onto Elementor widget wrappers. Every rule below
 * exists because that collision produced a real, visible bug on the previous
 * build of this system. Do not delete one without reproducing what it fixes.
 * ============================================================ */

/* ---- 1. `section{padding:80px 0}` also matches Elementor's own
 *         <section class="elementor-section"> wrappers, which put a blank
 *         80px band above the hero and doubled the padding on every raw band.
 *         .ggr-el sections are left alone: there the band class IS on the
 *         Elementor section, so its padding is the band's own.              */
.ggr-page section.elementor-section.ggr-raw{padding:0}
.ggr-page .elementor-section.ggr-raw > .elementor-container{max-width:none}

/* ---- 2. the mockups' body background is a preview artifact.
 *         #DDE3E9 is the grey the designer put behind the page frame in the
 *         mockup document. Shipping it paints the whole site grey.          */
body{background:#fff}

/* ---- 3. `.btn-*` are UNSCOPED in the mockup CSS, and the widgetizer copies
 *         an anchor's classes onto the Elementor Button widget's DIV wrapper.
 *         The wrapper then takes the navy fill and stretches the full width of
 *         the band, so the CTA renders as a solid navy bar with the label
 *         floating inside it. Styling belongs to the control, never the wrapper. */
.ggr-page .elementor-widget-button.btn-navy,
.ggr-page .elementor-widget-button.btn-light,
.ggr-page .elementor-widget-button.btn-white,
.ggr-page .elementor-widget-button.btn-outline,
.ggr-page .elementor-widget-button > .elementor-widget-container{
  background:none;border:0;padding:0;border-radius:0;box-shadow:none;
}
/*   The wrapper also picks up `.btn`, and the mockup's .btn is
 *   `display:inline-flex; justify-content:center`. On a 490px-wide widget
 *   wrapper that centres the button inside its own column, so the
 *   "Get A Free Estimate" button on each services band sat 132px right of the
 *   heading above it. Neutralising the FLEX role lets ordinary text-align
 *   control button alignment per band. */
.ggr-page .elementor-widget-button.btn{
  display:block;
  justify-content:normal;
  align-items:normal;
  height:auto;
  white-space:normal;
}

/* ---- 4. a button widget cannot be centred with text-align: Elementor's
 *         .elementor-widget-wrap is display:flex, so the widget shrinks to the
 *         button and pins to the start. Auto margins on the flex item are what
 *         actually centre it.                                               */
.ggr-page .cta-band .elementor-widget-button,
.ggr-page .banner   .elementor-widget-button,
.ggr-page .ctaband  .elementor-widget-button{margin-left:auto;margin-right:auto}

/* ---- 5. anything the theme emits as a <button> that the mockup drew as a
 *         <span> inherits the Elementor kit's button fill. This bit three
 *         times on the last build: the nav .sub-toggle and the rotator dots
 *         rendered as navy rectangles with a pink border instead of plain
 *         glyphs. Anything new emitting a <button> needs this reset.        */
.ggr-page .sub-toggle,
.ggr-page .nav-toggle,
.ggr-page .rev-dot,
.ggr-page .faq-btn{all:unset;cursor:pointer;display:inline-flex;align-items:center}
.ggr-page .faq-btn{display:block;width:100%}

/* ---- 6. the dropdown needs to be taken out of the top-level flex row.
 *         Without position:absolute the sub-menu items lay out inside the nav's
 *         own flex row and the header measured 2840px wide, scrolling the whole
 *         page sideways.                                                    */
.nav .sub-menu{position:absolute;z-index:60}

/* ---- 7. a dropdown parent's inline .sub-toggle opens its own line box after
 *         the block <a>, making the <li> taller than its siblings; centring
 *         then puts its link ~15px high. Put link and toggle on one row.
 *         Measure the ANCHOR, not the <li>, when a nav looks misaligned.    */
@media(min-width:981px){ .nav .menu > li{display:flex;align-items:center} }

/* ---- 8. the image filler emits <div class="ph"><img></div>, but the mockups
 *         size the <img> (or a .ph-img box) directly. The generic .ph has no
 *         height, so every such box collapsed to zero and the photo silently
 *         vanished. Any container the mockup sized needs an explicit .ph rule.
 *         Check this whenever a new band gets a photo.                      */
.ggr-page .ph{display:block;position:relative;overflow:hidden}
.ggr-page .ph > img{display:block;width:100%;height:100%;object-fit:cover}
.ggr-page .intro-photo .ph,
.ggr-page .svc-split .ph,
.ggr-page .photo .ph{height:100%}

/* ---- 9. maps. [ggr_map] emits <div class="mapsec"><iframe>, and .mapsec has
 *         no height anywhere in the mockup CSS, so a dropped-in map falls back
 *         to the iframe's intrinsic 300x150. Same family as the .ph collapse. */
.ggr-page .mapsec{display:block;width:100%}
.ggr-page .mapsec iframe{display:block;width:100%;height:440px;border:0}

/* ---- 10. customer quotes live in <blockquote> so the style gate's
 *          exclamation-point check exempts them. A customer's words are never
 *          edited to satisfy the gate. Keep them visually plain.            */
.ggr-page blockquote{margin:0;font-style:normal;quotes:none}
.ggr-page blockquote p{margin:0}

/* ---- 11. THE PAGE WOULD NOT SCROLL. `.page` is a bare class in the mockup
 *         CSS, written for their own <div class="page"> wrapper, and it carries
 *         overflow:hidden. WordPress puts class="page" on the BODY of every
 *         page post type, so that rule landed on <body> and killed vertical
 *         scrolling on every page of the site. Measured: body computed
 *         overflow hidden, document scrollHeight 7371 against clientHeight 890,
 *         and window.scrollTo(0,500) left scrollY at 0.
 *
 *         Same family as rule 1 (`section` colliding with .elementor-section)
 *         and rule 3 (unscoped .btn-* landing on widget wrappers): a bare
 *         mockup selector hitting markup the mockup never had. `.page` was the
 *         one that got missed because the collision is with a WORDPRESS body
 *         class rather than with Elementor.
 *
 *         NOTE this also silently defeated the horizontal-overflow audit: with
 *         overflow hidden on body, scrollWidth can never exceed clientWidth, so
 *         every page reported zero overflow. Re-check overflow after this.   */
/*         Plain overflow:visible, nothing more. An earlier attempt added
 *         overflow-x:clip here to keep blocking sideways scroll, but mixing a
 *         clip axis with a visible axis creates a clipping context on the body
 *         and can break position:sticky descendants. There is no horizontal
 *         overflow to suppress anyway: every multi-column grid has a mobile
 *         collapse and the pages measure zero horizontal overflow at 390px. */
body.page{
  overflow:visible;
  width:auto;
}

/* ==================== 10-contrast.css ==================== */
/* ============================================================
 * 10-contrast.css  —  measured accessibility corrections.
 *
 * Every number in this file was measured against the rendered ground with the
 * WCAG formula, never eyeballed. On the previous build three of six contrast
 * failures looked fine in a screenshot, and one measured 1.06:1 (invisible).
 *
 * STRUCTURAL NOTE. The previous build kept TWO lists, one for bands whose
 * heading goes white and one for bands whose accent goes light, and a band in
 * one list but not the other rendered half a two-tone heading correctly and
 * left the other half brand-blue on a dark ground. That is what "You're in
 * Great Hands is hard to read" turned out to be.
 *
 * Here there is ONE list. The selector group below is the single definition of
 * "dark band" and every rule in this file is keyed off it. IF YOU ADD A DARK
 * BAND, ADD IT ONCE, HERE, AND EVERY RULE FOLLOWS.
 *
 * Do not add a band to this list without checking its actual computed
 * background: on the last build a near-white band (#F3F5F8) was listed as dark,
 * so the "fix" painted near-white on near-white and measured 1.07:1, i.e. the
 * accessibility fix created the worst failure on the page.
 *
 * The dark bands on this site, with their real grounds:
 *   .hero      photo under a navy gradient scrim
 *   .pg-title  linear-gradient(--navy -> --blue2)
 *   .fin       linear-gradient(--navy-band -> --blue2)
 *   .cta-band  linear-gradient(--navy -> --blue2)
 *   .gallery   flat --blue2  <- the worst case, everything must pass HERE
 *   .storm     linear-gradient(--navy -> --blue2)
 * ============================================================ */

/* ---- token corrections (apply everywhere, not just dark bands) ---------- */
:root{
  /* --text was #7A7A7A: 4.29:1 on white and 3.57:1 on the --light band, so the
     site's ordinary body copy failed 4.5:1 everywhere. #686868 is the smallest
     darkening that passes on white (5.57), --light #E5EBEF (4.63) and
     --light-btn #E2EAEC (4.57). Visually near-identical, measurably compliant. */
  --text:#686868;

  /* --link was #377190: 4.45:1 on --light and 4.38:1 on --light-btn, i.e. the
     eyebrow failed on exactly the bands eyebrows sit on. #2F6380 measures
     6.53 on white and 5.35 on --light-btn. */
  --link:#2F6380;

  /* the light accent used on every dark band. Taken from the mockups' own
     .pg-title .crumb colour, so it is not a new colour in the palette.
     Measured: 9.49 on --navy, 9.29 on --navy-band, 4.99 on --blue2. */
  --on-dark:#C9D6E2;
}

/* ---- THE dark-band list. Headings go white. ---------------------------- */
.ggr-page .hero h1,     .ggr-page .hero h2,     .ggr-page .hero h3,
.ggr-page .pg-title h1, .ggr-page .pg-title h2, .ggr-page .pg-title h3,
.ggr-page .fin h1,      .ggr-page .fin h2,      .ggr-page .fin h3,
.ggr-page .cta-band h1, .ggr-page .cta-band h2, .ggr-page .cta-band h3,
.ggr-page .gallery h1,  .ggr-page .gallery h2,  .ggr-page .gallery h3,
.ggr-page .storm h1,    .ggr-page .storm h2,    .ggr-page .storm h3{color:#fff}

/* The same list, one level of specificity up, because the widgetizer turns a
   band heading into an Elementor Heading widget (h2.elementor-heading-title)
   and Elementor's stylesheet loads AFTER ggr.css. Without this the heading
   renders at --heading #21295C on a navy ground: 1.1:1, perfectly invisible. */
.ggr-page .hero     .elementor-heading-title,
.ggr-page .pg-title .elementor-heading-title,
.ggr-page .fin      .elementor-heading-title,
.ggr-page .cta-band .elementor-heading-title,
.ggr-page .gallery  .elementor-heading-title,
.ggr-page .storm    .elementor-heading-title{color:#fff}

/* ---- THE SAME list. Accents and body copy go light. -------------------- */
.ggr-page .hero .eyebrow,     .ggr-page .hero p,     .ggr-page .hero .tone,     .ggr-page .hero li,
.ggr-page .pg-title .eyebrow, .ggr-page .pg-title p, .ggr-page .pg-title .tone, .ggr-page .pg-title li,
.ggr-page .fin .eyebrow,      .ggr-page .fin p,      .ggr-page .fin .tone,      .ggr-page .fin li,
.ggr-page .cta-band .eyebrow, .ggr-page .cta-band p, .ggr-page .cta-band .tone, .ggr-page .cta-band li,
.ggr-page .gallery .eyebrow,  .ggr-page .gallery p,  .ggr-page .gallery .tone,  .ggr-page .gallery li,
.ggr-page .storm .eyebrow,    .ggr-page .storm p,    .ggr-page .storm .tone,    .ggr-page .storm li{
  color:var(--on-dark);
}

/* The mockup sets .eyebrow{color:var(--link)} unscoped. On --blue2 that is
   1.38:1, which is not "low contrast", it is not visible at all. The rule above
   fixes it; this one stops a later part file reintroducing it. */
.ggr-page .gallery .eyebrow{color:var(--on-dark)}

/* ---- small print on dark bands ----------------------------------------- */
/* .fin-fine is 13px, so it needs the full 4.5 and cannot rely on the
   large-text allowance. --on-dark on --blue2 is 4.99. */
.ggr-page .fin-fine{color:var(--on-dark)}

/* ---- links on dark bands ----------------------------------------------- */
.ggr-page .hero a:not(.btn),     .ggr-page .pg-title a:not(.btn),
.ggr-page .fin a:not(.btn),      .ggr-page .cta-band a:not(.btn),
.ggr-page .gallery a:not(.btn),  .ggr-page .storm a:not(.btn){
  color:#fff;text-decoration:underline;
}

/* ==================== 20-nav.css ==================== */
/* ============================================================
 * 20-nav.css  —  primary navigation dropdown.
 *
 * The mockups' nav is a FLAT list of <li> with no submenus, so their CSS has
 * no dropdown rules at all. The real menu has one (Services > All Services /
 * Residential Roofing), and without these rules the sub-menu inherits .menu's
 * display:flex and renders OPEN ON PAGE LOAD, overlaying the top-level row.
 * Measured before the fix: visible at top 64, 286px wide, opacity 1.
 *
 * Add to this file, never to the assembled ggr.css. build_css.py reassembles.
 * ============================================================ */

.nav .menu{position:relative}
.nav .menu > li{position:relative}

/* ---- closed state. Kept in the DOM and readable by crawlers (spec 7: no
 *      content may require interaction to exist), just visually hidden. ---- */
.nav .sub-menu{
  position:absolute;
  top:100%;
  left:0;
  z-index:60;
  display:flex;
  flex-direction:column;
  align-items:stretch;
  gap:0;
  min-width:232px;
  margin:0;
  padding:8px 0;
  list-style:none;
  background:#fff;
  border-radius:12px;
  box-shadow:0 18px 40px rgba(11,45,77,.18);
  opacity:0;
  visibility:hidden;
  pointer-events:none;
  transform:translateY(6px);
  transition:opacity .15s ease, transform .15s ease, visibility .15s;
}

/* ---- open on hover, on keyboard focus, and on the explicit toggle ---- */
.nav .menu > li:hover > .sub-menu,
.nav .menu > li:focus-within > .sub-menu,
.nav .menu > li.open > .sub-menu{
  opacity:1;
  visibility:visible;
  pointer-events:auto;
  transform:translateY(0);
}

.nav .sub-menu li{display:block;width:100%}
.nav .sub-menu a{
  display:block;
  padding:9px 18px;
  font-family:'Poppins',sans-serif;
  font-size:14.5px;
  line-height:1.4;
  color:var(--heading);
  white-space:nowrap;
}
.nav .sub-menu a:hover,
.nav .sub-menu a:focus-visible{background:var(--light);color:var(--navy)}

/* ---- the toggle button the chrome emits beside a parent link.
 *      It is a <button>, so it inherits the Elementor kit's button fill unless
 *      reset. 00-bridge.css does the all:unset; this only sizes the caret. ---- */
.nav .sub-toggle{
  width:18px;height:18px;margin-left:4px;
  display:inline-flex;align-items:center;justify-content:center;
  color:currentColor;
}
.nav .sub-toggle svg{width:10px;height:10px}
.nav .menu > li.open > a > .sub-toggle,
.nav .menu > li.open .sub-toggle{transform:rotate(180deg)}

/* ---- mobile: the dropdown becomes an inline block inside the stacked menu,
 *      so absolute positioning has to come back off. ---- */
@media(max-width:980px){
  .nav .sub-menu{
    position:static;
    opacity:1;
    visibility:visible;
    pointer-events:auto;
    transform:none;
    box-shadow:none;
    border-radius:0;
    background:transparent;
    padding:0 0 6px 14px;
    min-width:0;
    display:none;
  }
  .nav .menu > li.open > .sub-menu{display:flex}
  .nav .sub-menu a{padding:7px 0;font-size:15px}
}

/* ==================== 30-fixes.css ==================== */
/* ============================================================
 * 30-fixes.css  —  corrections found by measuring the rendered pages.
 * Add to this file, never to the assembled ggr.css.
 * ============================================================ */

/* ---- credentials band note. --text #686868 on the band's own
 *      rgba(162,179,193,.3) ground measured under 4.5:1. The band sits on white
 *      so the effective ground is a pale blue-grey; --slate-deep equivalent
 *      (--heading) measures well clear. Measured, not eyeballed. ---- */
.ggr-page .cred-note{color:var(--heading)}

/* ---- the credentials band has ONE badge now, not the mockup's four tiles
 *      (the CIB and BBB tiles are placeholders and do not ship). A flex row
 *      justified center with one child is fine, but the badge was sized for a
 *      row of four. Cap it so a single badge does not dominate the band. ---- */
.ggr-page .cred-row img{height:120px;width:auto}
.ggr-page .cred-note{max-width:640px;margin:18px auto 0;font-size:15px}

/* ---- service cards are anchors now (they link to the service pages), so they
 *      need the pointer and must not inherit the body link colour. ---- */
.ggr-page a.svc{cursor:pointer;color:inherit;text-decoration:none}

/* ---- the "inc" cards on the residential page were anchors in the mockup but
 *      link nowhere, so they are divs here. Keep the card look. ---- */
.ggr-page .inc{display:block}

/* ---- promise columns have no icon (the mockup's step icons belong to the
 *      process band, not here), so the column needs its own top spacing or the
 *      three headings sit hard against the band intro. ---- */
.ggr-page .g-col.promise{padding-top:4px}
.ggr-page .g-col.promise h3{margin-bottom:10px}

/* ---- .stepic is the round process icon. The mockup sizes .g-col img
 *      directly; ours carries a class so it can be sized without catching
 *      every other image that lands in a g-col. ---- */
.ggr-page .g-col img.stepic{width:130px;height:130px;object-fit:contain;margin:0 auto 18px;display:block}

/* ---- contact page: the four contact cards lost their icon column when the
 *      inline SVGs came out, so .c-list li is a single column now. ---- */
.ggr-page .c-list.row li{display:block}
.ggr-page .c-list .big{display:block;font-family:'Poppins',sans-serif;font-size:20px;font-weight:600;color:var(--heading);margin:4px 0}

/* ---- review stars. #F2B01E measured 1.91:1 on white. The glyphs carry
 *      aria-hidden and the rating is also given as text, so the bar is WCAG
 *      1.4.11 Non-text Contrast at 3:1 rather than 4.5:1. #C98209 measures
 *      3.14:1 and still reads as gold. Measured, not picked by eye. ---- */
.ggr-page .stars,
.ggr-page .rating i,
.ggr-page .rating-line .stars{color:#C98209}

/* ---- hero lead line. It was an <h3> in the mockup, straight after the <h1>,
 *      which is a heading-level skip (spec 6: clean hierarchy, no skips) and it
 *      is a tagline rather than a section heading. It is a <p> now and keeps the
 *      mockup's h3 typography. ---- */
.ggr-page .hero .hero-lead{
  font-family:'Poppins',sans-serif;
  font-size:22px;
  font-weight:600;
  line-height:1.35;
  color:#fff;
  margin:14px 0 26px;
  max-width:560px;
}
@media(max-width:700px){ .ggr-page .hero .hero-lead{font-size:18px} }

/* ---- .signs cards were <h4> under an <h2>, another skip. They are h3 now and
 *      keep the mockup's smaller card-heading size. ---- */
.ggr-page .signs .sign h3{font-size:17px;font-weight:600;margin-bottom:6px}

/* ---- footer column headings moved from h4 to h3 to remove a heading-level
 *      skip (the page body ends on h2). The mockup styles footer h4, so the
 *      same rules are mirrored onto h3. ---- */
.ggr-page footer.base h3,
footer.base h3{
  font-family:'Poppins',sans-serif;
  font-size:17px;
  font-weight:600;
  color:#fff;
  margin-bottom:14px;
}

/* ---- stats row class mismatch. The mockups style .stat-row, but
 *      [ggr_stats] emits <div class="stats">, which matches nothing in the
 *      mockup CSS, so the three stats stacked vertically instead of sitting in
 *      a row. Same family as the footer menu-name mismatch: the markup and the
 *      stylesheet were each correct on their own and simply never met. ---- */
.ggr-page .stats{
  display:flex;
  gap:36px;
  flex-wrap:wrap;
  margin-top:28px;
  padding-top:22px;
  border-top:1px solid var(--line);
}
.ggr-page .stats .stat b{
  display:block;font-family:'Poppins',sans-serif;font-size:32px;
  font-weight:700;color:var(--blue2);line-height:1;
}
.ggr-page .stats .stat span{font-size:13px;color:var(--text)}
@media(max-width:700px){ .ggr-page .stats{gap:22px} }

/* ---- the skip link was rendering as visible text at the top of every page,
 *      because the cloned chrome emits <a class="ggr-skip"> and NO rule for it
 *      ever existed in this stylesheet. Chloe spotted it in the header.
 *
 *      It is hidden rather than deleted. A skip link is WCAG 2.4.1 Bypass
 *      Blocks: a keyboard user lands on it first and can jump the whole nav
 *      instead of tabbing through every menu item on every page. Deleting it
 *      removes that. Clipping it until it takes focus is the standard pattern
 *      and gives the same visual result Chloe asked for. ---- */
.ggr-skip{
  position:absolute;
  width:1px;height:1px;
  margin:-1px;padding:0;border:0;
  clip:rect(0 0 0 0);
  clip-path:inset(50%);
  overflow:hidden;
  white-space:nowrap;
}
.ggr-skip:focus,
.ggr-skip:focus-visible{
  position:fixed;
  top:12px;left:12px;
  z-index:200;
  width:auto;height:auto;
  margin:0;padding:12px 20px;
  clip:auto;clip-path:none;
  overflow:visible;
  background:var(--navy);
  color:#fff;
  font-family:'Poppins',sans-serif;
  font-size:15px;
  border-radius:8px;
  box-shadow:0 10px 30px rgba(11,45,77,.35);
}

/* ---- footer logo. The band ground is --navy, and the NAVY logo was shipping
 *      there, so it was invisible: present, 220x202 on screen, and the same
 *      colour as the band. The client's own reversed variant is used now.
 *      Deliberately NO brightness(0) invert(1): that filter is what turned a
 *      previous build's footer logo into a solid white blob. ---- */
.ggr-page footer.base .f-logo,
footer.base .f-logo{
  display:block;
  margin-bottom:16px;
}
.ggr-page footer.base .f-logo img,
footer.base .f-logo img{
  display:block;
  width:170px;
  height:auto;
  max-width:100%;
}
@media(max-width:700px){
  .ggr-page footer.base .f-logo img,
  footer.base .f-logo img{width:140px}
}

/* ---- numbered process steps. The live site numbers them 1, 2, 3 and the
 *      build was rendering nothing there (it was printing attachment IDs).
 *      The number sits above the icon as a small mid-blue counter. ---- */
.ggr-page .g-col.step{position:relative}
.ggr-page .g-col.step .step-n{
  display:block;
  font-family:'Poppins',sans-serif;
  font-size:13px;
  font-weight:600;
  letter-spacing:.12em;
  color:var(--blue2);
  margin-bottom:10px;
}
.ggr-page .g-col.step .step-n::before{content:'STEP '}

/* ==================== 40-container.css ==================== */
/* ============================================================
 * 40-container.css  —  give widgetized bands back the mockups' .wrap geometry.
 *
 * THE BUG. Every band the widgetizer converts (.ggr-el) loses its inner
 * <div class="wrap">, because the widgets become direct children of Elementor's
 * own .elementor-container. The mockups put ALL their horizontal geometry on
 * .wrap (max-width:1140px, margin auto, 0 20px padding), so a converted band
 * spans the full viewport and its content sits flush against the window edge.
 *
 * Measured before this file: on a 1499px window, .fin / .light / .cta all had
 * container width 1499, x 0, max-width none, padding-left 0, and their headings
 * started at x=0. The .fin-list tick marks were stranded at the far left edge,
 * about 600px from the text they belong to.
 *
 * Bands that stay one HTML widget (.ggr-raw) keep their own .wrap and must NOT
 * get this, or the padding doubles.
 * ============================================================ */

.ggr-page .elementor-section.ggr-el > .elementor-container{
  max-width:1140px;
  margin-left:auto;
  margin-right:auto;
  padding-left:20px;
  padding-right:20px;
}

/* Two-column bands: the mockups' grids are a 50/50 or copy-plus-media split
   with a real gutter. Elementor's columns sit flush without one. */
.ggr-page .elementor-section.ggr-el2 > .elementor-container{gap:0}
.ggr-page .elementor-section.ggr-el2 > .elementor-container > .elementor-column{
  padding-left:25px;
  padding-right:25px;
}
@media(max-width:980px){
  .ggr-page .elementor-section.ggr-el2 > .elementor-container > .elementor-column{
    padding-left:0;
    padding-right:0;
  }
}

/* ---- .fin is text-align:center in the mockup because there it wraps a
 *      centred single column. Split into two real columns, that centring
 *      strands the copy and the tick list. The financing copy is a left
 *      column, so it reads left. ---- */
.ggr-page .fin.ggr-el2 .elementor-widget-container,
.ggr-page .fin.ggr-el2 h2,
.ggr-page .fin.ggr-el2 p,
.ggr-page .fin.ggr-el2 ul{text-align:left}
.ggr-page .fin.ggr-el2 .fin-list{list-style:none;padding-left:0}
.ggr-page .fin.ggr-el2 .fin-list li{position:relative;padding-left:28px;margin-bottom:8px}
.ggr-page .fin.ggr-el2 .fin-list li::before{
  content:'\2713';position:absolute;left:0;top:0;color:var(--on-dark);font-weight:700;
}
.ggr-page .fin.ggr-el2 .elementor-widget-button{margin-left:0;margin-right:auto}

/* ---- the media column: the mockups size these images by the grid cell, so
 *      without a rule they render at intrinsic size. ---- */
.ggr-page .ggr-el2 .fin-img img,
.ggr-page .ggr-el2 .media img,
.ggr-page .ggr-el2 .contact-photo img{
  display:block;width:100%;height:auto;border-radius:6px;
}

/* ---- the centre head inside a converted heading-plus-grid band ---- */
.ggr-page .ggr-headgrid.ggr-el > .elementor-container > .elementor-column .elementor-widget-heading,
.ggr-page .ggr-headgrid.ggr-el > .elementor-container > .elementor-column .elementor-widget-text-editor{
  text-align:center;
}
.ggr-page .ggr-headgrid.ggr-el .g-cols,
.ggr-page .ggr-headgrid.ggr-el .signs,
.ggr-page .ggr-headgrid.ggr-el .inc-grid,
.ggr-page .ggr-headgrid.ggr-el .map-form{text-align:left;margin-top:44px}
.ggr-page .ggr-headgrid.ggr-el .g-cols{text-align:center}

/* ==================== 50-twocol.css ==================== */
/* ============================================================
 * 50-twocol.css  —  make the mockups' .two-col styling work on Elementor
 *                   columns now that the wrapper classes survive.
 *
 * The widgetizer carries the grid's classes onto the SECTION and each column
 * div's class onto the Elementor COLUMN. So `.two-col` is a section and
 * `.media` is a column, where the mockup expected `.two-col > .media`. The
 * direct-child selectors therefore need restating for the real structure.
 * ============================================================ */

/* ---- FIRST, cancel the carried grid class's own LAYOUT role.
 *      The wrapper classes are carried onto the section so that DESCENDANT
 *      selectors keep matching (.two-col .media, .svc-block .ic). But those
 *      classes are grid declarations in the mockup, so landing one on the
 *      section turned the SECTION into a two-column grid, and Elementor's
 *      single .elementor-container child dropped into the first cell.
 *      Measured: container 690px wide inside a 1440px window instead of 1140,
 *      with both columns squeezed to 325px.
 *      The class is kept for scoping; only its display is neutralised. Applies
 *      to every grid class the widgetizer can carry up: two-col, cta-grid,
 *      intro-grid, fin-grid, serve, map-form. ---- */
.ggr-page .elementor-section.ggr-el2{
  display:block;
}
.ggr-page .elementor-section.ggr-el2 > .elementor-container{
  display:flex;
}

/* ---- the media column must NOT stretch to the copy column's height.
 *      The mockup's .two-col is align-items:center, so .media sizes to its own
 *      380px min-height and centres. Elementor columns stretch by default, so
 *      the photo was rendering 695px tall to match the copy beside it. ---- */
.ggr-page .ggr-el2 > .elementor-container{align-items:center}
.ggr-page .ggr-el2 > .elementor-container > .elementor-column.media{align-self:center}

/* ---- the media column: offset corner card, shadow, and a real height.
 *      Mockup: .two-col .media{border-radius:40px 8px 40px 8px;overflow:hidden;
 *      box-shadow:0 18px 40px rgba(11,45,77,.16);min-height:380px} ---- */
.ggr-page .ggr-el2 > .elementor-container > .elementor-column.media > .elementor-widget-wrap{
  border-radius:40px 8px 40px 8px;
  overflow:hidden;
  box-shadow:0 18px 40px rgba(11,45,77,.16);
  height:420px;          /* definite, so the photo does not track the copy height */
  min-height:380px;
}
/* The chain inside a media column is
   .elementor-column.media > .elementor-widget-wrap > .elementor-widget > img
   with NO .elementor-widget-container in between, so an earlier rule targeting
   that container did nothing and the photo sat 327px tall in a 420px card,
   leaving a 93px gap at the bottom. Target the widget itself. */
.ggr-page .ggr-el2 > .elementor-container > .elementor-column.media > .elementor-widget-wrap > .elementor-widget{
  height:100%;
  width:100%;
  flex:1 1 auto;
}
.ggr-page .ggr-el2 > .elementor-container > .elementor-column.media img{
  width:100%;
  height:100%;
  min-height:0;
  object-fit:cover;
  display:block;
  border-radius:0;   /* the corner shape belongs to the wrapper, not the image */
}

/* ---- .flip alternates the page: the mockup does
 *      `.two-col.flip > .media{order:-1}`, which cannot match once .media is an
 *      Elementor column. Reverse the container instead. Without this the
 *      services page ran photo-right three times and stopped alternating. ---- */
.ggr-page .ggr-el2.flip > .elementor-container{flex-direction:row-reverse}

/* ---- service icons. Mockup: .svc-block .ic{width:56px;height:56px}.
 *      .svc-block is on the section now, and the icon is inside an Elementor
 *      image widget, so the rule needs to reach through it. Without this the
 *      icons rendered at their intrinsic 200px. ---- */
.ggr-page .svc-block img.ic,
.ggr-page .ggr-el2 img.ic{
  width:56px;
  height:56px;
  min-height:0;
  display:block;
  margin-bottom:18px;
  object-fit:contain;
}

/* ---- gutter. The mockup's .two-col has gap:60px; Elementor columns are
 *      flush, and 40-container.css gives them 25px each side. On these bands
 *      the mockup's 60px reads better. ---- */
.ggr-page .ggr-el2.two-col > .elementor-container > .elementor-column{
  padding-left:30px;
  padding-right:30px;
}

@media(max-width:980px){
  /* mockup: .two-col{grid-template-columns:1fr} and .flip>.media{order:0},
     i.e. on mobile the photo goes back BELOW the copy on every band. */
  .ggr-page .ggr-el2.flip > .elementor-container{flex-direction:column}
  .ggr-page .ggr-el2 > .elementor-container > .elementor-column.media > .elementor-widget-wrap{
    height:260px;
    min-height:240px;
  }
  .ggr-page .ggr-el2 > .elementor-container > .elementor-column.media img{min-height:240px}
  .ggr-page .ggr-el2.two-col > .elementor-container > .elementor-column{
    padding-left:0;
    padding-right:0;
  }
}

/* ---- buttons in a two-column COPY column align left, as the mockup draws
 *      them (.svc-block .row-btn is a flex row starting at the copy's left
 *      edge). Elementor centres a button widget by default, which put the
 *      "Get A Free Estimate" button 132px right of the heading above it.
 *      Scoped to .two-col so the centred CTA bands are unaffected. ---- */
.ggr-page .ggr-el2.two-col > .elementor-container > .elementor-column:not(.media) .elementor-widget-button{
  margin-left:0;
  margin-right:auto;
  text-align:left;
}
.ggr-page .ggr-el2.two-col > .elementor-container > .elementor-column:not(.media) .elementor-widget-button .elementor-button-wrapper{
  text-align:left;
}
/* the mockup's .svc-block .row-btn{margin-top:26px} */
.ggr-page .svc-block .elementor-widget-button{margin-top:26px}

/* ==================== 60-elementor-widgets.css ==================== */
/* ============================================================
 * 60-elementor-widgets.css
 *
 * The FAQ accordions and the reviews are native Elementor widgets now
 * (accordion, testimonial, star-rating) so a client can edit a question or a
 * review in the builder. Elementor ships its own markup and default skin, so
 * this file restyles them to the mockups' design rather than leaving the
 * default look.
 *
 * Mockup reference, from mockup_merged.css:
 *   .faq-wrap{max-width:860px;margin:40px auto 0}
 *   .faq{background:#fff;border:1px solid var(--line);border-radius:6px;margin-bottom:12px}
 *   .faq h3{font-size:18px;display:flex;justify-content:space-between;padding:18px 22px}
 *   .faq h3 span{28px circle, var(--blue2) ground, white glyph, rotates 45deg when open}
 *   .faq p{padding:0 22px 20px;font-size:16px}
 *   .rev{white card, 1px --line border, radius 6, padding 40px 44px, centred}
 *   .rev .stars{gold} .rev p{19px/1.7 #4E5B68} .rev b{Poppins 15px --heading}
 * ============================================================ */

/* ---------------------------------------------------------- accordion ---- */
.ggr-page .ggr-faq-el .elementor-accordion{
  max-width:860px;
  margin:40px auto 0;
  border:0;
}
.ggr-page .ggr-faq-el .elementor-accordion-item{
  background:#fff;
  border:1px solid var(--line);
  border-radius:6px;
  margin-bottom:12px;
  overflow:hidden;
}
.ggr-page .ggr-faq-el .elementor-tab-title{
  font-family:'Poppins',sans-serif;
  font-size:18px;
  font-weight:600;
  color:var(--heading);
  padding:18px 22px;
  border:0;
  background:#fff;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:20px;
  cursor:pointer;
  line-height:1.35;
}
.ggr-page .ggr-faq-el .elementor-tab-title a,
.ggr-page .ggr-faq-el .elementor-tab-title .elementor-accordion-title{
  color:inherit;
  order:-1;          /* title first, icon last, as the mockup draws it */
  flex:1 1 auto;
}
/* the +/- icon becomes the mockup's filled circle, and the open state rotates
   it 45deg so the plus reads as a cross */
.ggr-page .ggr-faq-el .elementor-accordion-icon{
  width:28px;height:28px;
  flex:none;
  border-radius:50%;
  background:var(--blue2);
  color:#fff;
  display:flex;
  align-items:center;
  justify-content:center;
  font-size:14px;
  transition:transform .2s ease;
  order:2;
  margin:0;
}
/* Elementor puts the glyph in a nested span whose colour it sets itself, and
   it inherits --blue2, i.e. the SAME colour as the circle behind it, so the
   icon rendered as a solid blue blob. Force white on the span, the <i> and the
   <svg> path. Elementor also sizes the container itself, hence the explicit
   box-sizing and the width/height restated at this depth. */
.ggr-page .ggr-faq-el .elementor-tab-title .elementor-accordion-icon{
  box-sizing:border-box;
  width:28px;
  height:28px;
  padding:0;
  line-height:1;
}
.ggr-page .ggr-faq-el .elementor-tab-title .elementor-accordion-icon > span{
  display:flex;
  align-items:center;
  justify-content:center;
  width:100%;
  height:100%;
  color:#fff;
}
.ggr-page .ggr-faq-el .elementor-tab-title .elementor-accordion-icon i,
.ggr-page .ggr-faq-el .elementor-tab-title .elementor-accordion-icon svg{
  width:11px;
  height:11px;
  font-size:11px;
  color:#fff;
  fill:#fff;
}
.ggr-page .ggr-faq-el .elementor-tab-title .elementor-accordion-icon svg path{fill:#fff}
.ggr-page .ggr-faq-el .elementor-tab-title.elementor-active .elementor-accordion-icon{
  transform:rotate(45deg);
}
/* Elementor renders BOTH icon states, a plus and a minus, and swaps them.
   The mockup instead keeps ONE plus and rotates it 45deg so it reads as a
   cross. Rotating Elementor's minus gives a diagonal slash, which is what
   showed on the open panel. So the minus is never shown: the plus stays and
   rotates, matching `.faq.open h3 span{transform:rotate(45deg)}`. */
.ggr-page .ggr-faq-el .elementor-accordion-icon-closed{display:flex}
.ggr-page .ggr-faq-el .elementor-accordion-icon-opened{display:none}
.ggr-page .ggr-faq-el .elementor-tab-title.elementor-active .elementor-accordion-icon-closed{display:flex}

.ggr-page .ggr-faq-el .elementor-tab-content{
  border:0;
  padding:0 22px 20px;
  font-size:16px;
  color:var(--text);
  background:#fff;
}
.ggr-page .ggr-faq-el .elementor-tab-content p{margin:0 0 10px;font-size:16px}
.ggr-page .ggr-faq-el .elementor-tab-content p:last-child{margin-bottom:0}

/* ------------------------------------------------------- star rating ---- */
.ggr-page .ggr-reviews-el .elementor-star-rating__wrapper{
  justify-content:center;
  flex-wrap:wrap;
  gap:8px;
  margin-top:10px;
}
.ggr-page .ggr-reviews-el .elementor-star-rating{
  /* #C98209 measures 3.14:1 on white, which is the WCAG 1.4.11 bar for a
     graphical object. Elementor's default gold is far lighter. */
  color:#C98209;
  font-size:20px;
  letter-spacing:3px;
}
.ggr-page .ggr-reviews-el .elementor-star-rating__title{
  font-family:'Roboto',sans-serif;
  font-size:16px;
  color:var(--text);
  margin:0;
}

/* -------------------------------------------------------- testimonial ---- */
.ggr-page .ggr-review-row > .elementor-container{
  max-width:1140px;
  margin-left:auto;margin-right:auto;
  padding:0 20px;
  align-items:stretch;
  gap:0;
}
.ggr-page .ggr-review-row > .elementor-container > .elementor-column{
  padding-left:12px;padding-right:12px;
}
.ggr-page .elementor-widget-testimonial .elementor-testimonial-wrapper{
  background:#fff;
  border:1px solid var(--line);
  border-radius:6px;
  padding:34px 30px;
  text-align:center;
  height:100%;
}
.ggr-page .elementor-widget-testimonial .elementor-testimonial-content{
  font-family:'Roboto',sans-serif;
  font-size:17px;
  line-height:1.7;
  color:#4E5B68;
  margin-bottom:18px;
}
.ggr-page .elementor-widget-testimonial .elementor-testimonial-name{
  font-family:'Poppins',sans-serif;
  font-size:15px;
  font-weight:600;
  color:var(--heading);
}
.ggr-page .elementor-widget-testimonial .elementor-testimonial-job{
  font-family:'Roboto',sans-serif;
  font-size:13px;
  color:var(--text);
  margin-top:2px;
}
/* No photograph is attached to any testimonial and none should be: there are no
   real customer photos, and a stock face beside a real review would be exactly
   the false claim spec 9.3 exists to stop. Elementor still emits the image
   block and an `elementor-has-image` class, so both are neutralised. */
.ggr-page .elementor-widget-testimonial .elementor-testimonial-image,
.ggr-page .elementor-widget-testimonial .elementor-testimonial-wrapper .elementor-testimonial-image{
  display:none;
}
.ggr-page .elementor-widget-testimonial .elementor-testimonial-meta.elementor-has-image{
  padding:0;
}
.ggr-page .elementor-widget-testimonial .elementor-testimonial-meta-inner{
  display:block;
}

/* Equal card heights. The three reviews are different lengths (441 / 412 / 354
   before this), and Elementor columns do not stretch their widget wrap, so the
   cards ended ragged. Stretch the whole chain. */
/* Measured: the COLUMNS equalise fine at 357px each (the container is already
   align-items:stretch). The break was one level in, at .elementor-widget-wrap,
   which came out 357 / 328 / 270. In a column-direction flex container a child
   stretches on the CROSS axis (width) but not the main axis (height), so
   height:auto left it at content height. It needs flex:1. */
.ggr-page .ggr-review-row > .elementor-container > .elementor-column,
.ggr-page .ggr-review-row > .elementor-container > .elementor-column > .elementor-widget-wrap,
.ggr-page .ggr-review-row .elementor-widget-testimonial{
  display:flex;
  flex-direction:column;
  align-items:stretch;
}
.ggr-page .ggr-review-row > .elementor-container > .elementor-column > .elementor-widget-wrap,
.ggr-page .ggr-review-row .elementor-widget-testimonial{flex:1 1 auto}
.ggr-page .ggr-review-row .elementor-testimonial-wrapper{
  flex:1 1 auto;
  display:flex;
  flex-direction:column;
  justify-content:space-between;
}

@media(max-width:980px){
  .ggr-page .ggr-review-row > .elementor-container > .elementor-column{
    padding-left:0;padding-right:0;margin-bottom:14px;
  }
  .ggr-page .ggr-faq-el .elementor-tab-title{font-size:16.5px;padding:15px 18px}
  .ggr-page .ggr-faq-el .elementor-tab-content{padding:0 18px 18px}
}

/* ---- the attribution block keeps Elementor's own left alignment even inside a
 *      centred wrapper, so the name sat bottom-left under a centred quote. ---- */
.ggr-page .ggr-review-row .elementor-testimonial-meta,
.ggr-page .ggr-review-row .elementor-testimonial-meta-inner,
.ggr-page .ggr-review-row .elementor-testimonial-details{
  text-align:center;
  width:100%;
  justify-content:center;
}
.ggr-page .ggr-review-row .elementor-testimonial-name,
.ggr-page .ggr-review-row .elementor-testimonial-job{
  display:block;
  text-align:center;
}
/* stars read better before the count than after it */
.ggr-page .ggr-reviews-el .elementor-star-rating__wrapper{flex-direction:row-reverse}

/* ==================== 70-sgrid.css ==================== */
/* ============================================================
 * 70-sgrid.css  —  .sgrid / .scard, the card grid used on the locations hub,
 *                  the five city pages and the GBP category page.
 *
 * THE BUG. `.sgrid` and `.scard` are class names carried over from the
 * PREVIOUS build's mockups. They do not exist anywhere in the Good Guys mockup
 * CSS, so they had no styling at all: `.sgrid` computed to display:block and
 * the cards stacked as five full-width rows, 1100px wide each. Twelve
 * occurrences across seven pages, all of them wrong, and nothing errored.
 *
 * Styled here to the Good Guys card language, taken from the mockups' own
 * `.inc` card: white ground, 1px --line border, the offset corner radius
 * 40px 8px 40px 8px, and the mid-blue hover fill the other cards use.
 *
 * When cloning a build again: grep every class the content files use against
 * the NEW mockup CSS. A class that exists in the old mockups and not the new
 * ones fails silently and looks like a layout bug much later.
 * ============================================================ */

.ggr-page .sgrid{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:24px;
  margin-top:44px;
}

/* Exactly four cards read better 2x2 than 3+1, which leaves an orphan.
   The "What We Do in <city>" and GBP category grids are both four. */
.ggr-page .sgrid:has(> :nth-child(4):last-child){
  grid-template-columns:repeat(2,1fr);
}

.ggr-page .scard{
  display:block;
  padding:30px 28px;
  border-radius:40px 8px 40px 8px;
  background:#fff;
  border:1px solid var(--line);
  transition:background .25s, transform .25s, box-shadow .25s;
}
.ggr-page .scard h3{
  font-family:'Poppins',sans-serif;
  font-size:20px;
  font-weight:600;
  color:var(--heading);
  margin-bottom:8px;
  transition:color .25s;
}
.ggr-page .scard h3 a{color:inherit}
.ggr-page .scard p{
  font-family:'Poppins',sans-serif;
  color:var(--text-dark);
  font-size:15px;
  line-height:1.7;
  margin:0;
  transition:color .25s;
}

/* hover fill, matching .svc and .inc elsewhere on the site */
.ggr-page .scard:hover,
.ggr-page .scard:focus-within{
  background:var(--blue2);
  transform:translateY(-4px);
  box-shadow:0 20px 44px rgba(11,45,77,.18);
}
.ggr-page .scard:hover h3,
.ggr-page .scard:hover h3 a,
.ggr-page .scard:hover p,
.ggr-page .scard:focus-within h3,
.ggr-page .scard:focus-within h3 a,
.ggr-page .scard:focus-within p{color:#fff}

@media(max-width:980px){
  .ggr-page .sgrid,
  .ggr-page .sgrid:has(> :nth-child(4):last-child){
    grid-template-columns:repeat(2,1fr);
    gap:18px;
  }
}
@media(max-width:640px){
  .ggr-page .sgrid,
  .ggr-page .sgrid:has(> :nth-child(4):last-child){
    grid-template-columns:1fr;
  }
}

/* ==================== 80-orphan-classes.css ==================== */
/* ============================================================
 * 80-orphan-classes.css
 *
 * More classes carried over from the previous build's mockups that have no
 * styling in the Good Guys set, found by the same sweep that caught `.sgrid`:
 * compare every class the content files emit against the assembled stylesheet
 * and list the ones that match nothing.
 *
 * Deliberately NOT styled, because they are widgetizer routing hooks rather
 * than design classes and carry no visual role:
 *   faq-sec, reviews-band, svc-cards, q-band
 * ============================================================ */

/* ---- .pg-intro: the lead paragraph in the navy page-title band. The mockup
 *      writes it as an inline style, `color:#C9D6E2;max-width:760px;
 *      margin-top:12px;font-size:17px`. Colour already comes from the dark-band
 *      rules in 10-contrast.css; the measure and spacing were missing, so it
 *      ran the full width of the band. ---- */
.ggr-page .pg-title .pg-intro{
  max-width:760px;
  margin-top:12px;
  font-size:17px;
  line-height:1.7;
}

/* ---- .lead-line: the answer-first opening sentence on the problem pages.
 *      Spec 7 wants the direct answer to lead, so it should read as a lead
 *      paragraph rather than as ordinary body copy. ---- */
.ggr-page .lead-line{
  font-family:'Poppins',sans-serif;
  font-size:19px;
  line-height:1.65;
  font-weight:500;
  color:var(--heading);
  margin-bottom:18px;
}
@media(max-width:700px){ .ggr-page .lead-line{font-size:17px} }

/* ---- .nap-also: the small "we also cover, nearby" label above the city chips
 *      in the city pages' NAP band. ---- */
.ggr-page .nap-also{
  font-family:'Poppins',sans-serif;
  font-size:13px;
  font-weight:500;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:var(--blue-text, var(--link));
  margin:22px 0 8px;
}

/* ==================== 90-svc-icon-hover.css ==================== */
/* ============================================================
 * 90-svc-icon-hover.css  —  the service-card icon on hover.
 *
 * THE BUG Chloe reported: hovering a service card on the home page turned the
 * icon into a featureless white circle with no glyph visible.
 *
 * CAUSE. The mockup does `.svc:hover img.ic{filter:brightness(0) invert(1)}`,
 * which is the right trick for a SOLID single-colour glyph on a transparent
 * background: brightness(0) flattens it to black, invert(1) turns that white.
 * But the client's three icons are not built the same way as each other:
 *
 *   icon-residential   light grey disc rgba(231,232,237,.99) + navy glyph
 *   icon-commercial    solid navy shape, no disc
 *   icon-inspections   fully transparent ground + navy glyph
 *
 * On the two that carry a light disc, brightness(0) flattens the disc AND the
 * glyph to the same black, and invert then makes BOTH white. The glyph stops
 * existing. No filter can separate two colours it has already flattened into
 * one, so the fix is not a better filter.
 *
 * FIX. Drop the invert and put a white chip behind the icon instead. The navy
 * glyph then reads on white regardless of how any individual icon is built,
 * which also means a fourth service icon added later cannot reintroduce this.
 * Measured: navy #21295C on white is 13.6:1.
 * ============================================================ */

.ggr-page .svc .ic{
  border-radius:50%;
  background:transparent;
  transition:background .25s, box-shadow .25s;
}

.ggr-page .svc:hover .ic,
.ggr-page .svc:focus-visible .ic,
.ggr-page .svc:hover img.ic,
.ggr-page .svc:focus-visible img.ic{
  /* cancel the mockup's invert: see the note above for why it cannot work
     across these three icons */
  filter:none;
  background:#fff;
  box-shadow:0 0 0 6px #fff;   /* the chip reads as a circle a little larger
                                  than the glyph, matching the resting look */
}
