/* ============================================================
   Geaux 2 Guy Renovations, Columbia SC. Design system.

   Palette read verbatim from the client's own logo file
   (logo-main-DAZ06Gkt.svg): #16fd18 / #2cca2d green and
   #fffd02 / #fefb06 yellow. Neither neon is legible on white,
   so the ground is a near-black with a green cast (the truck
   wrap), the neon green and yellow live on dark, and a deepened
   green (#0B7D0F, 5.3:1 on white) carries text and buttons.

   Brand devices, all drawn from the mark:
     1. CHAMFER. The wordmark's letters have cut corners, so
        buttons, cards, badges and photo frames are chamfered
        rather than rounded.
     2. THE TRIANGLE. The G2G monogram sits inside a circle as a
        downward triangle. It reappears as a ghost watermark in
        dark bands and as the bullet and step marker.
     3. TAPE SEAM. A green rule with a yellow tick, the way the
        truck wrap splits green from yellow, sits under every
        section title and along band edges.

   Fonts: Francois One (display) + Barlow (body).

   THE DISPLAY FACE WAS CHANGED 2026-09-05. It was Chakra Petch,
   picked because its squared, chamfered terminals echo the
   wordmark. Echoing the logo was the wrong test. Chakra Petch is
   a technical face, and on a page it reads as a spec sheet or a
   game menu, not as a Columbia remodeler's work van. It also has
   to carry 14px eyebrows, 15px nav links and an 18px SENTENCE
   CASE FAQ question, which is exactly where a squared display
   face is weakest.

   Francois One is a sturdy, slightly
   condensed grotesque that reads like lettering on a work van: it
   has weight and warmth without being a costume. Auditioned
   against Roboto Condensed, Changa and Cairo on the REAL home page
   and the REAL FAQ page at 1366 and 375, see _qa/audition. It won
   on the hard test, the 18px sentence-case FAQ question, where the
   squared faces turn brittle.

   Anton was excluded on purpose: a recent sibling build already
   shipped Anton with Nunito Sans, and no combo is reused on
   consecutive builds. Bebas Neue was excluded because it has
   no true lowercase and this stylesheet sets the display face on a
   sentence-case question. Montserrat is what the client's current
   site already uses.

   FRANCOIS ONE IS SINGLE WEIGHT (400 only). Every rule that uses
   --font-display is therefore set to 400. Ask it for 700 and the
   browser fakes a bold and the headings smear. _qa.js gate 1
   checks that the weights the CSS asks for are weights Google
   actually serves, so this cannot drift.

   Barlow stays on body: it is on the approved list, and a normal
   width body under a heavier display keeps the two distinct.
   ============================================================ */

:root {
  --ink: #0F1511;
  --ink-2: #16201A;
  --ink-3: #1F2C24;
  --ink-line: #2C3B31;

  --grn: #16FD18;
  --grn-mid: #2CCA2D;
  --grn-deep: #0B7D0F;
  --grn-deep-hover: #096409;
  --grn-soft: rgba(22, 253, 24, 0.12);
  --grn-tint: #EAFBEA;

  --amber: #FFFD02;
  --amber-mid: #FEFB06;
  --amber-soft: rgba(255, 253, 2, 0.14);

  --color-bg: #FFFFFF;
  --color-surface: #F4F6F3;
  --color-text: #1B221D;
  --color-text-light: #59635C;
  --color-text-on-dark: #FFFFFF;
  --color-text-on-dark-muted: #A9B6AD;
  --color-border: #E1E6E0;
  --color-google-star: #FBBC04;

  /* ==========================================================
     SURFACE-SCOPED TEXT TOKENS.  Added 2026-09-05.

     THE BUG THESE EXIST TO KILL. Every colour above names a
     COLOUR. None of them names a SURFACE. So the dark band set
     "color: #fff" and ".band p { color: #C6D1C9 }" on itself and
     both inherited straight into the WHITE cards nested inside
     it. That produced, on 23 of the 28 pages:
       .form-card__sub and .form-card__note  1.57:1
       .review-card__text                    1.57:1
       the reviewer's name, white on white    1.00:1
       the phone number, amber on white       1.09:1
     288 unreadable text runs, from five rules, all of them the
     same mistake made once.

     THE FIX. These four tokens do not mean a colour. They mean
     "whatever is legible on the surface I am painted on". Light
     is the default here. A dark band re-points all four. A light
     card nested inside a dark band re-points them BACK, so the
     leak cannot happen again no matter how deeply anything is
     nested, and no matter which descendant selector reaches in.

     Every ratio below is measured, not estimated, by _contrast.js
     against real rendered pixels:
       #1B221D on white 16.24   on #F4F6F3 14.94
       #59635C on white  6.24   on #F4F6F3  5.74
       #0B7D0F on white  5.31   on #F4F6F3  4.89
       #FFFFFF on #0F1511 18.49    #C6D1C9 on #0F1511 11.77
       #FFFD02 on #0F1511 17.00    #16FD18 on #0F1511 13.29
     ========================================================== */
  --txt: #1B221D;          /* body and headings on this surface */
  --txt-muted: #59635C;    /* secondary copy on this surface */
  --txt-link: #0B7D0F;     /* links, phone numbers on this surface */
  --txt-accent: #0B7D0F;   /* eyebrow / subtitle on this surface */

  --font-display: 'Francois One', 'Arial Narrow', sans-serif;
  --font-body: 'Barlow', 'Helvetica Neue', sans-serif;

  --container-width: 1200px;
  --section-pad: 96px;
  --nav-h: 74px;
  /* Height of the fixed mobile call bar. Zero above 900px, where there is no
     bar. The mobile block below sets the real measured value, and the nav
     offset, the body padding and the drawer header all read it, so they can
     never drift apart from the bar again. */
  --cta-bar-h: 0px;

  --chamfer: 14px;
  --chamfer-sm: 9px;

  --shadow-sm: 0 2px 10px rgba(15, 21, 17, 0.08);
  --shadow-md: 0 10px 30px rgba(15, 21, 17, 0.13);
  --shadow-lg: 0 18px 46px rgba(15, 21, 17, 0.18);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --speed: 0.4s;

  /* the G2G triangle, used as a ghost watermark on dark bands */
  --tri: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cg fill='none' stroke='%2316FD18' stroke-width='5'%3E%3Ccircle cx='100' cy='100' r='84'/%3E%3Cpath d='M44 62h112L100 154z'/%3E%3Cpath d='M76 62v34M124 62v34M100 96v34'/%3E%3C/g%3E%3C/svg%3E");
}

/* ============================================================
   SURFACE SCOPING. Read this before adding any coloured surface.

   RULE ONE. A surface that changes its own background MUST also
   re-point the four text tokens. Otherwise the text painted on it
   is being coloured for somebody else's background.

   RULE TWO. A LIGHT card that can be nested inside a dark surface
   MUST appear in the light-reset list below. That list is the
   whole defence. .form-card and .review-card both live inside
   .band on this site, and leaving them out is precisely how 288
   unreadable text runs shipped.

   Custom properties resolve on the element that uses them, so
   ".band p { color: var(--txt-muted) }" gives #C6D1C9 for a
   paragraph on the band itself and #59635C for the same paragraph
   inside a white .form-card. One rule, correct on both surfaces.
   ============================================================ */
.band, .section--dark, .footer, .nav, .utility-bar, .nav__links, .nav__dropdown-menu, .hero {
  --txt: #FFFFFF;
  --txt-muted: #C6D1C9;
  --txt-link: var(--amber);
  --txt-accent: var(--grn);
}
/* The CTA banner is mid-green, not near-black, so #C6D1C9 would drop
   to 3.38:1 there. It gets its own near-white muted, #EEF6EE, which
   measures 4.82:1 on #0B7D0F. That is the tightest pairing on the whole
   site: it clears the 4.5 body-text bar with 0.32 to spare, so if this
   green ever darkens or that grey ever lightens, this is the first
   thing that breaks. An earlier version of this comment claimed 4.94:1,
   a number nobody had computed. The sweep measured 4.82 and the
   arithmetic agrees at 4.818. */
.cta-section {
  --txt: #FFFFFF;
  --txt-muted: #EEF6EE;
  --txt-link: var(--amber);
  --txt-accent: var(--amber);
}
/* THE LIGHT RESET. Every white or near-white card, wherever it sits. */
.form-card, .review-card, .quote-card, .lead-form, .faq-item, .area-card,
.icon-card, .svc-card, .step, .trust-strip, .fact-row, .pull-quote, .link-card,
.gallery-item, .review-widget, .specials-card, .section--surface {
  --txt: #1B221D;
  --txt-muted: #59635C;
  --txt-link: var(--grn-deep);
  --txt-accent: var(--grn-deep);
  color: var(--txt);
}

