/* =========================================================================
   CACTUS CONTAINERS — Design System  v1
   Evolve brand: steel + desert sand + sage + corten-rust accent
   Type: Satoshi (display) / General Sans (body)
   ========================================================================= */

:root{
  /* --- brand palette: Graphite & Cactus Sage ---
     Anchored on the Cactus Containers logo color #7A8B79 (hue 117°).
     The logo tint itself is too light for text (3.62:1 on white), so UI text/CTAs use
     deeper shades of the SAME hue that pass WCAG AA. --brand-logo is the exact
     logo color, reserved for decorative fills where contrast doesn't apply. */
  --brand-logo:#7a8b79;  /* EXACT logo sage — decorative use only */
  --ink:#14171a;         /* charcoal steel */
  --ink-2:#1d2227;
  --steel:#2c343b;
  --sage-900:#223621;    /* deepest sage — icon fills / bands */
  --sage-700:#577656;    /* primary accent / CTA — 5.08:1 on white */
  --sage-600:#436241;    /* hover / text on light — 6.86:1 on white, 6.04:1 on --sand */
  --sage-400:#8da68c;    /* light sage on dark */
  --sage-200:#cbd8cb;
  --blue:#3b6ea5;        /* steel blue — secondary */
  --blue-600:#2f5a86;
  --sand:#eef1f2;        /* cool light page background */
  --sand-2:#e4e9ec;
  --sand-3:#d7dee2;
  --line:#dde3e6;        /* hairline border */
  --line-2:#ccd4d8;
  --rust:#577656;        /* accent = primary CTA (teal) */
  --rust-600:#436241;
  --amber:#e6b13c;
  --paper:#ffffff;
  --text:#161a1e;
  --muted:#586067;
  /* --muted-2 was #828a90 — 3.51:1 on white, 2.87:1 on --sand-2. It is used for
     real fine print (.qr-fine, .qr-line small, .fcount, group labels, doc-meta),
     so it has to clear 4.5:1 on the lightest surface it lands on. #60686e is the
     lightest value that does: 5.67 white / 5.00 sand / 4.64 sand-2. */
  --muted-2:#60686e;
  /* --star was #e6b13c — 1.96:1 on white, failing 1.4.11 for the rating stars.
     Deepened to keep the gold read while clearing 3:1 (3.63 white / 3.20 sand).
     --amber above is untouched: it is a background, not a foreground. */
  --star:#b07d12;

  /* --- type --- */
  --font-display:"Satoshi","General Sans",system-ui,sans-serif;
  --font-body:"General Sans","Satoshi",system-ui,-apple-system,sans-serif;

  /* --- structure --- */
  --maxw:1240px;
  --radius:14px;
  --radius-sm:9px;
  --radius-lg:22px;
  --shadow-sm:0 1px 2px rgba(20,24,26,.06),0 2px 6px rgba(20,24,26,.05);
  --shadow:0 8px 24px -8px rgba(20,24,26,.14),0 3px 8px -4px rgba(20,24,26,.08);
  --shadow-lg:0 30px 60px -24px rgba(20,24,26,.30),0 12px 24px -12px rgba(20,24,26,.14);
  --ease:cubic-bezier(.22,.61,.36,1);
}

*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
body{
  margin:0;font-family:var(--font-body);color:var(--text);
  background:var(--sand);line-height:1.6;font-size:17px;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
button{font-family:inherit}
h1,h2,h3,h4{font-family:var(--font-display);font-weight:700;line-height:1.05;margin:0;letter-spacing:-.02em;color:var(--text)}
p{margin:0}

/* --- layout helpers --- */
.container{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:24px}
.section{padding-block:clamp(56px,7vw,104px)}
.section-tight{padding-block:clamp(40px,5vw,64px)}
.center{text-align:center}
.eyebrow{
  display:inline-flex;align-items:center;gap:8px;
  font-size:12.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  /* sage-700 is 5.08:1 on pure white but only 4.48:1 on --sand, and the eyebrow
     sits on --sand more often than not. sage-600 is the token meant for text on
     light surfaces (6.04:1 on sand) and is the same brand hue. */
  color:var(--sage-600);
}
.eyebrow::before{content:"";width:22px;height:2px;background:var(--rust);border-radius:2px}
.eyebrow.on-dark{color:var(--sage-200)}
h2.h-xl{font-size:clamp(30px,4.4vw,52px)}
.lead{font-size:clamp(17px,1.6vw,20px);color:var(--muted);max-width:60ch}
.section-head{max-width:64ch}
.section-head.center{margin-inline:auto}

/* --- buttons --- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  font-weight:600;font-size:15.5px;letter-spacing:.01em;
  padding:14px 24px;border-radius:10px;border:1.5px solid transparent;
  cursor:pointer;transition:all .25s var(--ease);white-space:nowrap;
}
.btn svg{width:18px;height:18px}
.btn-primary{background:var(--rust);color:#fff;box-shadow:0 6px 18px -6px rgba(87, 118, 86,.6)}
.btn-primary:hover{background:var(--rust-600);transform:translateY(-2px);box-shadow:0 12px 26px -8px rgba(87, 118, 86,.65)}
.btn-dark{background:var(--ink);color:#fff}
.btn-dark:hover{background:var(--ink-2);transform:translateY(-2px)}
.btn-ghost{background:transparent;color:var(--text);border-color:var(--line-2)}
.btn-ghost:hover{border-color:var(--ink);background:var(--paper)}
.btn-ghost.on-dark{color:#fff;border-color:rgba(255,255,255,.28)}
.btn-ghost.on-dark:hover{border-color:#fff;background:rgba(255,255,255,.08)}
.btn-lg{padding:17px 30px;font-size:16.5px}
.btn-block{width:100%}

/* --- badges / chips / specs --- */
.chip{
  display:inline-flex;align-items:center;gap:6px;
  /* sage-700 on its own 10% tint is 4.47:1 — just under AA for this 12.5px text.
     sage-600 on the same tint is 6.03:1. */
  font-size:12.5px;font-weight:600;color:var(--sage-600);
  background:rgba(87, 118, 86,.10);border:1px solid rgba(87, 118, 86,.18);
  padding:5px 11px;border-radius:100px;letter-spacing:.01em;
}
.chip.rust{color:var(--rust-600);background:rgba(87, 118, 86,.09);border-color:rgba(87, 118, 86,.20)}
.chip.ink{color:#e7ebed;background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.14)}
.spec{display:inline-flex;align-items:center;gap:6px;font-size:13.5px;color:var(--muted);font-weight:500}
.spec svg{width:15px;height:15px;color:var(--sage-600)}

/* --- generic card --- */
.card{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-sm);transition:transform .3s var(--ease),box-shadow .3s var(--ease),border-color .3s}
.card:hover{transform:translateY(-4px);box-shadow:var(--shadow);border-color:var(--line-2)}

/* =======================  TOP BAR + HEADER  ======================= */
.topbar{background:var(--ink);color:#c4cace;font-size:13px}
.topbar .container{display:flex;align-items:center;justify-content:space-between;gap:16px;min-height:40px}
.topbar a{color:#c4cace;transition:color .2s}
.topbar a:hover{color:#fff}
.topbar .tb-left{display:flex;gap:22px;align-items:center}
.topbar .tb-item{display:inline-flex;gap:7px;align-items:center}
.topbar .tb-item svg{width:14px;height:14px;color:var(--sage-400)}
.topbar .tb-right{display:flex;gap:16px;align-items:center}
.topbar .tb-social{display:flex;gap:12px}
.topbar .tb-social svg{width:15px;height:15px}

header.site{position:sticky;top:0;z-index:50;background:rgba(238,241,242,.86);backdrop-filter:blur(14px);border-bottom:1px solid var(--line)}
.nav{display:flex;align-items:center;gap:28px;min-height:82px}
.nav .logo{display:flex;align-items:center;gap:11px;flex-shrink:0}
.nav .logo img{height:54px;width:auto}
.nav .logo b{font-family:var(--font-display);font-size:19px;letter-spacing:-.01em;line-height:1}
.nav .logo span{display:block;font-size:10px;letter-spacing:.28em;color:var(--sage-600);font-weight:600}
.nav>ul{display:flex;gap:4px;list-style:none;margin:0;padding:0;margin-left:8px}
.nav ul a{padding:9px 15px;border-radius:8px;font-weight:500;font-size:15.5px;color:var(--text);transition:all .2s;position:relative}
.nav ul a:hover{background:rgba(87, 118, 86,.10);color:var(--sage-600)}
.nav ul a.active{color:var(--sage-600)}
.nav ul a.active::after{content:"";position:absolute;left:15px;right:15px;bottom:2px;height:2px;background:var(--rust);border-radius:2px}
.nav .nav-right{margin-left:auto;display:flex;align-items:center;gap:14px}
.nav .icon-btn{width:42px;height:42px;display:grid;place-items:center;border-radius:10px;border:1px solid var(--line);background:var(--paper);color:var(--text);transition:all .2s;position:relative}
.nav .icon-btn:hover{border-color:var(--ink);transform:translateY(-1px)}
.nav .icon-btn svg{width:19px;height:19px}
.nav .phone-cta{display:flex;flex-direction:column;line-height:1.1}
.nav .phone-cta small{font-size:11px;color:var(--muted);font-weight:500}
.nav .phone-cta b{font-family:var(--font-display);font-size:17px;color:var(--text)}
/* Multi-word nav items ("Rent-to-Own", "Custom Builds", "Self Storage",
   "Tack Rooms") must never break onto two lines. The nav now carries up to 10
   items, so it tightens in two stages on mid-size laptops — and drops the
   phone-cta block before the links themselves — to stay on one row instead of
   overflowing the container. */
.nav ul a{white-space:nowrap}
@media(max-width:1460px){
  .nav{gap:14px}
  .nav>ul{margin-left:0;gap:0}
  .nav ul a{padding-left:9px;padding-right:9px;font-size:14.7px}
  .nav .nav-right{gap:10px}
}
@media(max-width:1220px){
  .nav{gap:10px}
  .nav ul a{padding-left:6px;padding-right:6px;font-size:13.8px}
  .nav .phone-cta{display:none}
}

/* =======================  HERO  ======================= */
.hero{position:relative;background:var(--ink);color:#fff;overflow:hidden}
.hero-media{position:absolute;inset:0}
.hero-media img{width:100%;height:100%;object-fit:cover;opacity:.55}
.hero-media::after{content:"";position:absolute;inset:0;
  background:linear-gradient(100deg,rgba(15,20,22,.94) 0%,rgba(15,20,22,.72) 42%,rgba(15,20,22,.25) 100%);}
.hero .container{position:relative;z-index:2;padding-block:clamp(72px,11vw,132px)}
.hero-inner{max-width:680px}
.hero h1{font-size:clamp(38px,6vw,68px);font-weight:900;color:#fff;letter-spacing:-.03em}
.hero h1 em{font-style:normal;color:var(--sage-400)}
.hero .lead{color:rgba(255,255,255,.82);margin-top:20px;font-size:clamp(17px,1.7vw,20px);max-width:52ch}
.hero .hero-cta{display:flex;flex-wrap:wrap;gap:14px;margin-top:32px}
.hero-trust{display:flex;flex-wrap:wrap;gap:26px;margin-top:44px;padding-top:28px;border-top:1px solid rgba(255,255,255,.14)}
.hero-trust .ht{display:flex;flex-direction:column;gap:2px}
.hero-trust .ht b{font-family:var(--font-display);font-size:26px;color:#fff;line-height:1}
.hero-trust .ht span{font-size:13px;color:rgba(255,255,255,.62)}

/* ZIP quote widget floating on hero */
.zip-card{position:relative;z-index:2;background:var(--paper);border-radius:var(--radius);box-shadow:var(--shadow-lg);
  padding:22px;max-width:var(--maxw);margin:-46px auto 0;display:grid;grid-template-columns:1.3fr 1fr 1fr auto;gap:16px;align-items:end}
.zip-card .field{display:flex;flex-direction:column;gap:6px}
.zip-card label{font-size:12px;font-weight:600;color:var(--muted);letter-spacing:.03em;text-transform:uppercase}
.zip-card input,.zip-card select{padding:12px 14px;border:1.5px solid var(--line-2);border-radius:9px;font-size:15px;font-family:inherit;background:var(--sand);color:var(--text)}
/* Keep the border tint as the hover/typing affordance, but never suppress the
   focus ring for keyboard users — see the :focus-visible block at the bottom. */
.zip-card input:focus,.zip-card select:focus{border-color:var(--sage-600);background:#fff}
.zip-card optgroup{font-family:inherit}

/* ---- ZIP quote result panel (rendered by the delivery pricing engine) ---- */
.quote-result{display:none;max-width:var(--maxw);margin:14px auto 0;background:var(--paper);
  border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);
  padding:clamp(18px,2.2vw,26px)}
.quote-result.show{display:block;animation:qrIn .35s var(--ease)}
@keyframes qrIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.quote-result.is-warn{background:var(--sand-2);border-color:var(--line-2);box-shadow:var(--shadow-sm)}
.qr-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 14px;padding-bottom:14px;
  border-bottom:1px solid var(--line)}
.qr-where{font-family:var(--font-display);font-size:clamp(18px,2vw,21px);font-weight:700;color:var(--text);line-height:1.25}
.qr-meta{font-size:14px;color:var(--muted)}
.qr-meta b{color:var(--sage-600);font-weight:600}
.qr-line{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  padding:11px 0;border-bottom:1px solid var(--line);font-size:15px}
.qr-line>span{color:var(--muted);min-width:0}
.qr-line>b{font-variant-numeric:tabular-nums;font-weight:600;color:var(--text);white-space:nowrap}
.qr-line small{display:block;font-size:12.5px;color:var(--muted-2);margin-top:1px}
.qr-line.qr-total{border-bottom:0;padding-top:16px}
.qr-line.qr-total>span{color:var(--text);font-weight:600;font-size:15.5px}
.qr-line.qr-total>b{font-family:var(--font-display);font-size:clamp(23px,3vw,30px);color:var(--sage-700);line-height:1.1}
.qr-beat{display:flex;gap:9px;align-items:flex-start;margin-top:14px;padding:11px 13px;
  border-radius:var(--radius-sm);background:rgba(87,118,86,.09);border:1px solid rgba(87,118,86,.20);
  font-size:14px;line-height:1.5;color:var(--sage-600)}
.qr-beat svg{width:16px;height:16px;flex-shrink:0;margin-top:3px}
.qr-msg{margin:0;font-size:15.5px;line-height:1.6;color:var(--text)}
.qr-head+.qr-msg{margin-top:14px}
.qr-fine{margin:14px 0 0;font-size:13px;color:var(--muted-2)}
.quote-result a:not(.btn){color:var(--sage-600);font-weight:600;text-decoration:underline;text-underline-offset:2px}
.qr-cta{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}
.qr-cta .btn{white-space:normal;text-align:center}
@media(max-width:520px){.qr-cta .btn{width:100%}}

/* =======================  STAT / LOGO STRIP  ======================= */
.marquee{background:var(--ink-2);color:#c5cbcf;overflow:hidden}
.marquee .container{display:flex;gap:44px;align-items:center;justify-content:center;flex-wrap:wrap;padding-block:20px;font-size:14px}
.marquee .mi{display:inline-flex;gap:9px;align-items:center;white-space:nowrap}
.marquee .mi svg{width:17px;height:17px;color:var(--sage-400)}

/* =======================  CATEGORY GRID  ======================= */
.cat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px;margin-top:44px}
.cat{position:relative;border-radius:var(--radius);overflow:hidden;min-height:270px;display:flex;align-items:flex-end;
  color:#fff;background:var(--steel);box-shadow:var(--shadow-sm);transition:transform .35s var(--ease),box-shadow .35s}
.cat img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .6s var(--ease)}
.cat::after{content:"";position:absolute;inset:0;background:linear-gradient(to top,rgba(13,18,20,.92),rgba(13,18,20,.15) 62%,transparent)}
.cat:hover{transform:translateY(-5px);box-shadow:var(--shadow-lg)}
.cat:hover img{transform:scale(1.07)}
.cat .cat-body{position:relative;z-index:2;padding:22px}
.cat .cat-body h3{color:#fff;font-size:20px}
.cat .cat-body p{font-size:13.5px;color:rgba(255,255,255,.74);margin-top:4px}
.cat .cat-arrow{display:inline-flex;align-items:center;gap:6px;margin-top:12px;font-weight:600;font-size:14px;color:var(--sage-200)}
.cat.tall{grid-row:span 2;min-height:100%}

/* =======================  PRODUCT CARDS  ======================= */
.prod-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:22px;margin-top:44px}
/* A product switched off in the content editor is hidden by the build, which
   puts the `hidden` attribute on its <article> (sync_product_visibility in
   tools/sync-content.py). The attribute alone is not enough: these cards are
   grid items and the UA's [hidden]{display:none} is a weak rule that any
   author display on .prod or .card would outrank. Stated explicitly so a
   withdrawn product cannot reappear because of an unrelated CSS change. */
[hidden]{display:none!important}
.prod{display:flex;flex-direction:column;overflow:hidden}
.prod .prod-media{position:relative;aspect-ratio:4/3;background:var(--sand-2);overflow:hidden}
.prod .prod-media img{width:100%;height:100%;object-fit:cover;transition:transform .5s var(--ease)}
.prod:hover .prod-media img{transform:scale(1.05)}
.prod .prod-tag{position:absolute;top:12px;left:12px;z-index:2}
.prod .prod-body{padding:18px 18px 20px;display:flex;flex-direction:column;flex:1}
.prod .prod-cat{font-size:12px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--sage-600)}
.prod h3{font-size:18px;margin-top:6px;line-height:1.15}
.prod .prod-specs{display:flex;flex-wrap:wrap;gap:14px;margin-top:12px;padding-top:12px;border-top:1px dashed var(--line)}
.prod .prod-foot{display:flex;align-items:center;justify-content:space-between;margin-top:auto;padding-top:16px;gap:12px}
.prod .price{font-family:var(--font-display);font-size:22px;font-weight:700;color:var(--text)}
.prod .price small{font-size:12.5px;font-weight:500;color:var(--muted);display:block;letter-spacing:0}
.prod .price.quote{font-size:16px;color:var(--sage-700)}

/* =======================  HOW IT WORKS  ======================= */
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:22px;margin-top:48px;position:relative}
.step{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:28px 24px;position:relative;transition:all .3s var(--ease)}
.step:hover{border-color:var(--sage-400);box-shadow:var(--shadow)}
.step .step-num{font-family:var(--font-display);font-size:14px;font-weight:700;color:var(--rust);letter-spacing:.06em}
.step .step-ico{width:56px;height:56px;border-radius:14px;background:var(--sage-900);color:var(--sage-200);display:grid;place-items:center;margin:14px 0 18px}
.step .step-ico svg{width:27px;height:27px}
.step h3{font-size:18px}
.step p{margin-top:8px;font-size:14.5px;color:var(--muted)}

/* =======================  CUSTOM BUILD BAND  ======================= */
.band{position:relative;background:var(--sage-900);color:#fff;border-radius:var(--radius-lg);overflow:hidden}
.band-media{position:absolute;inset:0}
.band-media img{width:100%;height:100%;object-fit:cover;opacity:.22}
.band-media::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,var(--sage-900) 30%,rgba(55,67,46,.5))}
.band .band-inner{position:relative;z-index:2;padding:clamp(40px,6vw,72px);display:grid;grid-template-columns:1fr 1.45fr;gap:40px;align-items:start}
/* start, not center. The form column is a ~1,450px GoHighLevel iframe and the
   copy beside it is ~440px, so centring left the copy as an island with ~500px
   of empty green above and below it — it read as shrunken rather than as the
   band's opening statement. It now tops out level with the form.
   Sticky was the obvious next step and was rejected: containers.html carries a
   second sticky bar (.locbar, catalog.css:136, pinned at y=76 and 111px deep)
   that outranks anything inside .band — .band is a stacking context three times
   over — so a pinned copy column would have sat with its eyebrow and headline
   behind an opaque bar for the whole scroll. */
/* The form column used to be the SMALLER half (1.2fr .9fr), which left the
   quote iframe 378px wide. GoHighLevel stacks every field full-width whatever
   room it is given, so at that width the form ran ~1,360px tall inside an
   1,180px box and grew its own inner scrollbar — a visitor scrolled inside a
   box inside a scrolling page, on the one element that captures leads.
   Measured: 400px wide -> 1,350 tall; 600px -> 1,250; 900px -> 1,210. Width
   alone cannot fix the height, but it buys back ~100px and stops the form
   looking cramped, so the form now gets the larger column. */
.band h2{color:#fff;font-size:clamp(28px,3.6vw,42px)}
.band p{color:rgba(255,255,255,.82);margin-top:14px;max-width:46ch}
.band .band-list{display:flex;flex-direction:column;gap:12px;margin-top:24px}
/* The tick hangs in a gutter rather than sitting in a flex row. Flex makes a
   separate item out of every child, INCLUDING each run of bare text, so a
   bullet that wraps part of its wording in a link ("Generator enclosures" on
   the home band) split into two columns that wrapped independently. Keeping
   the text in normal inline flow means a bullet can carry a link, a <strong>
   or an <abbr> and still read as one sentence. */
.band .band-list .bl{position:relative;padding-left:31px;font-size:15.5px;color:rgba(255,255,255,.9)}
.band .band-list .bl svg{position:absolute;left:0;top:2px;width:20px;height:20px;color:var(--sage-400)}
.quote-box{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.16);border-radius:var(--radius);padding:26px;backdrop-filter:blur(6px)}
.quote-box h3{color:#fff;font-size:20px}
.quote-box .qf{display:flex;flex-direction:column;gap:12px;margin-top:16px}
.quote-box input,.quote-box select,.quote-box textarea{width:100%;padding:12px 14px;border-radius:9px;border:1px solid rgba(255,255,255,.2);background:rgba(255,255,255,.07);color:#fff;font-family:inherit;font-size:15px}
/* Placeholder text is text: 50% white on this panel was 3.97:1, 62% is 5.18:1. */
.quote-box input::placeholder,.quote-box textarea::placeholder{color:rgba(255,255,255,.62)}
/* outline:none removed — this rule out-specifies the :focus-visible baseline at
   the foot of this file, so leaving it here would have silently kept the focus
   ring suppressed on the quote form. Border tint stays as the typing cue. */
.quote-box input:focus,.quote-box select:focus,.quote-box textarea:focus{border-color:var(--sage-400)}

/* =======================  WHY / FEATURES  ======================= */
.feat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin-top:44px}
.feat{padding:28px;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius)}
.feat .feat-ico{width:50px;height:50px;border-radius:12px;background:rgba(87, 118, 86,.10);color:var(--rust);display:grid;place-items:center;margin-bottom:16px}
.feat .feat-ico svg{width:24px;height:24px}
.feat h3{font-size:18px}
.feat p{margin-top:8px;font-size:14.5px;color:var(--muted)}

/* =======================  COVERAGE  ======================= */
.coverage{display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:center}
.coverage .cov-map{background:var(--ink);border-radius:var(--radius);overflow:hidden;position:relative;min-height:340px;display:grid;place-items:center;color:#fff}
.loc-list{display:flex;flex-direction:column;gap:16px;margin-top:26px}
.loc{display:flex;gap:16px;padding:20px;border:1px solid var(--line);border-radius:var(--radius);background:var(--paper);transition:all .25s}
.loc:hover{border-color:var(--sage-400);box-shadow:var(--shadow-sm)}
.loc .loc-ico{width:46px;height:46px;border-radius:12px;background:var(--sage-900);color:var(--sage-200);display:grid;place-items:center;flex-shrink:0}
.loc h3{font-size:17px}
.loc p{font-size:14px;color:var(--muted);margin-top:3px}

/* =======================  TESTIMONIALS  ======================= */
.tst-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin-top:44px}
.tst{padding:28px;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);display:flex;flex-direction:column}
.tst .stars{display:flex;gap:3px;color:var(--star);margin-bottom:14px}
.tst .stars svg{width:17px;height:17px}
.tst blockquote{margin:0;font-size:16px;color:var(--text);line-height:1.6;flex:1}
.tst .tst-by{display:flex;align-items:center;gap:12px;margin-top:20px;padding-top:18px;border-top:1px solid var(--line)}
.tst .avatar{width:44px;height:44px;border-radius:100px;background:var(--sage-700);color:#fff;display:grid;place-items:center;font-family:var(--font-display);font-weight:700}
.tst .tst-by b{font-size:15px}
.tst .tst-by span{font-size:13px;color:var(--muted)}

/* =======================  FAQ  ======================= */
.faq{max-width:820px;margin:44px auto 0}
.faq details{border-bottom:1px solid var(--line);padding:6px 0}
.faq summary{cursor:pointer;list-style:none;padding:18px 4px;font-family:var(--font-display);font-weight:600;font-size:18px;display:flex;justify-content:space-between;align-items:center;gap:16px}
.faq summary::-webkit-details-marker{display:none}
.faq summary .q-ico{flex-shrink:0;width:28px;height:28px;border-radius:8px;background:var(--sand-2);display:grid;place-items:center;transition:all .3s;color:var(--sage-700)}
.faq details[open] summary .q-ico{background:var(--sage-700);color:#fff;transform:rotate(45deg)}
.faq .faq-a{padding:0 4px 20px;color:var(--muted);font-size:15.5px;max-width:70ch}

/* =======================  CTA  ======================= */
.cta{position:relative;background:var(--rust);color:#fff;border-radius:var(--radius-lg);overflow:hidden;text-align:center;padding:clamp(44px,6vw,76px) 24px}
.cta::before{content:"";position:absolute;inset:0;background:radial-gradient(circle at 20% 0%,rgba(255,255,255,.14),transparent 55%)}
.cta h2{position:relative;color:#fff;font-size:clamp(28px,4vw,46px)}
/* 90% white on the sage CTA panel measured 4.47:1. 94% clears AA at 4.72:1. */
.cta p{position:relative;color:rgba(255,255,255,.94);margin:14px auto 0;max-width:52ch}
.cta .cta-btns{position:relative;display:flex;gap:14px;justify-content:center;flex-wrap:wrap;margin-top:30px}
.cta .btn-primary{background:#fff;color:var(--rust);box-shadow:none}
.cta .btn-primary:hover{background:var(--sand)}

/* =======================  FOOTER  ======================= */
footer.site{background:var(--ink);color:#b3b9bd;padding-top:64px;font-size:14.5px}
footer.site .f-top{display:grid;grid-template-columns:1.5fr 1fr 1fr 1.4fr;gap:36px;padding-bottom:44px;border-bottom:1px solid rgba(255,255,255,.1)}
footer.site .logo b{color:#fff;font-family:var(--font-display);font-size:19px}
footer.site .logo span{color:var(--sage-400);font-size:10px;letter-spacing:.28em;font-weight:600}
footer.site p{margin-top:14px;max-width:34ch;color:#969ca1;line-height:1.65}
/* The footer column headings were <h4> sitting directly under the page's <h2>
   sections, which skips h3. They are now <h2> (siblings of the main sections,
   which is what they are); the h4 selector is kept so nothing regresses if a
   stray one comes back. Appearance is unchanged. */
footer.site h2,
footer.site h4{color:#fff;font-size:13px;letter-spacing:.12em;text-transform:uppercase;margin-bottom:16px;font-family:var(--font-body);font-weight:600}
footer.site ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:11px}
footer.site ul a:hover{color:#fff}
footer.site .f-contact div{display:flex;gap:10px;align-items:flex-start;margin-bottom:14px}
footer.site .f-contact svg{width:17px;height:17px;color:var(--sage-400);flex-shrink:0;margin-top:3px}
footer.site .f-news{display:flex;gap:8px;margin-top:14px}
footer.site .f-news input{flex:1;padding:11px 13px;border-radius:9px;border:1px solid rgba(255,255,255,.16);background:rgba(255,255,255,.06);color:#fff;font-family:inherit}
footer.site .f-social{display:flex;gap:10px;margin-top:18px}
footer.site .f-social a{width:38px;height:38px;border-radius:10px;border:1px solid rgba(255,255,255,.14);display:grid;place-items:center;transition:all .2s}
footer.site .f-social a:hover{background:var(--sage-700);border-color:var(--sage-700);color:#fff}
footer.site .f-bot{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap;padding:24px 0;color:#7f858a;font-size:13.5px}
footer.site .f-bot img{height:22px;opacity:.85}
/* legal link row — privacy / terms / accessibility, on every page */
footer.site .f-legal{display:flex;flex-wrap:wrap;gap:6px 12px;align-items:center}
footer.site .f-legal a{color:#9aa1a6;transition:color .2s}
footer.site .f-legal a:hover{color:#fff;text-decoration:underline}
/* aria-hidden in the markup, but it is still rendered text, so give it the same
   4.5:1 floor as the links either side of it (#5c6266 was 2.91:1). */
footer.site .f-legal .sep{color:#8b9297;user-select:none}

/* =======================  RESPONSIVE  ======================= */
/* The ZIP form drops to two columns at 1180, not 1024. Its four tracks are
   1.3fr 1fr 1fr auto, and the auto track is the submit button, which cannot
   shrink below its own text plus 30px of side padding (262px). Measured: the
   tracks plus gaps and padding need about 1104px, so anywhere under ~1152 the
   button spilled out of the card and pushed the whole page 6px sideways — a
   horizontal scrollbar on a page that has no business scrolling sideways.
   The old 1024 breakpoint was below the width where the overflow starts. */
@media(max-width:1180px){
  .zip-card{grid-template-columns:1fr 1fr}
}
@media(max-width:1024px){
  .cat-grid,.prod-grid,.steps,.feat-grid,.tst-grid{grid-template-columns:repeat(2,1fr)}
  .band .band-inner,.coverage{grid-template-columns:1fr}
  footer.site .f-top{grid-template-columns:1fr 1fr}

  /* Once the band stacks, its full-bleed backdrop stops being a photograph.
     The panel carries the quote form, so on a phone it runs ~2,600px tall in a
     342px column: object-fit:cover crops a narrow vertical sliver out of the
     source, scales it ~12x, and .22 opacity fades what is left into the sage.
     The result is a flat green void, which is what the band looked like.
     Give the photo a bounded home at the top of the panel instead — a real
     image strip at full opacity that fades down into the copy. It also puts a
     picture before the reading, which is how the rest of the site now works. */
  .band-media{position:relative;inset:auto;height:clamp(165px,30vw,300px)}
  .band-media img{opacity:1;object-position:center 42%}
  /* cinematic.js writes an inline transform for the parallax. Harmless on an
     absolute backdrop that is clipped anyway; on an in-flow strip it slides the
     photo out of place and opens a gap, so it has to go. */
  .band-media{transform:none!important}
  /* The 90deg gradient was aimed at the desktop two-column split — it holds the
     copy side solid and lets the photo breathe on the right. In one column that
     just adds more green, so fade downward into the panel instead. */
  .band-media::after{background:linear-gradient(180deg,rgba(55,67,46,0) 45%,rgba(55,67,46,.55) 78%,var(--sage-900))}
}
/* The desktop link row gives way to the burger at 1120px, NOT at 820px.
   The wordmark is 3.53:1, so at the nav's 54px it occupies 191px — and the
   link row plus nav-right leave no room for it below ~1120. Measured on the
   live layout: the nav overflows by 79px at 1060 and by 18px at 1100, and is
   clean from 1140 up. This was always tight — the previous 2.04:1 logo fit
   the same band with 0-2px to spare — so the breakpoint, not the artwork, is
   the thing that has to move. Shrinking the logo cannot rescue it: it would
   need to be ~32px tall to fit at 1060, which is illegible.
   If the link row ever loses an item, this can come back down. */
@media(max-width:1120px){
  /* `.nav>ul` — the child combinator is load bearing. `.nav ul` also matches
     ul.call-sub, the three-yard phone dropdown, so hiding it here left a
     visible Call button on every phone that opened nothing at all. Calls
     are a primary conversion, so that was the worst place on the site to
     have a dead control. */
  .nav>ul,.nav .phone-cta{display:none}
  .nav-toggle{display:grid!important}
}
@media(max-width:820px){
  .topbar .tb-left{display:none}
}
@media(max-width:640px){
  body{font-size:16px}
  .cat-grid,.prod-grid,.steps,.feat-grid,.tst-grid,.zip-card,footer.site .f-top{grid-template-columns:1fr}
  /* A 1fr track still floors at the item's min-content width, and the product
     <select> carries long option labels — without min-width:0 the single
     column blew out to 436px and scrolled the page sideways at 375px. */
  .zip-card .field{min-width:0}
  .zip-card>*{min-width:0}
  .zip-card input,.zip-card select{min-width:0;max-width:100%}
  .hero-trust{gap:18px}
  .hero-trust .ht b{font-size:22px}
}
.nav-toggle{display:none;width:42px;height:42px;place-items:center;border:1px solid var(--line);border-radius:10px;background:var(--paper)}

/* reveal on scroll */
.reveal{opacity:0;transform:translateY(22px);transition:opacity .7s var(--ease),transform .7s var(--ease)}
.reveal.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}.reveal{opacity:1;transform:none}}

/* ---- Header phone block: never let the number wrap ------------------------
   The nav carries 10 items plus search, phone and a CTA. Below ~1250px the
   phone block is what breaks first, so it collapses to an icon button and
   then hides entirely — the number is always still in the topbar and footer. */
.nav .phone-cta{white-space:nowrap;line-height:1.15}
.nav .phone-cta small{white-space:nowrap;font-size:10.5px;letter-spacing:.01em}
.nav .phone-cta b{white-space:nowrap;font-size:16px;font-variant-numeric:tabular-nums}
.nav ul a{padding-inline:12px}
.nav{gap:18px}

@media(max-width:1350px){
  .nav ul a{padding-inline:9px;font-size:14.5px}
  .nav .phone-cta b{font-size:15px}
}
@media(max-width:1180px){
  /* drop the text phone block; keep a compact call icon instead */
  .nav .phone-cta{display:none}
  .nav .call-icon{display:grid}
}
.nav .call-icon{display:none;width:42px;height:42px;place-items:center;border-radius:10px;
  border:1px solid var(--line);background:var(--paper);color:var(--sage-700);transition:all .2s}
.nav .call-icon:hover{border-color:var(--sage-700);transform:translateY(-1px)}
.nav .call-icon svg{width:19px;height:19px}

/* ---- Nav dropdowns --------------------------------------------------------
   10 flat items overflowed the bar (needed 1401px in a 1240px container and
   pushed the CTA off-screen). Grouped into 6, two of which open on hover and
   on keyboard focus so the menu stays reachable without a pointer. */
.nav>ul{align-items:center}
.nav li{position:relative}
.nav .caret{width:13px;height:13px;margin-left:3px;opacity:.6;transition:transform .2s}
.nav .has-sub:hover > a .caret,
.nav .has-sub:focus-within > a .caret{transform:rotate(180deg)}

/* display/list-style/margin are restated here on purpose. They used to arrive
   from `.nav ul`, which was narrowed to `.nav>ul` so the burger breakpoint's
   display:none would stop matching ul.call-sub and killing the phone dropdown.
   ul.sub is a GRANDCHILD of .nav, so it lost them: the list reverted to block
   (making the gap below inert) and to the UA's second-level `circle` marker,
   which paints outside a 7px gutter and so floated in a column beside the
   panel. Restated narrowly rather than by widening .nav ul again, because a
   broad `.nav ul{padding:0}` is exactly what used to stomp .call-sub's own
   padding:7px. */
.nav ul.sub{
  display:flex;list-style:none;margin:0;
  position:absolute;top:calc(100% - 2px);left:0;min-width:212px;flex-direction:column;
  background:var(--paper);border:1px solid var(--line);border-radius:12px;
  box-shadow:var(--shadow);padding:7px;gap:1px;z-index:60;
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .18s var(--ease),transform .18s var(--ease),visibility .18s;
}
.nav .has-sub:hover > ul.sub,
.nav .has-sub:focus-within > ul.sub{opacity:1;visibility:visible;transform:none}
.nav ul.sub li{width:100%}
.nav ul.sub a{display:block;width:100%;padding:9px 13px;font-size:14.5px;border-radius:8px;white-space:nowrap}
.nav ul.sub a::after{display:none}

/* keep the whole bar on one line */
.nav ul > li > a{white-space:nowrap}

/* ---- Custom work showcase (3 photos inside the custom-builds band) -------- */
.work-gallery{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:26px}
.work-shot{margin:0;position:relative;border-radius:12px;overflow:hidden;
  border:1px solid rgba(255,255,255,.16);background:rgba(255,255,255,.05)}
.work-shot img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;
  transition:transform .5s var(--ease)}
.work-shot:hover img{transform:scale(1.06)}
/* The old gradient faded to transparent across the caption box, so where the
   text actually sits the scrim was only ~52% — white on a light photo measured
   3.91:1. Holding .82 solid behind the text and only fading above it puts the
   worst case (a blown-out white photo) at 11.7:1 regardless of the image. */
.work-shot figcaption{position:absolute;left:0;right:0;bottom:0;padding:16px 12px 9px;
  font-size:12.5px;font-weight:600;color:#fff;letter-spacing:.01em;
  background:linear-gradient(to top,rgba(9,14,16,.90) 0%,rgba(9,14,16,.82) 62%,rgba(9,14,16,0) 100%)}
@media(max-width:640px){
  .work-gallery{grid-template-columns:1fr 1fr;gap:9px}
  .work-shot:last-child{grid-column:1/-1}
}

/* ---- Header "Call" menu ---------------------------------------------------
   One compact trigger listing all three yards, so no single location gets the
   default. Keeps the nav narrow (a single number, or three, overflowed the bar)
   and keeps each number tied to its own city for local SEO. */
.call-menu{position:relative}
.call-trigger{display:inline-flex;align-items:center;gap:7px;cursor:pointer;
  font-family:inherit;font-weight:600;font-size:15px;color:var(--text);
  background:transparent;border:1.5px solid var(--line-2);border-radius:10px;
  padding:11px 14px;transition:all .2s var(--ease);white-space:nowrap}
.call-trigger:hover{border-color:var(--sage-700);color:var(--sage-600)}
.call-trigger svg{width:17px;height:17px}
.call-trigger .caret{width:13px;height:13px;opacity:.6;transition:transform .2s}
.call-menu:hover .caret,.call-menu:focus-within .caret,
.call-trigger[aria-expanded="true"] .caret{transform:rotate(180deg)}

.call-sub{position:absolute;top:calc(100% + 6px);right:0;min-width:238px;
  list-style:none;margin:0;padding:7px;display:flex;flex-direction:column;gap:1px;
  background:var(--paper);border:1px solid var(--line);border-radius:12px;
  box-shadow:var(--shadow);z-index:70;
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .18s var(--ease),transform .18s var(--ease),visibility .18s}
.call-menu:hover .call-sub,.call-menu:focus-within .call-sub,
.call-trigger[aria-expanded="true"] + .call-sub{opacity:1;visibility:visible;transform:none}
/* Dismissal escape hatch (WCAG 2.4.7 / 4.1.2). `:focus-within` above is what
   makes this menu keyboard-reachable with scripting off, but it also means the
   menu cannot be closed while the trigger still holds focus — pressing Escape,
   or clicking the trigger a second time, left the panel on screen while
   aria-expanded had already flipped to "false", so the announced state was the
   exact opposite of the visible one. cinematic.js sets .is-closed on those two
   paths and clears it on re-open. Equal specificity to the rule above (0,3,0),
   so it must stay AFTER it in source order to win. */
.call-menu.is-closed .call-sub{opacity:0;visibility:hidden;transform:translateY(-6px)}
.call-menu.is-closed .caret{transform:none}
.call-sub .call-head{padding:8px 12px 6px;font-size:11px;font-weight:600;
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted-2)}
.call-sub a{display:flex;align-items:baseline;justify-content:space-between;gap:14px;
  padding:10px 12px;border-radius:8px;transition:background .18s}
.call-sub a:hover{background:rgba(87,118,86,.10)}
.call-sub a b{font-family:var(--font-display);font-size:15px;color:var(--text)}
/* sage-600, not sage-700: these rows get a 10% sage hover tint behind them,
   where sage-700 drops to 4.47:1. */
.call-sub a span{font-size:14px;color:var(--sage-600);font-weight:600;
  font-variant-numeric:tabular-nums;white-space:nowrap}

@media(max-width:1180px){
  .call-trigger span{display:none}       /* icon-only when space is tight */
  .call-trigger{padding:11px}
}

/* ---- Header on small phones ----------------------------------------------
   These rules used to live only in catalog.css, so the three pages that don't
   load it (index, accessories, rent-to-own) kept a full-width CTA plus the
   search button in the bar and scrolled sideways at 375px. The header is
   global markup, so its responsive rules belong in the global sheet.
   Duplicating them in catalog.css is harmless — identical declarations. */
@media(max-width:560px){
  header.site .nav{gap:14px}
  header.site .nav-right{gap:10px}
  header.site .nav-right .btn-primary{display:none}  /* CTA lives in-page + topbar phone */
  header.site .nav .logo img{height:38px}
}
@media(max-width:400px){
  header.site .nav-right .icon-btn[aria-label="Search"]{display:none}
}

/* ---- Mobile navigation drawer --------------------------------------------
   Built at runtime from the desktop nav (see assets/js/mobile-nav.js), so the
   markup lives in exactly one place. */
.mnav{position:fixed;inset:0;z-index:200;background:rgba(9,14,16,.55);
  backdrop-filter:blur(3px);opacity:0;transition:opacity .24s var(--ease)}
.mnav.is-open{opacity:1}
.mnav-panel{position:absolute;top:0;right:0;bottom:0;width:min(88vw,380px);
  background:var(--paper);display:flex;flex-direction:column;
  box-shadow:-18px 0 48px -20px rgba(9,14,16,.5);
  transform:translateX(100%);transition:transform .26s var(--ease);
  overflow-y:auto;-webkit-overflow-scrolling:touch}
.mnav.is-open .mnav-panel{transform:none}

.mnav-head{display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding:16px 18px;border-bottom:1px solid var(--line);position:sticky;top:0;
  background:var(--paper);z-index:2}
.mnav-head .logo img{height:42px;width:auto}
.mnav-close{width:42px;height:42px;display:grid;place-items:center;flex-shrink:0;
  border:1px solid var(--line);border-radius:10px;background:var(--paper);
  color:var(--text);cursor:pointer;transition:all .2s}
.mnav-close:hover{border-color:var(--ink)}
.mnav-close svg{width:20px;height:20px}

.mnav-links{padding:12px 12px 4px;display:flex;flex-direction:column;gap:2px}
.mnav-link{display:block;padding:13px 14px;border-radius:10px;font-weight:600;
  font-size:16.5px;color:var(--text);transition:background .18s}
.mnav-link:hover,.mnav-link.is-active{background:rgba(87,118,86,.10);color:var(--sage-600)}

.mnav-group{padding:14px 12px 4px;display:flex;flex-direction:column;gap:2px}
.mnav-grouplabel{padding:0 14px 7px;font-size:11px;font-weight:600;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted-2)}
.mnav-sublink{display:block;padding:12px 14px;border-radius:10px;font-size:15.5px;
  color:var(--text);transition:background .18s}
.mnav-sublink:hover{background:rgba(87,118,86,.10);color:var(--sage-600)}

.mnav-calls{border-top:1px solid var(--line);margin-top:10px;padding-top:16px}
.mnav-call{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:12px 14px;border-radius:10px;transition:background .18s}
.mnav-call:hover{background:rgba(87,118,86,.10)}
.mnav-call b{font-family:var(--font-display);font-size:15.5px;color:var(--text)}
.mnav-call span{font-size:14.5px;font-weight:600;color:var(--sage-600);
  font-variant-numeric:tabular-nums;white-space:nowrap}

.mnav-foot{margin-top:auto;padding:16px 18px calc(18px + env(safe-area-inset-bottom));
  border-top:1px solid var(--line);position:sticky;bottom:0;background:var(--paper)}

@media(prefers-reduced-motion:reduce){
  .mnav,.mnav-panel{transition:none}
}

/* ---- Photo gallery for product pages --------------------------------------
   Light-background variant of .work-gallery. Drop real photos into
   assets/img/ and swap the three src paths in each page's <section id="gallery">. */
.photo-gallery{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:36px}
.photo-shot{margin:0;position:relative;border-radius:var(--radius);overflow:hidden;
  border:1px solid var(--line);background:var(--sand-2);box-shadow:var(--shadow-sm);
  transition:transform .3s var(--ease),box-shadow .3s var(--ease)}
.photo-shot:hover{transform:translateY(-4px);box-shadow:var(--shadow)}
.photo-shot img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;
  transition:transform .5s var(--ease)}
.photo-shot:hover img{transform:scale(1.05)}
/* Same fix as .work-shot: the caption used to sit on a ~51% scrim, which put
   white text at 3.81:1 over a light photo. Now floored at .82 behind the text. */
.photo-shot figcaption{position:absolute;left:0;right:0;bottom:0;padding:18px 14px 11px;
  font-size:13px;font-weight:600;color:#fff;
  background:linear-gradient(to top,rgba(9,14,16,.90) 0%,rgba(9,14,16,.82) 62%,rgba(9,14,16,0) 100%)}
@media(max-width:900px){
  .photo-gallery{grid-template-columns:1fr 1fr;gap:12px}
  .photo-shot:last-child{grid-column:1/-1}
}
@media(max-width:560px){
  .photo-gallery{grid-template-columns:1fr}
  .photo-shot:last-child{grid-column:auto}
}

/* =========================================================================
   ACCESSIBILITY LAYER  (WCAG 2.1 AA)
   Added by the accessibility audit. Everything below is additive — it does not
   restyle any component, it only makes existing components operable and
   perceivable. Lives in styles.css because this is the only sheet all pages
   load (catalog.css / local.css / legal.css are page-specific).
   ========================================================================= */

/* ---- Visually-hidden text -------------------------------------------------
   Was defined only in catalog.css, which index.html, accessories.html and
   rent-to-own.html do not load — so an .sr-only label on those pages rendered
   as visible text. Defined here so it works everywhere. The catalog.css copy is
   left in place; the declarations are identical, so the duplicate is harmless. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

/* ---- Skip link (WCAG 2.4.1 Bypass Blocks) --------------------------------
   Every page opens with a topbar, a 10-item nav and a hero before the content
   starts. This lets a keyboard user jump straight to <main>. */
.skip-link{position:absolute;left:8px;top:-60px;z-index:300;
  padding:12px 18px;border-radius:0 0 10px 10px;
  background:var(--ink);color:#fff;font-weight:600;font-size:15px;
  text-decoration:none;transition:top .18s var(--ease)}
.skip-link:focus{top:0}
/* main is a scroll target for the skip link; don't ring it when it takes focus */
main:focus{outline:none}

/* ---- Visible focus indicator (WCAG 2.4.7 Focus Visible) -------------------
   Four rules in this codebase set `outline:none` on :focus and replaced it with
   a border-colour change only, which is not a reliable focus indicator. The
   baseline below applies to anything focusable by keyboard; :focus-visible
   means mouse users still never see a ring.
   Two rings are drawn — a dark outline plus a white box-shadow halo — so the
   indicator stays visible on the sand page, on white cards AND on the dark
   header/hero/locbar without needing a per-surface rule. */
:where(a,button,input,select,textarea,summary,[tabindex]):focus-visible{
  outline:3px solid var(--sage-600);
  outline-offset:2px;
  border-radius:4px;
}
/* on dark surfaces the sage ring alone is low-contrast against near-black —
   add a light halo so the indicator reads on both */
.topbar :focus-visible,
header.site :focus-visible,
.hero :focus-visible,
.page-hero :focus-visible,
.band :focus-visible,
.cinema :focus-visible,
.locbar :focus-visible,
.cta :focus-visible,
footer.site :focus-visible,
.yard-cross :focus-visible{
  outline-color:#fff;
  box-shadow:0 0 0 6px rgba(9,14,16,.55);
}
/* the FAQ rows hide the native marker and are the main keyboard target on most
   pages — give the ring a little breathing room so it isn't clipped */
.faq summary:focus-visible{outline-offset:-2px;border-radius:8px}

/* Forms that previously killed the ring outright. Keeping the border tint as a
   secondary cue, but the ring above now always draws. */
.quote-box input:focus-visible,
.quote-box select:focus-visible,
.quote-box textarea:focus-visible{outline-color:#fff}

/* ---- Don't let a reveal strand its content --------------------------------
   .reveal / .stagger start at opacity:0 and only become visible when
   cinematic.js adds .in, so with scripting off the page renders large blank
   bands. The counterpart to this is the <noscript> block in each page's
   <head>, which force-shows them.

   Why <noscript> and not an html.js class: cinematic.js is loaded at the end of
   <body>, so a class it sets would arrive after first paint — content would
   flash in, snap out, then fade back. And an inline <head> script is off the
   table because this codebase is deliberately keeping `script-src 'self'`
   viable with no 'unsafe-inline' (see the note above the zip-quote scripts).
   <noscript> needs no script execution at all and cannot flash.

   The rules themselves live in that <noscript><style> block rather than here,
   because <noscript> in <head> can only carry <style>/<link>/<meta> — it cannot
   set a class for a selector here to hook. Keep the two in sync:

     .reveal,.reveal-scale,.reveal-left,.reveal-right,.stagger>*
       { opacity:1!important; transform:none!important; filter:none!important; }

   cinematic.js additionally force-shows everything when the browser has no
   IntersectionObserver, which covers the other way this could strand. */

/* ---- Rating stars ---------------------------------------------------------
   The five star glyphs are decorative once the rating is also given in text
   (see the .sr-only span added next to each set in the markup). */
.stars svg{flex-shrink:0}


/* ---- No-JavaScript notices --------------------------------------------------
   Shown only from inside <noscript>, where the interactive control they replace
   has been hidden. Styled as an ordinary notice rather than an error: scripting
   being off is a legitimate way to browse, not a fault of the visitor's. */
.nojs-note{
  margin:18px 0;padding:16px 18px;
  border:1px solid var(--line);border-left:4px solid var(--sage-600);
  border-radius:10px;background:var(--paper);
  font-size:15px;line-height:1.65;color:var(--ink)
}
/* sage-600 (6.86:1 on white), not sage-700 (5.08:1) — this notice carries the
   phone numbers a no-JS visitor needs, so it gets the stronger of the two. */
.nojs-note a{color:var(--sage-600);font-weight:600}

/* Fallback shown in place of the GoHighLevel iframe when scripting is off. It
   sits inside .quote-box, which is a dark translucent panel, so it needs light
   text rather than the .nojs-note treatment used on light backgrounds. */
.nojs-quote{
  margin:0;padding:14px 16px;border-radius:10px;
  background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.18);
  color:rgba(255,255,255,.92);font-size:14.5px;line-height:1.6
}
.nojs-quote a{color:#fff;font-weight:600}

/* =========================================================================
   QUOTE FORM IFRAME HEIGHT
   -------------------------------------------------------------------------
   GoHighLevel never posts its height to us. assets/js/ghl-autosize.js listens
   for that message, but it only arrives if you load GHL's own form_embed.js —
   which we deliberately do not, because it would need script-src access to
   every page. Verified on the live site: zero messages received.

   So the height is ours to set, and it has to be RIGHT, because a box smaller
   than the form makes the form scroll inside itself — a visitor scrolling in a
   box inside a scrolling page, on the one element that captures leads. The old
   1180px was too small at every width.

   Measured against the real form: 300px wide -> 1530 tall · 467 -> 1310 ·
   543 -> 1270 · 690 -> 1210. Narrower means taller, because GHL stacks every
   field full-width and the two consent paragraphs wrap. Values below carry a
   ~30px margin. Re-measure if fields are added or the consent text changes.
   ========================================================================= */
#ghl-quote-form{min-height:1300px}          /* form ~543px wide */
@media(max-width:1199px){
  #ghl-quote-form{min-height:1350px}        /* form ~467px — narrowest two-column */
}
@media(max-width:899px){
  #ghl-quote-form{min-height:1250px}        /* stacks full width, so it gets wider */
}
@media(max-width:560px){
  #ghl-quote-form{min-height:1580px}        /* phones: ~300px wide, tallest case */
}

/* On a phone the form was left 208px wide: the container, the band padding and
   the quote-box padding together ate 182px of a 390px screen. GoHighLevel
   stacks fields full-width, so a narrower box is a TALLER box — 208px wide
   needed 1,580px of height. Giving the padding back buys width, which buys
   height back, on the one element that captures leads. */
@media(max-width:560px){
  .band .band-inner{padding:18px}
  .quote-box{padding:14px}
}

/* The quote CTAs used to jump to the SECTION that contains the form (#custom /
   #custom-build). On desktop the form sits beside the copy so that looked fine,
   but on a phone it stacks ~830px below — so "Request Quote" landed the visitor
   on a heading with no form in sight, on the site's main conversion path.
   They now target the form box itself; this keeps its heading clear of the
   sticky header when they arrive. */
#quote-form{scroll-margin-top:96px}
@media(max-width:820px){ #quote-form{scroll-margin-top:76px} }