/* ============================================================
   SECTION PADDING LADDER. Added 2026-09-05.

   --section-pad was 96px at every width. On a 390px phone every band
   paid 96px top and 96px bottom, which is double what the reference
   reference estate runs (measured 2026-09-05 on 13 live homepages: 48px
   at phone width, 64 at 768 and 1024, 68 at 1440). Desktop keeps 96; the
   phone lands on 48. Same ladder the sister sites use.
   ============================================================ */
@media (max-width: 1024px) { :root { --section-pad: 76px; } }
@media (max-width: 767px)  { :root { --section-pad: 58px; } }
@media (max-width: 480px)  { :root { --section-pad: 48px; } }

/* ============ reset ============ */
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; overflow-x: clip; }
body {
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.65;
  color: var(--txt);
  background: var(--color-bg);
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--txt-link); }
ul, ol { list-style: none; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  line-height: 1.06;
  letter-spacing: 0.005em;
  color: var(--txt);
}
h1 { font-size: clamp(33px, 5vw, 60px); }
h2 { font-size: clamp(27px, 3.5vw, 42px); }
h3 { font-size: clamp(19px, 2vw, 23px); }
h4 { font-size: 17px; letter-spacing: 0.05em; }
p + p { margin-top: 15px; }
strong { font-weight: 700; }

.container { width: 100%; max-width: var(--container-width); margin: 0 auto; padding: 0 24px; }
.section { padding: var(--section-pad) 0; position: relative; }
.section--surface { background: var(--color-surface); }
.section--tight { padding: 62px 0; }
.text-center { text-align: center; }
.prose { max-width: 820px; }
.prose p { color: var(--txt-muted); }
.prose h2 { margin-bottom: 18px; }

.section-subtitle {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 14px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--txt-accent);
  margin-bottom: 10px;
}
.section-title { margin-bottom: 18px; }
/* device 3: green tape rule with a yellow tick */
.section-title--underline { position: relative; padding-bottom: 20px; }
.section-title--underline::after {
  content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
  width: 96px; height: 5px;
  background: linear-gradient(90deg, var(--grn-deep) 0 66px, var(--amber-mid) 66px 78px, var(--grn-deep) 78px 96px);
}
.section-title--underline.left::after { left: 0; transform: none; }
.section--dark .section-title, .band .section-title, .cta-section h2 { color: var(--txt); }
/* the eyebrow now reads --txt-accent, which the surface itself sets, so the
   old dark-only override is gone rather than duplicated. */
.band .section-title--underline::after {
  background: linear-gradient(90deg, var(--grn) 0 66px, var(--amber) 66px 78px, var(--grn) 78px 96px);
}

/* ============ buttons (device 1: chamfer) ============ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--font-display); font-weight: 400; font-size: 16px;
  letter-spacing: 0.06em; text-transform: uppercase; text-decoration: none;
  padding: 15px 30px; border: 2px solid transparent; cursor: pointer;
  transition: background var(--speed) var(--ease), color var(--speed) var(--ease), transform var(--speed) var(--ease);
  clip-path: polygon(var(--chamfer) 0, 100% 0, 100% calc(100% - var(--chamfer)), calc(100% - var(--chamfer)) 100%, 0 100%, 0 var(--chamfer));
  min-height: 52px;
}
.btn:hover { transform: translateY(-2px); }
.btn--primary { background: var(--grn-deep); color: #fff; }
.btn--primary:hover { background: var(--grn-deep-hover); color: #fff; }
.btn--dark { background: var(--ink); color: #fff; }
.btn--dark:hover { background: var(--ink-3); color: #fff; }
.btn--outline { background: transparent; color: var(--ink); border-color: var(--ink); clip-path: none; }
.btn--outline:hover { background: var(--ink); color: #fff; }
.btn--outline-light { background: transparent; color: #fff; border-color: rgba(255,255,255,0.55); clip-path: none; }
.btn--outline-light:hover { background: #fff; color: var(--ink); border-color: #fff; }
.btn--amber { background: var(--amber-mid); color: var(--ink); }
.btn--amber:hover { background: #ece900; color: var(--ink); }
.btn--sm { padding: 10px 18px; font-size: 14px; min-height: 42px; --chamfer: 9px; }
.btn-pair { display: flex; flex-wrap: wrap; gap: 14px; }

/* ============ utility bar ============ */
.utility-bar {
  background: var(--ink); color: var(--txt-muted);
  font-size: 13.5px; padding: 9px 0; border-bottom: 1px solid var(--ink-line);
}
.utility-bar .container { display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap; }
.utility-bar__item { display: inline-flex; align-items: center; gap: 7px; }
.utility-bar__item svg { width: 15px; height: 15px; color: var(--grn); flex-shrink: 0; }
.utility-bar__actions { display: flex; align-items: center; gap: 20px; }
.utility-bar__phone { display: inline-flex; align-items: center; min-height: 26px; color: var(--txt-link); font-family: var(--font-display); font-weight: 400; letter-spacing: 0.04em; text-decoration: none; font-size: 15px; }
.utility-bar__phone:hover { color: #fff; }
@media (max-width: 900px) { .utility-bar { display: none; } }

/* ============ nav ============ */
.nav {
  position: sticky; top: 0; z-index: 90; background: var(--ink);
  border-bottom: 2px solid var(--ink-line); transition: box-shadow var(--speed) var(--ease);
}
.nav.scrolled { box-shadow: 0 6px 22px rgba(0,0,0,0.32); }
.nav .container { display: flex; align-items: center; gap: 20px; min-height: var(--nav-h); }
.nav__logo { display: flex; align-items: center; flex-shrink: 0; }
.nav__logo img { height: 56px; width: auto; }
.nav__links { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.nav__link, .nav__dropdown-toggle {
  font-family: var(--font-display); font-weight: 400; font-size: 15px;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--txt); white-space: nowrap;
  background: none; border: 0; cursor: pointer; padding: 13px 13px; min-height: 44px;
  text-decoration: none; display: inline-flex; align-items: center; gap: 6px;
  transition: color var(--speed) var(--ease);
}
.nav__link:hover, .nav__dropdown-toggle:hover { color: var(--grn); }
.nav__dropdown { position: relative; }
.nav__dropdown-menu {
  position: absolute; top: calc(100% + 6px); left: 0; min-width: 268px;
  background: var(--ink-2); border: 1px solid var(--ink-line);
  padding: 8px; opacity: 0; visibility: hidden; transform: translateY(-8px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease), visibility 0.3s;
  box-shadow: var(--shadow-lg);
}
.nav__dropdown:hover .nav__dropdown-menu { opacity: 1; visibility: visible; transform: translateY(0); }
.nav__dropdown-item {
  display: flex; align-items: center; min-height: 46px; padding: 9px 13px; color: var(--txt-muted); text-decoration: none;
  font-size: 15px; font-weight: 500; border-left: 3px solid transparent;
  transition: all 0.25s var(--ease);
}
.nav__dropdown-item:hover { background: var(--ink-3); color: var(--grn); border-left-color: var(--grn); }
.nav__actions { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.nav__hamburger { display: none; background: none; border: 0; cursor: pointer; padding: 8px; margin-left: auto; }
.nav__hamburger span { display: block; width: 26px; height: 3px; background: var(--grn); margin: 5px 0; transition: all 0.3s var(--ease); }
.nav__hamburger.active span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.nav__hamburger.active span:nth-child(2) { opacity: 0; }
.nav__hamburger.active span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }
.nav-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.55); opacity: 0; visibility: hidden; transition: all 0.3s; z-index: 88; }
.nav-overlay.active { opacity: 1; visibility: visible; }

/* The drawer close control. Hidden on desktop, a real 46x46 button on mobile. */
.nav__close { display: none; }

/* ============================================================
   OPEN DRAWER STACKING.

   .nav is position:sticky with a z-index, so it creates its own stacking
   context: everything inside it, drawer AND hamburger, is trapped there and
   the fixed call bar (z 95) paints on top of the lot. Two consequences were
   shipping: the drawer's top strip sat behind the call bar, so a tap on the
   first menu group dialled the business, and .nav__links (z 89) covered the
   hamburger (z auto) so the menu could not be closed with the control that
   opened it.

   Fix: while the drawer is open lift the WHOLE nav above the call bar, put the
   backdrop above the call bar too so nothing behind the drawer is tappable,
   and lift the hamburger above the drawer inside the nav's own context.
   ============================================================ */
/* THE SCROLL LOCK GOES ON THE ROOT, NEVER ON BODY.
   overflow:hidden on <body> takes the scrollport off the body box, and
   position:sticky on .nav is measured against it, so the nav came unpinned the
   moment the drawer opened: at scroll 3000 the hamburger's own rect moved to
   y=-2889, right off the screen. That is a large part of why the hamburger
   could not be tapped to close the menu. Locking the root instead keeps the
   nav stuck to the top of the viewport with the drawer open. */
html.menu-open { overflow: hidden; }
body.menu-open .nav { z-index: 1200; }
body.menu-open .nav-overlay { z-index: 1150; }

@media (max-width: 1100px) {
  .nav__actions { display: none; }
  .nav__hamburger { display: block; position: relative; z-index: 120; }
  .nav__links {
    position: fixed; top: 0; right: 0; bottom: 0; width: min(340px, 86vw);
    background: var(--ink); flex-direction: column; align-items: stretch;
    gap: 0; padding: 84px 18px 32px; overflow-y: auto; z-index: 89;
    transform: translateX(105%); transition: transform 0.35s var(--ease); margin-left: 0;
  }
  .nav__links.open { transform: translateX(0); }
  /* The close control sits on the drawer's own header row, LEFT side, level
     with the hamburger on the right. Top right is where the hamburger already
     is, and the hamburger has to stay visible and tappable while the drawer is
     open, so putting a second control there stacked two near-identical glyphs
     6px apart. Left keeps them apart at every width, with or without the call
     bar, and the drawer's top padding clears both. */
  .nav__close {
    display: grid; place-items: center; position: absolute;
    top: 15px; left: 14px; right: auto;
    width: 46px; height: 46px; padding: 0; z-index: 3; cursor: pointer;
    background: var(--ink-2); border: 1px solid var(--ink-line); color: var(--grn);
    transition: background var(--speed) var(--ease), color var(--speed) var(--ease);
  }
  .nav__close svg { width: 22px; height: 22px; }
  .nav__close:hover, .nav__close:focus-visible { background: var(--ink-3); color: #fff; }
  /* The drawer's X and the hamburger's own X-morph landed 6px apart in the
     same corner and read as two of the same control. The hamburger has to
     stay visible and tappable while the drawer is open, so it keeps its bars
     and takes the amber active tint instead of becoming a second X. */
  .nav__hamburger.active span:nth-child(1) { transform: none; }
  .nav__hamburger.active span:nth-child(2) { opacity: 1; }
  .nav__hamburger.active span:nth-child(3) { transform: none; }
  .nav__hamburger.active span { background: var(--amber-mid); }
  .nav__link, .nav__dropdown-toggle { width: 100%; justify-content: space-between; padding: 14px 8px; border-bottom: 1px solid var(--ink-line); }
  .nav__dropdown-menu {
    position: static; opacity: 1; visibility: visible; transform: none;
    max-height: 0; overflow: hidden; padding: 0; border: 0; box-shadow: none;
    background: var(--ink-2); transition: max-height 0.35s var(--ease);
  }
  .nav__dropdown.open .nav__dropdown-menu { max-height: 520px; padding: 6px; }
}

/* ============ mobile sticky CTA ============ */
/* The call bar was 47.094px tall (12px padding, a 23.094px line box, 12px
   padding) while .nav sat at top:44px and body at padding-top:44px. Three
   pixels of the nav were tucked under the bar at every scroll position. The
   bar is now pinned to an exact height with --cta-bar-h, and the nav offset
   and the body padding both read that same variable, so they cannot drift
   apart again when a font or a font-size changes. Measured at 375, 414 and
   768px: bar 48.00px, nav top 48px, body padding-top 48px. */
.mobile-cta-bar { display: none; }
@media (max-width: 900px) {
  :root { --cta-bar-h: 48px; }   /* measured: the bar renders at exactly 48.00px */
  .mobile-cta-bar {
    display: grid; grid-template-columns: 1fr 1fr; gap: 2px; height: var(--cta-bar-h); box-sizing: content-box; padding-bottom: env(safe-area-inset-bottom, 0px);
    position: fixed; bottom: 0; left: 0; right: 0; z-index: 95; background: var(--ink-line);
  }
  .mobile-cta-bar a {
    display: flex; align-items: center; justify-content: center;
    text-align: center; padding: 0 8px; line-height: 1.15; font-family: var(--font-display);
    font-weight: 400; font-size: 14px; letter-spacing: 0.06em; text-transform: uppercase; text-decoration: none;
  }
  .mobile-cta-bar__primary { background: var(--grn-deep); color: #fff; }
  .mobile-cta-bar__call { background: var(--amber-mid); color: var(--ink); }
  body .nav { top: 0; }
  body { padding-bottom: calc(var(--cta-bar-h) + env(safe-area-inset-bottom, 0px)); }
}

/* ============ hero ============ */
.hero { position: relative; background: var(--ink); color: #fff; overflow: hidden; }
.hero::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image: var(--tri); background-repeat: no-repeat;
  background-position: right -90px top -60px; background-size: 460px; opacity: 0.06;
}
.hero__content { position: relative; z-index: 2; max-width: 720px; padding: 74px 0 88px; }
.hero__title { color: var(--txt); margin: 14px 0 12px; }
.hero__count { font-family: var(--font-display); font-weight: 400; font-size: 17px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--txt-link); margin-bottom: 14px; }
.hero__text { font-size: 18.5px; color: var(--txt-muted); max-width: 620px; }
.hero__actions { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 30px; }

.hero--split { display: block; }
.hero--split .hero__photo { position: absolute; inset: 0 0 0 auto; width: 46%; }
.hero--split .hero__photo img { width: 100%; height: 100%; object-fit: cover; }
.hero--split .hero__photo::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, var(--ink) 0%, rgba(15,21,17,0.72) 26%, rgba(15,21,17,0.12) 68%);
}
.hero--split .hero__content { max-width: 620px; padding: 88px 0 100px; }
/* PHONE AND TABLET HERO. The photo used to become a 260px strip ABOVE a
   black text panel, which read as a header image, not a hero. The reference
   estate never does that: the photograph stays full-bleed UNDER the headline at
   every width with a brand wash over it (measured median 0.85). So below
   980px the same photo goes to cover, behind the text, under a wash of the
   site's own ink that runs 0.80 at the top to 0.92 at the bottom. Worst
   case for contrast is a pure white photo pixel under the 0.80 end:
   0.80 x #0F1511 + 0.20 x #FFF = about rgb(63,68,65), and white text on
   that measures 9.9:1, the muted #C6D1C9 6.3:1, the amber 9.1:1. All of
   it clears 4.5 with room, and _contrast.js re-measures the real pixels. */
@media (max-width: 980px) {
  .hero--split .hero__photo { position: absolute; inset: 0; width: 100%; height: 100%; }
  .hero--split .hero__photo img { width: 100%; height: 100%; object-fit: cover; object-position: center 40%; }
  .hero--split .hero__photo::after { background: linear-gradient(180deg, rgba(15,21,17,0.80) 0%, rgba(15,21,17,0.86) 55%, rgba(15,21,17,0.92) 100%); }
  .hero--split .hero__content { padding: 44px 0 52px; }
}
@media (max-width: 767px) {
  .hero--split .hero__content { padding: 32px 0 40px; }
  .hero__actions { margin-top: 24px; gap: 10px; }
  .hero__actions .btn { flex: 1 1 auto; }
}

.hero--sub .hero__bg {
  position: absolute; inset: 0; background-size: cover; background-position: center;
}
.hero--sub .hero__bg::after { content: ''; position: absolute; inset: 0; background: linear-gradient(100deg, rgba(15,21,17,0.94) 0%, rgba(15,21,17,0.86) 42%, rgba(15,21,17,0.58) 100%); }
.hero--sub .hero__content { padding: 46px 0 66px; }
.hero--nophoto { background: var(--ink) linear-gradient(140deg, var(--ink) 0%, var(--ink-3) 100%); }

.hero__slope { position: absolute; bottom: -1px; left: 0; width: 100%; line-height: 0; z-index: 3; }
.hero__slope svg { display: block; width: 100%; height: 46px; }

.breadcrumbs { position: relative; z-index: 2; padding-top: 22px; font-size: 14px; color: #A9B6AD; }
.breadcrumbs ol { display: flex; gap: 9px; flex-wrap: wrap; align-items: center; }
.breadcrumbs a, .breadcrumbs .current { display: inline-flex; align-items: center; min-height: 26px; }
.breadcrumbs a { color: #A9B6AD; text-decoration: none; }
.breadcrumbs a:hover { color: var(--grn); }
.breadcrumbs .current { color: var(--txt); }

/* review badges, mandatory in every hero */
/* ===== HERO RATING BADGE ROW =============================================
   The row NEVER wraps and NEVER stacks, at any width, at any badge count.

   What broke before: each badge was an HTML lockup, a logo beside a couple of
   spans of text. An HTML lockup cannot compress narrower than its own words,
   so two of them would not fit a phone column and the row fell into a stack.

   What fixes it: each badge is now one inline <svg viewBox="0 0 193 60">. An
   SVG with a viewBox has NO minimum content width, so it shrinks freely, the
   same way the flat image badges on the reference sites do. Three properties
   carry that, and removing ANY ONE of them puts the stacking back:
     flex: 1 1 0     each badge takes an equal share of the row
     min-width: 0    permits shrinking below content size. The forgotten one.
     max-width       stops a lone badge ballooning across the whole row
   Measured on a real 375px phone: 1 badge 193px, 2 badges 178px each,
   3 badges 117px each, 4 badges 86px each. One row every time.

   _gate-badge-row.js re-measures all of this in a real browser at 375, 414
   and 768 and fails the build if the row ever uses more than one line. */
:root {
  --rbadge-ink: var(--color-text-on-dark);  /* the marks and the rating line, on this dark hero */
  --rbadge-star: #F6AB26;                   /* measured star gold; NOT the Google #FBBC04 */
}
/* >>> rating-badge component: generated by .skills/client-website/components/rbadge-css.js. Do not edit inside the markers. <<< */
.rbadges {
  display: flex;
  flex-wrap: nowrap;              /* THE FIX. It physically cannot stack. */
  align-items: center;
  justify-content: flex-start;
  gap: 20px;
  width: 100%;
  max-width: 520px;
  margin: 0 0 20px;
  padding: 0;
  background: none;               /* no panel, no pill, no card behind the row */
  border: 0;
}
.rbadges[data-count="3"] { gap: 12px; }
.rbadges[data-count="4"] { gap: 10px; }
.rbadges__item {
  flex: 1 1 0;
  min-width: 0;                   /* REQUIRED. Without it the row breaks. */
  max-width: 193px;
  display: block;
  line-height: 0;
  /* The item is an <a>, so without this it inherits the site's link colour. Nothing inside the
     badge is painted with that colour, but a contrast sweep reading currentColor would measure a
     colour the badge never paints. Pin it to the same token the artwork uses so the two agree. */
  color: var(--rbadge-ink, #fff);
}
.rbadges__item:focus-visible { outline: 3px solid var(--rbadge-focus, currentColor); outline-offset: 4px; border-radius: 2px; }
.rbadge { display: block; width: 100%; height: auto; aspect-ratio: 193 / 60; color: var(--rbadge-ink, #fff); }
.rbadge text { fill: currentColor; font-family: var(--font-body, inherit); }
.rbadge path[fill="#F6AB26"] { fill: var(--rbadge-star, #F6AB26); }
@media (max-width: 768px) { .rbadges { max-width: none; gap: 12px; } }
@media (max-width: 400px)  { .rbadges { gap: 8px; } }
/* A light section flips ONLY the ink. The Google G keeps Google's colours on any ground. */
.rbadges--dark .rbadge { color: #0E1A2B; }
/* <<< end rating-badge component >>> */

/* ============ trust strip ============ */
.trust-strip { position: relative; z-index: 5; margin-top: -34px; }
.trust-strip__card {
  background: #fff; box-shadow: var(--shadow-md); border-top: 4px solid var(--grn-deep);
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; padding: 24px 18px;
  clip-path: polygon(var(--chamfer) 0, 100% 0, 100% calc(100% - var(--chamfer)), calc(100% - var(--chamfer)) 100%, 0 100%, 0 var(--chamfer));
}
.trust-strip__item { display: flex; align-items: center; gap: 13px; padding: 0 14px; }
.trust-strip__item + .trust-strip__item { border-left: 1px solid var(--color-border); }
.trust-strip__icon { width: 40px; height: 40px; flex-shrink: 0; display: grid; place-items: center; background: var(--grn-tint); color: var(--grn-deep); }
.trust-strip__icon svg { width: 21px; height: 21px; }
.trust-strip__label { font-family: var(--font-display); font-weight: 400; font-size: 16px; text-transform: uppercase; letter-spacing: 0.03em; line-height: 1.15; }
.trust-strip__sub { font-size: 13.5px; color: var(--txt-muted); line-height: 1.35; }
@media (max-width: 900px) {
  .trust-strip__card { grid-template-columns: 1fr 1fr; }
  .trust-strip__item:nth-child(odd) { border-left: 0; }
  .trust-strip__item { padding: 10px 8px; }
}
@media (max-width: 540px) { .trust-strip__card { grid-template-columns: 1fr; } .trust-strip__item { border-left: 0 !important; } }

/* ============ cards ============ */
.card-grid { display: grid; gap: 26px; margin-top: 44px; }
.card-grid--2 { grid-template-columns: repeat(2, 1fr); }
.card-grid--3 { grid-template-columns: repeat(3, 1fr); }
.card-grid--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1040px) { .card-grid--4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 900px) { .card-grid--3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 680px) { .card-grid { grid-template-columns: 1fr !important; } }

.svc-card {
  background: #fff; border: 1px solid var(--color-border); display: flex; flex-direction: column;
  transition: transform var(--speed) var(--ease), box-shadow var(--speed) var(--ease), border-color var(--speed) var(--ease);
  clip-path: polygon(var(--chamfer) 0, 100% 0, 100% calc(100% - var(--chamfer)), calc(100% - var(--chamfer)) 100%, 0 100%, 0 var(--chamfer));
}
.svc-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-md); border-color: var(--grn-mid); }
.svc-card__photo { position: relative; line-height: 0; }
.svc-card__photo img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.svc-card__badge {
  position: absolute; left: 16px; bottom: -20px; width: 44px; height: 44px;
  display: grid; place-items: center; background: var(--ink); color: var(--grn);
  clip-path: polygon(var(--chamfer-sm) 0, 100% 0, 100% calc(100% - var(--chamfer-sm)), calc(100% - var(--chamfer-sm)) 100%, 0 100%, 0 var(--chamfer-sm));
}
.svc-card__badge svg { width: 22px; height: 22px; }
.svc-card__icon { width: 54px; height: 54px; display: grid; place-items: center; background: var(--grn-tint); color: var(--grn-deep); margin: 26px 26px 0; }
.svc-card__icon svg { width: 27px; height: 27px; }
.svc-card > h3 { padding: 32px 26px 0; }
.svc-card__photo + h3 { padding-top: 32px; }
.svc-card > p { padding: 10px 26px 0; color: var(--txt-muted); font-size: 15.5px; }
.svc-card__links { padding: 16px 26px 26px; margin-top: auto; display: grid; gap: 7px; }
.svc-card__links li { font-size: 15px; color: var(--txt-muted); display: flex; gap: 7px; align-items: flex-start; }
.svc-card__links a { color: var(--txt-link); text-decoration: none; font-weight: 600; display: inline-flex; align-items: center; gap: 6px; min-height: 28px; }
.svc-card__links a:hover { text-decoration: underline; }
.svc-card__links svg { width: 15px; height: 15px; flex-shrink: 0; margin-top: 4px; color: var(--grn-deep); }
.svc-card__more { display: inline-flex; align-items: center; gap: 6px; font-weight: 700; color: var(--txt-link); text-decoration: none; }
.svc-card__more:hover { text-decoration: underline; }
.svc-card__more svg { width: 15px; height: 15px; }

.icon-card {
  background: #fff; border: 1px solid var(--color-border); padding: 30px 26px;
  clip-path: polygon(var(--chamfer) 0, 100% 0, 100% calc(100% - var(--chamfer)), calc(100% - var(--chamfer)) 100%, 0 100%, 0 var(--chamfer));
  transition: transform var(--speed) var(--ease), box-shadow var(--speed) var(--ease);
}
.icon-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-md); }
.icon-card__icon { width: 50px; height: 50px; display: grid; place-items: center; background: var(--grn-tint); color: var(--grn-deep); margin-bottom: 18px; }
.icon-card__icon svg { width: 25px; height: 25px; }
.icon-card h3 { margin-bottom: 9px; }
.icon-card p { color: var(--txt-muted); font-size: 15.5px; }
.section--surface .icon-card { background: #fff; }

.link-card {
  display: flex; align-items: center; gap: 16px; padding: 19px 22px; background: #fff;
  border: 1px solid var(--color-border); text-decoration: none; color: inherit;
  transition: all var(--speed) var(--ease);
}
.link-card:hover { border-color: var(--grn-mid); transform: translateX(4px); box-shadow: var(--shadow-sm); }
.link-card__icon { width: 42px; height: 42px; flex-shrink: 0; display: grid; place-items: center; background: var(--ink); color: var(--grn); }
.link-card__icon svg { width: 21px; height: 21px; }
.link-card__body { display: flex; flex-direction: column; }
.link-card__title { font-family: var(--font-display); font-weight: 400; text-transform: uppercase; font-size: 17px; letter-spacing: 0.02em; }
.link-card__sub { font-size: 14px; color: var(--txt-muted); line-height: 1.4; }

/* ============ check list (device 2: triangle bullet) ============ */
.check-list { display: grid; gap: 10px; }
.check-list li { display: flex; align-items: flex-start; gap: 10px; font-size: 15.5px; color: var(--txt-muted); }
.check-list li svg { width: 18px; height: 18px; flex-shrink: 0; margin-top: 4px; color: var(--grn-deep); }
.check-list a { color: var(--txt); text-decoration: none; font-weight: 600; display: flex; align-items: flex-start; gap: 10px; min-height: 28px; padding: 2px 0; }
.check-list a:hover { color: var(--grn-deep); }
.check-list--cols { columns: 2; column-gap: 34px; }
.check-list--cols li { break-inside: avoid; padding: 4px 0; }
@media (max-width: 640px) { .check-list--cols { columns: 1; } }

/* ============ split ============ */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; align-items: center; }
.split__img { line-height: 0; }
.split__img img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; box-shadow: var(--shadow-md);
  clip-path: polygon(24px 0, 100% 0, 100% calc(100% - 24px), calc(100% - 24px) 100%, 0 100%, 0 24px);
}
.split--flip .split__img { order: -1; }
@media (max-width: 900px) { .split { grid-template-columns: 1fr; gap: 32px; } .split--flip .split__img { order: 0; } }

.photo-band { margin-top: 40px; line-height: 0; }
.photo-band img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; clip-path: polygon(18px 0, 100% 0, 100% calc(100% - 18px), calc(100% - 18px) 100%, 0 100%, 0 18px); }

/* before / after composite, the client's own branded graphics */
.ba-figure { margin: 0; }
.ba-figure img { width: 100%; box-shadow: var(--shadow-md); }
.ba-figure figcaption { margin-top: 12px; font-size: 14.5px; color: var(--txt-muted); }

/* ============ stats ============ */
.stat-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; margin-top: 32px; }
.stat { border-left: 4px solid var(--grn-deep); padding-left: 14px; }
.stat__num { font-family: var(--font-display); font-weight: 400; font-size: 34px; line-height: 1; color: var(--ink); }
.stat__label { font-size: 13.5px; color: var(--txt-muted); text-transform: uppercase; letter-spacing: 0.05em; margin-top: 5px; }
@media (max-width: 700px) { .stat-row { grid-template-columns: 1fr 1fr; } }

/* ============ steps ============ */
.step-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px; margin-top: 44px; }
.step { background: #fff; border: 1px solid var(--color-border); padding: 32px 26px; position: relative; }
.step__num {
  width: 46px; height: 46px; display: grid; place-items: center; background: var(--ink); color: var(--grn);
  font-family: var(--font-display); font-weight: 400; font-size: 21px; margin-bottom: 16px;
  clip-path: polygon(var(--chamfer-sm) 0, 100% 0, 100% calc(100% - var(--chamfer-sm)), calc(100% - var(--chamfer-sm)) 100%, 0 100%, 0 var(--chamfer-sm));
}
.step h3 { margin-bottom: 9px; }
.step p { color: var(--txt-muted); font-size: 15.5px; }
@media (max-width: 860px) { .step-grid { grid-template-columns: 1fr; } }

/* ============ reviews ============ */
.review-card {
  background: #fff; border: 1px solid var(--color-border); padding: 28px 26px; display: flex; flex-direction: column;
  clip-path: polygon(var(--chamfer) 0, 100% 0, 100% calc(100% - var(--chamfer)), calc(100% - var(--chamfer)) 100%, 0 100%, 0 var(--chamfer));
}
.review-card__g { width: 24px; height: 24px; margin-bottom: 12px; }
.review-card__g svg { width: 100%; height: 100%; }
.review-card__stars { display: flex; gap: 2px; margin-bottom: 12px; }
.review-card__stars svg { width: 17px; height: 17px; color: var(--color-google-star); }
.review-card__text { color: var(--txt); font-size: 15.5px; line-height: 1.62; }
.review-card__reply { margin-top: 14px; padding-top: 13px; border-top: 1px dashed var(--color-border); font-size: 14.5px; color: var(--txt-muted); }
.review-card__reply strong { color: var(--txt-link); }
.quote-card .review-card__g { margin-bottom: 12px; }
.review-card__meta { display: flex; align-items: center; gap: 11px; margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--color-border); }
.review-card__avatar { width: 42px; height: 42px; border-radius: 50%; object-fit: cover; }
.review-card__initial { width: 42px; height: 42px; display: grid; place-items: center; background: var(--ink); color: var(--grn); font-family: var(--font-display); font-weight: 400; font-size: 19px; border-radius: 50%; }
.review-card__author { font-family: var(--font-display); font-weight: 400; text-transform: uppercase; font-size: 16px; letter-spacing: 0.02em; }
.review-card__when { font-size: 13px; color: var(--txt-muted); }
.quote-card { max-width: 800px; margin: 40px auto 0; background: #fff; border: 1px solid var(--color-border); border-top: 4px solid var(--grn-deep); padding: 34px 34px 28px; text-align: center; }
.quote-card .review-card__g, .quote-card .review-card__stars { margin-left: auto; margin-right: auto; }
.quote-card .review-card__stars { justify-content: center; }
.quote-card__text { font-size: 18px; line-height: 1.6; }
.quote-card .review-card__meta { justify-content: center; }
.reviews__cta { display: flex; flex-wrap: wrap; gap: 14px; justify-content: center; margin-top: 40px; }
.review-widget { margin-top: 32px; background: #fff; padding: 12px; border: 1px solid var(--color-border); }
.review-widget iframe { display: block; min-height: 620px; }

/* ============ FAQ ============ */
.faq-list { max-width: 900px; margin: 40px auto 0; display: grid; gap: 12px; }
.faq-item { background: #fff; border: 1px solid var(--color-border); }
.faq-item__question {
  width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  font-family: var(--font-display); font-weight: 400; font-size: 18px; letter-spacing: 0.01em;
  color: var(--txt); padding: 20px 22px; display: flex; justify-content: space-between;
  align-items: center; gap: 16px; text-transform: none; min-height: 56px;
}
.faq-item__question svg { flex-shrink: 0; color: var(--grn-deep); transition: transform 0.3s var(--ease); }
.faq-item.active .faq-item__question svg { transform: rotate(180deg); }
.faq-item.active .faq-item__question { color: var(--txt-link); }
.faq-item__answer { max-height: 0; overflow: hidden; transition: max-height 0.35s var(--ease); }
.faq-item.active .faq-item__answer { max-height: 620px; }
.faq-item__answer-inner { padding: 0 22px 22px; color: var(--txt-muted); font-size: 15.5px; }

/* ============ areas ============ */
.area-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-top: 40px; }
@media (max-width: 860px) { .area-grid { grid-template-columns: repeat(2, 1fr); } }
/* Six short city cards stay TWO-UP on a phone (a 1-column stack of six ran
   1,150px). Each card is a city name and four short links, which fits a
   163px column with room. */
@media (max-width: 560px) {
  .area-grid { gap: 10px; margin-top: 28px; }
  .area-card { padding: 12px 10px 10px 12px; }
  .area-card__city { font-size: 17px; }
  .area-card__links { font-size: 13.5px; gap: 5px; }
}
.area-card { background: #fff; border: 1px solid var(--color-border); border-left: 4px solid var(--grn-deep); padding: 20px 22px; transition: all var(--speed) var(--ease); }
.area-card:hover { box-shadow: var(--shadow-sm); border-left-color: var(--amber-mid); }
.area-card__city { display: flex; min-height: 30px; align-items: center; gap: 8px; font-family: var(--font-display); font-weight: 400; font-size: 19px; text-transform: uppercase; color: var(--txt); text-decoration: none; }
.area-card__city svg { width: 18px; height: 18px; color: var(--grn-deep); }
.area-card__city:hover { color: var(--grn-deep); }
.area-card__links { margin-top: 6px; font-size: 14px; color: var(--txt-muted); display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }
.area-card__links a { display: inline-flex; align-items: center; min-height: 28px; }
.area-card__links a { color: var(--txt-link); text-decoration: none; }
.area-card__links a:hover { text-decoration: underline; }

/* ============ dark band ============ */
.band { background: var(--ink); color: #fff; padding: 82px 0; position: relative; overflow: hidden; }
.band::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image: var(--tri); background-repeat: no-repeat;
  background-position: left -110px bottom -110px; background-size: 480px; opacity: 0.05;
}
.band .container { position: relative; z-index: 2; }
.band p { color: var(--txt-muted); }
.band__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 52px; align-items: start; }
@media (max-width: 940px) { .band__grid { grid-template-columns: 1fr; gap: 36px; } }
.form-card { background: #fff; color: var(--txt); padding: 30px 28px; box-shadow: var(--shadow-lg); }
.form-card__title { font-family: var(--font-display); font-weight: 400; font-size: 24px; text-transform: uppercase; }
.form-card__sub { font-size: 15px; color: var(--txt-muted); margin: 7px 0 18px; }
.form-card__facts { display: grid; gap: 12px; }
.form-card__note { margin-top: 16px; font-size: 14.5px; color: var(--txt-muted); }

/* ============ CTA band ============ */
.cta-section { background: var(--grn-deep); color: #fff; padding: 66px 0; text-align: center; position: relative; overflow: hidden; }
.cta-section::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 6px; background: linear-gradient(90deg, var(--amber-mid) 0 22%, var(--ink) 22% 100%); }
.cta-section h2 { color: var(--txt); margin-bottom: 12px; }
.cta-section p { color: var(--txt-muted); max-width: 680px; margin: 0 auto 26px; }

/* ============ lead form ============ */
/* #estimate rides the FORM column, not the section.
   On a phone the two columns stack, the copy column runs about 1,500px tall,
   and an anchor on the section wrapper dropped the visitor roughly 1,600px
   above the form a button had just promised to jump to. The id now sits on
   the form column so the jump lands on the form on every width. The reading
   order is untouched: the copy still comes first in the markup and on screen.
   scroll-margin-top clears the sticky nav (48px bar + 76px nav on mobile). */
#estimate { scroll-margin-top: 130px; }
.lead-split__sticky { position: sticky; top: calc(var(--nav-h) + 24px); }
.lead-split { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: 52px; align-items: start; }
.lead-split__copy { max-width: 560px; }
.lead-split__copy > p { color: var(--txt-muted); }
/* the intro paragraph now sits first inside the phone disclosure; same colour as before */
.lead-split__copy details.more--lead > .more__body > p:first-child { color: var(--txt-muted); margin-top: 0; }
.lead-split__facts { margin-top: 22px; }
.lead-split__phone { display: inline-block; margin-top: 22px; font-family: var(--font-display); font-weight: 400; font-size: 36px; letter-spacing: 0.02em; color: var(--txt-link); text-decoration: none; }
.lead-split__phone:hover { color: var(--ink); }
.lead-split__steps { counter-reset: lsstep; margin-top: 26px; padding-top: 24px; border-top: 1px solid var(--color-border); display: grid; gap: 16px; }
.lead-split__steps li { counter-increment: lsstep; position: relative; padding-left: 48px; font-size: 15px; color: var(--txt-muted); line-height: 1.6; }
.lead-split__steps li::before {
  content: counter(lsstep); position: absolute; left: 0; top: 0; width: 34px; height: 34px;
  background: var(--ink); color: var(--grn); font-family: var(--font-display); font-weight: 400; font-size: 16px;
  display: grid; place-items: center;
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
}
.lead-split__steps strong { display: block; color: var(--txt); font-size: 16px; }
.lead-split__linkhead { margin-top: 26px; padding-top: 24px; border-top: 1px solid var(--color-border); font-family: var(--font-display); font-weight: 400; font-size: 17px; text-transform: uppercase; letter-spacing: 0.05em; }
.lead-split__links { columns: 2; gap: 24px; margin-top: 12px; }
.lead-split__links li { padding: 3px 0; break-inside: avoid; }
.lead-split__links a { font-size: 15px; font-weight: 600; color: var(--txt-link); text-decoration: none; display: inline-flex; align-items: center; min-height: 28px; }
.lead-split__links a:hover { text-decoration: underline; }
.lead-split__form { align-self: start; }
@media (max-width: 960px) {
  .lead-split { grid-template-columns: 1fr; gap: 34px; }
  .lead-split__copy { max-width: 660px; }
  .lead-split__sticky { position: static; top: auto; }
}
@media (max-width: 520px) { .lead-split__links { columns: 1; } }

.lead-form { background: #fff; border: 1px solid var(--color-border); box-shadow: var(--shadow-md); padding: 28px 26px; }
.lead-form__title { font-family: var(--font-display); font-weight: 400; font-size: 24px; text-transform: uppercase; }
.lead-form__sub { font-size: 15px; color: var(--txt-muted); margin: 7px 0 20px; }
.lead-form__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.lead-form__full { grid-column: 1 / -1; }
/* The grid stays TWO columns on a phone. First/Last, Phone/Email and City/State
   share a row, the .lead-form__full fields span both, and the form is about
   400px shorter for it. Inputs hold 16px so iOS does not zoom on focus, and
   min-height 46px keeps every field a real thumb target. */
@media (max-width: 520px) {
  .lead-form__grid { gap: 12px 10px; }
  .form-input, .form-textarea, .form-select { min-height: 46px; padding: 10px 12px; }
  .form-select { padding-right: 34px; background-position: right 10px center; }
}
.form-group { display: flex; flex-direction: column; gap: 6px; }
.form-label { font-family: var(--font-display); font-weight: 400; font-size: 14px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--txt); }
.form-input, .form-textarea, .form-select {
  font-family: var(--font-body); font-size: 16px; padding: 12px 14px;
  border: 1.5px solid var(--color-border); background: #fff; color: var(--txt); width: 100%;
  transition: border-color 0.25s var(--ease);
}
.form-input:focus, .form-textarea:focus, .form-select:focus { outline: none; border-color: var(--grn-deep); }
.form-textarea { resize: vertical; }
.form-select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230B7D0F' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; background-size: 17px; padding-right: 38px; }
.form-file { font-size: 15px; padding: 10px 0; }
.form-hint { font-size: 13.5px; color: var(--txt-muted); }
.form-consent { display: flex; align-items: flex-start; gap: 10px; font-size: 14.5px; color: var(--txt-muted); }
.form-consent input { margin-top: 5px; width: 18px; height: 18px; flex-shrink: 0; accent-color: var(--grn-deep); }
.lead-form__submit {
  grid-column: 1 / -1; font-family: var(--font-display); font-weight: 400; font-size: 17px;
  letter-spacing: 0.07em; text-transform: uppercase; background: var(--grn-deep); color: #fff;
  border: 0; padding: 16px 26px; cursor: pointer; min-height: 54px;
  clip-path: polygon(var(--chamfer) 0, 100% 0, 100% calc(100% - var(--chamfer)), calc(100% - var(--chamfer)) 100%, 0 100%, 0 var(--chamfer));
  transition: background var(--speed) var(--ease);
}
.lead-form__submit:hover { background: var(--grn-deep-hover); }
.lead-form__submit:disabled { opacity: 0.6; cursor: default; }
.lead-form__result { grid-column: 1 / -1; font-size: 15px; padding: 12px 14px; }
.lead-form__result.is-ok { background: var(--grn-tint); color: #0A5E0D; }
.lead-form__result.is-err { background: #FDECEC; color: #9B1C1C; }
.lead-form__consent { grid-column: 1 / -1; font-size: 12.5px; line-height: 1.55; color: var(--txt-muted); }
.lead-form__consent a { color: var(--txt-link); }

/* ============ gallery ============ */
.gallery-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 40px; }
@media (max-width: 1000px) { .gallery-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 760px) { .gallery-grid { grid-template-columns: repeat(2, 1fr); } }
.gallery-item { line-height: 0; background: var(--ink); }
.gallery-item img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; transition: opacity var(--speed) var(--ease); }
.gallery-item:hover img { opacity: 0.86; }
.gallery-item figcaption { line-height: 1.4; font-size: 13px; color: var(--txt-muted); padding: 9px 2px 0; background: var(--color-bg); }

/* ============ maps ============ */
.map-section { line-height: 0; display: grid; grid-template-columns: 1fr; }
.map-embed { width: 100%; height: 320px; border: 0; display: block; }

/* ============ footer ============ */
.footer { background: var(--ink); color: var(--txt-muted); padding: 66px 0 34px; position: relative; overflow: hidden; }
.footer::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image: var(--tri); background-repeat: no-repeat;
  background-position: right -120px bottom -140px; background-size: 520px; opacity: 0.045;
}
.footer .container { position: relative; z-index: 2; }
.footer__grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1.2fr; gap: 40px; }
@media (max-width: 980px) { .footer__grid { grid-template-columns: 1fr 1fr; gap: 32px; } }
@media (max-width: 600px) { .footer__grid { grid-template-columns: 1fr; } }
.footer__logo img { height: 84px; width: auto; }
.footer__brand-desc { margin-top: 16px; font-size: 15px; line-height: 1.6; }
.footer__rating { display: flex; align-items: center; gap: 8px; margin-top: 16px; font-size: 14px; color: var(--txt); }
.footer__rating svg { width: 16px; height: 16px; color: var(--color-google-star); }
.footer__heading { font-size: 17px; color: var(--txt); margin-bottom: 16px; letter-spacing: 0.09em; } /* 17px was the h4 size; the tag is h3 now so the outline does not skip a level */
.footer__links { display: grid; gap: 4px; }
.footer__links a { color: var(--txt-muted); text-decoration: none; font-size: 15px; display: inline-flex; align-items: center; min-height: 28px; }
.footer__links a:hover { color: var(--grn); }
.footer__contact-item { display: flex; align-items: flex-start; gap: 11px; font-size: 15px; margin-bottom: 13px; }
.footer__contact-item svg { width: 19px; height: 19px; flex-shrink: 0; color: var(--grn); margin-top: 3px; }
.footer__contact-item a { color: var(--txt-link); text-decoration: none; font-weight: 600; display: inline-flex; align-items: center; min-height: 26px; }
.footer__contact-item a:hover { color: #fff; }
.footer__bottom { margin-top: 42px; padding-top: 22px; border-top: 1px solid var(--ink-line); display: flex; justify-content: space-between; gap: 14px; flex-wrap: wrap; font-size: 13.5px; }
.legal-footer { background: #070A08; color: #7C8A81; text-align: center; padding: 14px 20px; font-size: 13px; }
.legal-footer a { color: #7C8A81; text-decoration: none; display: inline-block; padding: 4px 2px; min-height: 26px; }
.legal-footer a:hover { color: var(--grn); }

/* ============ misc ============ */
.section__footer { text-align: center; margin-top: 44px; }
.section-divider { line-height: 0; }
.reveal { opacity: 0; transform: translateY(26px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }
.reveal.visible { opacity: 1; transform: none; }
/* No-JS fallback, 2026-09-07. <html> ships with class="no-js" and a one-line inline
   script in <head> swaps it to "js" before the first paint. If that script never runs
   (blocked, broken, or a crawler that does not execute scripts) every .reveal band
   would sit at opacity 0 forever. This rule makes them simply present instead.
   _gate-no-js.js proves it on every page with scripts blocked. */
html.no-js .reveal { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
  .btn:hover, .svc-card:hover, .icon-card:hover { transform: none; }
}
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* customer pull quote, used where a review line is the best proof available */
.pull-quote { margin: 26px 0 0; padding: 20px 24px; background: var(--grn-tint); border-left: 5px solid var(--grn-deep); font-size: 18px; line-height: 1.55; color: var(--txt); }
.pull-quote cite { display: block; margin-top: 10px; font-size: 14px; font-style: normal; color: var(--txt-muted); }

/* ============================================================
   PHONE SHAPE. Added 2026-09-05.

   The homepage measured 18,213px tall on a 390px phone, 22 screens. The
   13 live reference homepages measured the same day run 5,828 to
   11,523 (median 8,524), 7 to 10 bands, nothing taller than ~2,200.
   _gate-mobile-shape.js holds those limits and _qa.js spawns it.

   Nothing here removes a word or a link from the DOM. The tools are:
   the padding ladder above, two-up grids for short items, native
   <details> disclosures for secondary copy (closed on a phone by a
   one-line script, open and summary-less on wider screens), and a
   tighter card anatomy at phone width.
   ============================================================ */

/* ---- disclosures ----
   <details class="more" open><summary>label</summary>…</details>
   Open in the markup, so a crawler or a browser without JS sees every
   word. The inline script at the foot of each page closes them on a
   phone. Above 767px the summary is hidden and the content stays open,
   so desktop is untouched. The summary is a real 48px tappable row with
   the site's own chevron. */
details.more > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 48px; padding: 10px 2px; margin-top: 18px;
  border-top: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border);
  font-family: var(--font-display); font-weight: 400; font-size: 15px;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--txt-link);
  -webkit-tap-highlight-color: transparent;
}
details.more > summary::-webkit-details-marker { display: none; }
details.more > summary::after {
  content: ''; flex-shrink: 0; width: 9px; height: 9px; margin: 0 8px 4px 0;
  border-right: 2.5px solid currentColor; border-bottom: 2.5px solid currentColor;
  transform: rotate(45deg); transition: transform 0.25s var(--ease);
}
details.more[open] > summary::after { transform: rotate(225deg); margin: 4px 8px 0 0; }
details.more > summary:focus-visible { outline: 3px solid var(--txt-link); outline-offset: 3px; }
details.more > .more__body { padding-top: 6px; }
/* A closed disclosure paints nothing, but Chromium keeps the last layout of
   its contents, so a text run inside one still answers getClientRects() with
   real coordinates. The pixel sweep then measures words that are not on the
   screen and reports them as text the colour of its own background. Saying
   the closed body is hidden makes the measurement agree with the screen; the
   open state, the desktop and the markup are untouched. */
details.more:not([open]) > .more__body { visibility: hidden; }
/* the footer variant: the column heading IS the summary, so the desktop
   heading is unchanged and the phone gets one tappable row per column */
details.more--footer > summary { border-color: var(--ink-line); border-bottom: 0; margin-top: 0; padding: 12px 2px; }
details.more--footer > summary .footer__heading { margin: 0; }
details.more--footer > .more__body { padding: 4px 0 14px; }
/* the card variant: the dark band's "Three Ways to Reach Us" card folds on a
   phone. Every fact in it (phone, booking, estimate link, hours, towns) is
   also in the two buttons above it and in the footer. The row rules on the
   band's own line colour so it reads on the dark surface. */
details.more--card > summary { border-color: var(--ink-line); margin-top: 0; }
details.more--card > .more__body { padding-top: 14px; }
/* the proof variant: under "Every Photo On This Site Is Our Own Work" the
   second paragraph, the stat row and the two buttons fold; the heading, the
   first paragraph and the before-and-after photo stay in view. On a wide
   screen the paragraph keeps the 15px a p + p sibling would have had. */
details.more--proof > .more__body { padding-top: 0; }
details.more--proof > .more__body > p:first-child { margin-top: 15px; }
@media (max-width: 767px) { details.more--proof > .more__body > p:first-child { margin-top: 8px; } }
/* on a phone the footer reads as an accordion: brand, then one rule per row */
@media (max-width: 600px) {
  .footer__grid { gap: 0; }
  .footer__grid > div:first-child { margin-bottom: 20px; }
  /* Contact folds like the other two columns; its summary row carries the rule line */
  .footer__contact-item { margin-bottom: 9px; }
  .footer__brand-desc { font-size: 14.5px; }
}
@media (min-width: 768px) {
  details.more:not(.more--footer) > summary { display: none; }
  details.more--footer > summary { display: block; pointer-events: none; min-height: 0; padding: 0; margin: 0; border: 0; }
  details.more--footer > summary::after { display: none; }
  details.more--footer > summary .footer__heading { margin-bottom: 16px; }
  details.more--footer > .more__body { padding-top: 0; }
  details.more--card > .more__body { padding-top: 0; }
  /* the estimate copy: the paragraph moved inside the disclosure, so the body
     drops its 6px and the facts list takes it, and nothing moves on a wide screen */
  details.more--lead > .more__body { padding-top: 0; }
  details.more--lead .lead-split__facts { margin-top: 28px; }
}

/* ---- the two homepage sections that tuck under a divider ----
   Inline padding-top styles used to pin these at 52 and 74 at every
   width; on a phone they follow the ladder like everything else. */
.section--tuck { padding-top: 52px; }
.band--tuck { padding-top: 74px; }
.btn-pair--after { margin-top: 44px; }
.btn-pair--center { justify-content: center; }

/* ---- phone type and spacing ----
   Body copy drops from 17 to 16px on a phone, which is where the reference
   estate sits, and every intro paragraph wraps one line fewer for it. */
@media (max-width: 480px) {
  body { font-size: 16px; }
  .hero__text { font-size: 17px; }
  .section-subtitle { margin-bottom: 8px; }
  .faq-item__question { padding: 14px 16px; font-size: 17px; }
  .faq-item__answer-inner { padding: 0 16px 16px; }
  .btn { font-size: 15px; min-height: 48px; padding: 12px 18px; }
  .btn-pair, .hero__actions, .reviews__cta { gap: 10px; }
  .review-card__text { font-size: 15px; }
  .review-card__meta { margin-top: 14px; padding-top: 12px; }
  .stat-row { grid-template-columns: repeat(4, 1fr); gap: 10px; }
  .stat { padding-left: 10px; border-left-width: 3px; }
  .stat__num { font-size: 28px; }
  .stat__label { font-size: 11px; letter-spacing: 0.03em; }
  .area-card__links span { display: none; }   /* the decorative bullet between links */
  .area-card__links { gap: 4px 12px; }
  /* the three numbered steps read as rows: number left, copy right */
  .step { display: grid; grid-template-columns: 40px minmax(0, 1fr); column-gap: 14px; padding: 18px 16px; align-items: start; }
  .step > * { grid-column: 2; }
  .step__num { grid-column: 1; grid-row: 1 / span 2; width: 40px; height: 40px; font-size: 18px; margin: 0; }
  .step h3 { margin-bottom: 4px; align-self: center; }
  .step p { font-size: 15px; line-height: 1.55; }
  .form-card__title, .lead-form__title { font-size: 22px; }
  .lead-form__consent { font-size: 12px; }
}

/* ---- phone bands and spacing ---- */
@media (max-width: 767px) {
  .band, .cta-section, .section--tuck, .band--tuck { padding: var(--section-pad) 0; }
  .footer { padding: var(--section-pad) 0 28px; }
  .section-title { margin-bottom: 10px; }
  .section-title--underline { padding-bottom: 12px; }
  p + p { margin-top: 12px; }
  .card-grid, .step-grid, .faq-list, .gallery-grid { margin-top: 22px; }
  .card-grid, .step-grid { gap: 12px; }
  .faq-list { gap: 10px; }
  .btn-pair--after, .reviews__cta, .section__footer { margin-top: 22px; }
  .btn-pair .btn, .reviews__cta .btn { flex: 1 1 auto; }
  .btn { padding: 14px 20px; }
  .trust-strip__card { padding: 10px 8px; }
  .trust-strip__item { padding: 6px 6px; }
  .step { padding: 22px 18px; }
  .review-card { padding: 20px 16px; }
  .form-card { padding: 22px 18px; }
  .form-card__sub { margin-bottom: 14px; }
  .form-card__facts { gap: 10px; }
  .lead-form { padding: 20px 14px; }
  .lead-form__sub { margin-bottom: 14px; }
  .lead-form__grid { gap: 10px; }
  .form-group { gap: 5px; }
  .lead-split { gap: 24px; }
  .stat-row { margin-top: 20px; gap: 14px; }
  .quote-card { padding: 26px 20px 22px; }
  .footer__grid { gap: 18px; }
  .footer__bottom { margin-top: 20px; padding-top: 16px; }
  .footer__rating { margin-top: 12px; }
  .map-embed { height: 240px; }
}

/* ---- icon cards read as a row on a phone: icon left, copy right ----
   A stacked icon card ran ~230px; the row runs ~130 and says the same. */
@media (max-width: 680px) {
  .icon-card { display: grid; grid-template-columns: 44px minmax(0, 1fr); column-gap: 14px; align-items: start; padding: 16px; }
  .icon-card > * { grid-column: 2; }
  .icon-card__icon { grid-column: 1; grid-row: 1 / span 2; width: 44px; height: 44px; margin: 0; }
  .icon-card__icon svg { width: 22px; height: 22px; }
  .icon-card h3 { margin-bottom: 4px; align-self: center; }
  .icon-card p { font-size: 15px; line-height: 1.55; }
}

/* ---- service cards become a media object on a phone ----
   Photo on the left, filling the card's height; title, line and links on
   the right. Six full-width photo cards ran 3,081px; six of these run
   about 1,600. Every link stays exactly where it was in the DOM. */
@media (max-width: 680px) {
  .svc-card { display: grid; grid-template-columns: 116px minmax(0, 1fr); grid-template-rows: auto auto 1fr; }
  .svc-card > * { grid-column: 2; }
  .svc-card__photo, .svc-card__icon { grid-column: 1; grid-row: 1 / span 3; }
  .svc-card__photo { min-height: 150px; height: auto; }
  .svc-card__photo img { position: absolute; inset: 0; width: 100%; height: 100%; aspect-ratio: auto; object-fit: cover; }
  .svc-card__badge { left: 8px; bottom: 8px; width: 32px; height: 32px; }
  .svc-card__badge svg { width: 16px; height: 16px; }
  .svc-card__icon { width: auto; height: auto; margin: 0; align-self: stretch; }
  .svc-card > h3 { padding: 14px 14px 0; font-size: 18px; }
  .svc-card__photo + h3 { padding-top: 14px; }
  .svc-card > p { padding: 5px 14px 0; font-size: 14.5px; line-height: 1.5; }
  .svc-card__links { padding: 8px 14px 14px; gap: 3px; }
  .svc-card__links li { font-size: 14.5px; }
}

/* ============================================================
   BEFORE AND AFTER SLIDERS. Added 2026-09-08.

   The brief was for before-and-after comparisons that move as you
   scroll, on the pages where a real pair exists.

   ONE SET OF MARKUP, TWO RENDERINGS.
   With JavaScript, the AFTER image lies underneath, the BEFORE
   image is clipped over it at --ba, and a divider with a round
   handle wipes between them. The wipe animates once from fully
   before to the middle when the card scrolls into view.
   With html.no-js the same frame becomes a two-up grid, stacked
   on a phone, with both labels showing and the divider hidden.
   That is what keeps _gate-no-js.js green: a blocked script, a
   reader mode or a crawler still sees both photographs.

   COLOURS AND SHAPES ARE THE SITE'S OWN. Green divider, near
   black chip labels in the display face, chamfered frame, and
   the caption on --txt-muted so it stays legible on the white
   band and on the grey one.

   THE LABEL CHIPS ARE WHITE ON rgba(15,21,17,0.92). Over the
   brightest pixel a photo can give (pure white) that composites
   to about #222724, which still measures over 15:1 against
   white text. Thin that alpha and it is the first thing that
   breaks, so do not.
   ============================================================ */
.ba-band__intro { max-width: 620px; margin: 14px auto 0; }
.ba-band__more { max-width: 820px; margin: 42px auto 0; }
.ba-grid { display: grid; gap: 30px; margin-top: 40px; }
/* the cards are capped deliberately. The BEFORE half of the client's composite
   holds about 320px of real detail, so a card wider than about 430px is drawing
   pixels the photograph never had. */
.ba-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 900px; margin-left: auto; margin-right: auto; }
.ba-grid--1 { grid-template-columns: minmax(0, 1fr); max-width: 435px; margin-left: auto; margin-right: auto; }
@media (max-width: 760px) { .ba-grid--2 { grid-template-columns: minmax(0, 1fr); max-width: 435px; } }

.ba-pair { margin: 0; }
.ba-pair__frame {
  --ba: 50%;
  position: relative; overflow: hidden; line-height: 0;
  aspect-ratio: 4 / 3; background: var(--ink);
  box-shadow: var(--shadow-md);
  clip-path: polygon(18px 0, 100% 0, 100% calc(100% - 18px), calc(100% - 18px) 100%, 0 100%, 0 18px);
  /* pan-y leaves vertical scrolling to the browser and gives us the sideways drag */
  touch-action: pan-y;
  -webkit-user-select: none; user-select: none;
}
/* Not every pair is landscape. The five CompanyCam pairs added 2026-09-08 include
   two shot in portrait, and cropping a portrait job photo to 4:3 would throw away
   the top of an arched alcove or the bottom of a stair landing. _before-after.js
   puts this modifier on any pair whose brief entry reads aspect 3:4. */
.ba-pair--portrait .ba-pair__frame { aspect-ratio: 3 / 4; }
.ba-pair__side { position: absolute; inset: 0; }
.ba-pair__side img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ba-pair__side--before { clip-path: inset(0 calc(100% - var(--ba)) 0 0); }
.ba-pair__tag {
  position: absolute; bottom: 12px; z-index: 3;
  font-family: var(--font-display); font-weight: 400; font-size: 12.5px; line-height: 1;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: #FFFFFF; background: rgba(15, 21, 17, 0.92); padding: 9px 13px;
  clip-path: polygon(7px 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%, 0 7px);
}
.ba-pair__tag--before { left: 12px; }
.ba-pair__tag--after { right: 12px; }
.ba-pair__line {
  position: absolute; top: 0; bottom: 0; left: var(--ba); width: 3px; margin-left: -1.5px;
  background: var(--grn); box-shadow: 0 0 0 1px rgba(15, 21, 17, 0.5); z-index: 4; pointer-events: none;
}
.ba-pair__handle {
  position: absolute; top: 50%; left: var(--ba); transform: translate(-50%, -50%);
  width: 46px; height: 46px; z-index: 5; padding: 0; cursor: ew-resize;
  display: grid; place-items: center;
  background: var(--ink); color: var(--grn); border: 2px solid var(--grn); border-radius: 50%;
  box-shadow: 0 3px 12px rgba(15, 21, 17, 0.45);
  touch-action: none; -webkit-tap-highlight-color: transparent;
}
.ba-pair__handle svg { width: 22px; height: 22px; display: block; }
.ba-pair__handle:focus-visible { outline: 3px solid var(--amber); outline-offset: 3px; }
.ba-pair__caption { margin-top: 13px; font-size: 14.5px; line-height: 1.45; color: var(--txt-muted); }
/* At either end of the wipe one label is behind the other photograph. js/main.js puts
   these classes on the frame so the element is hidden rather than merely covered, which
   is what stops _contrast.js measuring white text against a photo nobody can see it on.
   Same fix, same reason, as the closed <details> body above. */
.ba-pair__frame.is-all-before .ba-pair__tag--after,
.ba-pair__frame.is-all-after .ba-pair__tag--before { visibility: hidden; }

/* ---- no JavaScript: the same markup, side by side ---- */
html.no-js .ba-pair__frame {
  aspect-ratio: auto; overflow: visible; background: none; box-shadow: none; clip-path: none;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; touch-action: auto;
}
html.no-js .ba-pair__side { position: relative; inset: auto; clip-path: none; }
html.no-js .ba-pair__side img {
  aspect-ratio: 4 / 3; height: auto; box-shadow: var(--shadow-md);
  clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 14px), calc(100% - 14px) 100%, 0 100%, 0 14px);
}
html.no-js .ba-pair--portrait .ba-pair__side img { aspect-ratio: 3 / 4; }
html.no-js .ba-pair__side--before { order: -1; }
html.no-js .ba-pair__line, html.no-js .ba-pair__handle { display: none; }
@media (max-width: 600px) { html.no-js .ba-pair__frame { grid-template-columns: minmax(0, 1fr); } }

@media (max-width: 767px) {
  .ba-grid { gap: 26px; margin-top: 26px; }
  .ba-band__more { margin-top: 30px; }
}
