/* =====================================================================
   INTEGRITY RESTORATIONS & REMODELING
   Mobile-first. Phone layout is the default; desktop is added at 768px.
   ===================================================================== */

/* ---------- TOKENS (from the logo's vector print files) ---------- */
:root {
    --red:       #ED1C24;   /* accents, headline emphasis */
    --red-dark:  #BA1E23;   /* buttons, white text on it */
    --ink:       #231F20;   /* text; all photo overlays are this at alpha, never #000 */
    --grey-900:  #88888A;   /* dark surfaces; exact logo background grey */
    --grey-700:  #939598;   /* the "I" on the shield, right half */
    --grey-500:  #A7A9AC;
    --grey-300:  #D1D3D4;   /* the "I" on the shield, left half; secondary text on dark */
    --grey-100:  #E6E7E8;
    --white:     #FFFFFF;
    --gold:      #F2B01E;   /* review stars only; the one colour outside the logo palette, by request */

    /* The brand "light source": bright left half, dark right half, taken
       from the shield's faceted lighting. Everything emphasised uses it. */
    --grad-brand:  linear-gradient(90deg, var(--red) 0%, var(--red) 50%, var(--red-dark) 100%);
    --grad-brand-smooth: linear-gradient(90deg, var(--red), var(--red-dark));
    /* Same idea in the shield's "I" greys: the headline wears this so its
       left edge is lighter than its right, matching the mark. On phones
       the headline is only ~350px wide, so the ramp is softened (white
       into light grey) to match the mobile comp; desktop widens it to
       the full I range below. */
    --grad-steel:  linear-gradient(90deg, var(--white) 0%, var(--white) 100%);      /* the headline is solid white now (Phil's call); the ramp machinery is kept for the two red words */

    /* Photo overlay strength (comp default .85). One knob. */
    --overlay: 0.6;

    --font-display: "Bebas Neue", "Oswald", Impact, sans-serif;
    --font-ui:      "Oswald", "Arial Narrow", sans-serif;
    --font-body:    "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

    --nav-h: 64px;
    --gutter: 22px;
    --ease-out: cubic-bezier(.22, 1, .36, 1);
}

/* ---------- RESET ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
/* NOTHING MAY WIDEN THE PAGE. Things parked off to the side waiting for their
   entrance (rows that slide in from the right, a rotated photo stack) would
   otherwise stretch the layout on a phone: the whole site shrinks to fit and
   the hamburger lands off screen. clip, not hidden: no scroll container, so
   pinning and anchors behave. */
main, .site-footer { overflow-x: clip; }
body {
    font-family: var(--font-body);
    color: var(--ink);
    background: var(--white);
    line-height: 1.5;
    overflow-x: clip;
}
img, svg { display: block; max-width: 100%; }
[hidden] { display: none !important; }   /* the attribute must beat any display rule */
img { height: auto; }              /* width/height attrs give the ratio, CSS the size */
ul { list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
:focus-visible { outline: 3px solid var(--red); outline-offset: 3px; }
.svg-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

.skip-link {
    position: absolute; left: 12px; top: -100px; z-index: 100;
    padding: 10px 16px; background: var(--red-dark); color: var(--white);
    font-family: var(--font-ui); text-transform: uppercase; letter-spacing: .08em;
}
.skip-link:focus { top: 12px; }

/* ---------- BUTTONS ---------- */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: .4em;
    min-height: 48px; padding: 12px 20px;
    font-family: var(--font-ui); font-weight: 600; font-size: 13.5px;
    letter-spacing: .08em; text-transform: uppercase; line-height: 1;
    color: var(--white); white-space: nowrap;
    transition: transform .25s var(--ease-out), box-shadow .25s var(--ease-out);
}
.btn--primary {
    background: var(--grad-brand);
    box-shadow: 0 6px 22px rgba(35, 31, 32, .45);
}
/* THE OUTLINE BUTTON. At rest: a faint grey frame, and a line of Integrity
   red that travels round it, drawing the outline as it goes (a conic
   gradient turned by --spin, masked down to a 2px ring). On hover or focus
   the line runs on round the whole frame, then the brand gradient fills the
   button. Reduced motion: the full red outline, still. */
@property --spin { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
@property --gap { syntax: "<percentage>"; inherits: false; initial-value: 55%; }   /* the part of the ring with no red on it */
.btn--outline {
    position: relative; isolation: isolate;
    box-shadow: inset 0 0 0 2px rgba(209, 211, 212, .28); color: var(--grey-300);      /* the faint frame: a shadow, not a border, so the ring below can sit inside the button's own box (the rolling label clips overflow) */
    font-weight: 500;
    transition: transform .25s var(--ease-out), color .3s;
}
.btn--outline::before {
    content: ""; position: absolute; inset: 0; z-index: -1;
    background: var(--grad-brand); opacity: 0; transition: opacity .25s;
}
.btn--outline::after {
    content: ""; position: absolute; inset: 0; padding: 2px; pointer-events: none;
    background: conic-gradient(from var(--spin), transparent 0 var(--gap), var(--red-dark) calc(var(--gap) * 1.42), var(--red) 100%);
    transition: --gap .75s ease-in-out;
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor; mask-composite: exclude;
    animation: btn-spin 3.6s linear infinite;
}
@keyframes btn-spin { to { --spin: 360deg; } }
.btn--outline:hover, .btn--outline:focus-visible { color: var(--white); }
/* hover, in two beats: the red line runs on round the frame until it meets
   its own tail (--gap closes), THEN the fill comes in. Leaving: the fill goes
   first, the line lets go after. */
.btn--outline:hover::before, .btn--outline:focus-visible::before { opacity: 1; transition: opacity .35s .7s; }
.btn--outline:hover::after, .btn--outline:focus-visible::after { --gap: 0%; animation-play-state: paused; }
/* .btn--still: the quiet version. A plain light outline, no travelling line;
   hover or focus gives the red outline and the fill at once. One moving
   button per screen is enough. */
.btn--still { box-shadow: inset 0 0 0 2px rgba(209, 211, 212, .8); }
.btn--still::after { animation: none; opacity: 0; transition: opacity .3s; --gap: 0%; }
.btn--still:hover::after, .btn--still:focus-visible::after { opacity: 1; }
.btn--still:hover::before, .btn--still:focus-visible::before { transition: opacity .3s; }
@media (prefers-reduced-motion: reduce) { .btn--outline::after { animation: none; transition: none; --gap: 0%; } .btn--outline:hover::before, .btn--outline:focus-visible::before { transition: none; } }
.btn:hover, .btn:focus-visible { transform: translateY(-2px); }
.btn--primary:hover { box-shadow: 0 10px 28px rgba(35, 31, 32, .55); }

/* ---------- HEADER / NAV ---------- */
.site-header {
    position: fixed; inset: 0 0 auto 0; z-index: 50;
    height: var(--nav-h);
}
/* readability gradient under the nav: intentionally light so the black
   half of the wordmark still reads without a glow on the logo */
.site-header::before {
    content: ""; position: absolute; inset: 0 0 auto 0; height: 110px; z-index: -1;
    background: linear-gradient(to bottom, rgba(35,31,32,.35) 0%, rgba(35,31,32,.18) 55%, transparent 100%);
    pointer-events: none;
    transition: opacity .5s;
}
.site-header.is-scrolled::before { opacity: 0; }
/* the grey bar itself: a child, not a background, so it can wipe in
   from the left (script.js scales it; reduced motion just shows it) */
.site-header__bg {
    position: absolute; inset: 0; z-index: -1;
    background: var(--grey-900);
    transform: scaleX(0); transform-origin: 0 50%;
}
@media (prefers-reduced-motion: reduce) {
    .site-header.is-scrolled .site-header__bg { transform: none; }
}

.nav {
    height: 100%; padding: 0 var(--gutter);
    display: flex; align-items: center; justify-content: space-between;
}
.nav__brand { display: flex; align-items: center; gap: 10px; }
.nav__shield { width: 38px; height: auto; }
.nav__wordmark { width: 118px; height: auto; }

/* hamburger: three bars, becomes an X when open */
.nav__toggle {
    width: 44px; height: 44px; display: grid; place-content: center; gap: 5px;
}
.nav__bar {
    width: 22px; height: 2.5px; background: var(--white); border-radius: 2px;
    transition: transform .3s var(--ease-out), opacity .2s, background-color .2s;
}
/* the X (menu open) turns Integrity red under the finger or the pointer */
.nav__toggle[aria-expanded="true"]:hover .nav__bar, .nav__toggle[aria-expanded="true"]:active .nav__bar, .nav__toggle[aria-expanded="true"]:focus-visible .nav__bar { background: var(--red); }
.nav__toggle[aria-expanded="true"] .nav__bar:nth-child(1) { transform: translateY(7.5px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] .nav__bar:nth-child(2) { opacity: 0; }
.nav__toggle[aria-expanded="true"] .nav__bar:nth-child(3) { transform: translateY(-7.5px) rotate(-45deg); }

/* mobile menu panel: full-screen sheet under the nav bar */
.nav__menu {
    position: fixed; inset: var(--nav-h) 0 0 0;
    background: rgba(35, 31, 32, .96);
    padding: 32px var(--gutter) 48px;
    display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 8px;      /* everything centred, across and down */
    overflow-y: auto; overscroll-behavior: contain;                                                  /* a short phone in landscape can still reach every link */
    transform: translateX(100%);
    visibility: hidden;
    transition: transform .6s cubic-bezier(.65, 0, .35, 1), visibility 0s .6s;      /* this is the CLOSE: slower, easing away rather than snapping shut */
}
.nav__menu.is-open { transform: none; visibility: visible; transition: transform .4s var(--ease-out); }
.nav__menu--snap { transition: none !important; }   /* while the header switches layouts */
.nav__list { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.nav__link {
    display: block; padding: 14px 0;
    font-family: var(--font-ui); font-weight: 500; font-size: 22px;
    letter-spacing: .12em; text-transform: uppercase; color: var(--white); text-align: center;
    text-shadow: 0 1px 3px rgba(35, 31, 32, .5);
    transition: color .2s;
}
.nav__link:hover, .nav__link:focus-visible { color: var(--red); }      /* no rolling letters here: just the Integrity red */
.nav__cta { margin-top: 24px; align-self: center; width: min(100%, 340px); }

/* ---------- HOME CONTROL ----------
   Fixed bottom right. Hidden over the hero (.visible comes from script.js);
   its colour follows the background under it: white over dark sections and
   photos, Integrity red (.on-light) over white and grey ones. */
.home-btn {
    position: fixed; right: 0; bottom: 12px; z-index: 45;      /* bottom right, tucked into the page gutter so it stays clear of the text column */      /* under the header and its menu (50) */
    width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
    color: var(--white); opacity: 0; visibility: hidden;
    filter: drop-shadow(0 1px 2px rgba(35, 31, 32, .45));
    transition: opacity .35s ease, visibility .35s, color .4s, filter .4s;
}
.home-btn.visible { opacity: 1; visibility: visible; }
.home-btn.on-light { color: var(--red); filter: none; }
.home-btn svg { display: block; width: 22px; height: 22px; }
@media (min-width: 768px) { .home-btn { right: 10px; bottom: 16px; width: 52px; height: 52px; } .home-btn svg { width: 32px; height: 32px; } }
.home-btn .home-fill { opacity: 0; transition: opacity .3s ease; }
.home-btn:hover .home-fill, .home-btn:focus-visible .home-fill { opacity: 1; }
.home-btn:focus-visible { outline: 3px solid currentColor; outline-offset: 2px; }
body.has-dialog .home-btn { visibility: hidden; }
@media (prefers-reduced-motion: reduce) { .home-btn, .home-btn .home-fill { transition: none; } }

/* ---------- HERO ---------- */
.hero {
    position: relative; isolation: isolate;
    min-height: 100vh;              /* fallback for browsers without svh */
    min-height: 100svh;             /* small viewport: excludes the mobile URL bar */
    display: grid; grid-template-rows: 1fr auto;
    color: var(--white);
}
.hero__media { position: absolute; inset: 0; z-index: -1; overflow: hidden; }
/* THE SHIELD'S POINT. The hero's base is a shallow V, like the bottom of
   the shield, not a flat edge. --vee is its depth. The V sits where the
   photo meets the white credentials strip (see .trust), at every size. */
.hero { --vee: clamp(22px, 3.4vw, 62px); }
/* THE REVEAL. --rv runs 0 (before photo, no "a success") to 1 (finished
   kitchen, "a success" in full). Both the after photo and the red words
   wear the same soft-edged mask, so they arrive left to right in step.
   Default 0 so the page opens on the before photo with no flash; if
   script.js never takes over, the fallback animation flips it to 1
   after a few seconds, and reduced motion starts at 1. */
.hero { --rv: 0; --rm: 0; animation: hero-rv-fallback 0s 6s forwards; }      /* --rm: the drywall stage, revealed the same way before --rv */
@keyframes hero-rv-fallback { to { --rv: 1; --rm: 1; } }
@media (prefers-reduced-motion: reduce) { .hero { --rv: 1; --rm: 1; animation: none; } }
/* THE INTRO'S STARTING STATE IS IN THE STYLESHEET, so the first paint already
   has it. Left to script.js alone, the page drew everything, then the script
   hid it, then faded it in: a flash and a jump on a phone's first load. If the
   script never arrives the same fallback as above shows everything after a
   few seconds; script.js cancels the fallback when it takes over. */
.hero__title, .hero__note, .hero__actions, .trust__item, .nav__list, .nav__brand { opacity: 0; animation: intro-fallback 0s 6s forwards; }
@keyframes intro-fallback { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .hero__title, .hero__note, .hero__actions, .trust__item, .nav__list, .nav__brand { opacity: 1; animation: none; } }
.hero__after, .hero__title .hl {
    -webkit-mask-image: linear-gradient(90deg, #000 calc(var(--rv) * 125% - 25%), transparent calc(var(--rv) * 125%));
            mask-image: linear-gradient(90deg, #000 calc(var(--rv) * 125% - 25%), transparent calc(var(--rv) * 125%));
}
.hero__after, .hero__mid { position: absolute; inset: 0; overflow: hidden; }
.hero__mid {
    -webkit-mask-image: linear-gradient(90deg, #000 calc(var(--rm) * 125% - 25%), transparent calc(var(--rm) * 125%));
            mask-image: linear-gradient(90deg, #000 calc(var(--rm) * 125% - 25%), transparent calc(var(--rm) * 125%));
}
.hero__title .hl { display: inline-block; }   /* one box, so one mask runs across both words */
.hero__photo {
    width: 100%; height: 100%; object-fit: cover;
    /* portrait crop of a landscape photo: bias left so the hood, the
       cabinet run, and the window edge stay in frame (matches the comp) */
    object-position: 38% 60%;
}
/* the shadow overlay: bottom-heavy on phones because the content sits
   at the bottom; a left-to-right light source on desktop */
.hero__media::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(
        to top,
        rgba(35,31,32, calc(var(--overlay) * 1.08)) 0%,
        rgba(35,31,32, calc(var(--overlay) * .85)) 34%,
        rgba(35,31,32, calc(var(--overlay) * .26)) 62%,
        rgba(35,31,32, calc(var(--overlay) * .06)) 100%
    );
}

.hero__content {
    align-self: end;
    padding: calc(var(--nav-h) + 40px) var(--gutter) 22px;
    display: flex; flex-direction: column; gap: 18px;
}
/* headline + note: one block that keeps the content column's rhythm */
.hero__copy { display: flex; flex-direction: column; gap: inherit; }
.hero__title {
    font-family: var(--font-display); font-weight: 400;
    font-size: clamp(38px, 11.8vw, 56px); line-height: .96; letter-spacing: .01em;   /* 46px at 390 */
    text-transform: uppercase;
    color: var(--white);            /* plain fallback until SplitText runs (and for no-JS) */
}
.hero__title .hl, .hero__title .em { color: var(--red); display: inline-block; }      /* .em: "you", red like "a success" but not part of the reveal */

/* GRADIENT-CLIPPED TEXT, PER WORD.
   A background clipped to text only paints the element's OWN layer. The
   moment a child gets a transform (which GSAP gives every word) the
   browser composites that child separately and its glyphs fall out of
   the parent's clip: invisible text. So each word carries the gradient
   itself. script.js sizes the gradient to the headline's width and
   offsets it by the word's x, so the ramp reads as one continuous
   sweep across the line instead of restarting on every word. */
.hero__title .word {
    background-image: var(--grad-steel);
    background-repeat: no-repeat;
    -webkit-background-clip: text; background-clip: text;
    color: transparent;
}
.hero__title .hl .word, .hero__title .em .word { background-image: var(--grad-brand); }
/* THE DRAWING STATE (script.js adds .is-drawing for the drywall stage): each
   word is an outline, and a fill rises through it bottom to top as --fill
   goes 0 to 1. "you" is red and full throughout. "a success" is never
   outlined: it arrives whole with the finished kitchen. Without the class
   (no JS, reduced motion, or once the fill is done) the words are solid. */
.hero__title { --fill: 0; }
.hero__title.is-drawing .word {
    -webkit-text-stroke: 1.5px var(--white);
    background-image: linear-gradient(to top, var(--white) calc(var(--fill) * 100%), transparent calc(var(--fill) * 100%));
}
.hero__title.is-drawing .em .word { -webkit-text-stroke: 0; background-image: var(--grad-brand); }      /* "you" is full from the start: only the white words fill */

.hero__note {
    font-family: var(--font-ui); font-weight: 400; font-size: 17px; line-height: 1.5; letter-spacing: .01em;
    color: var(--white); text-shadow: 0 1px 4px rgba(35, 31, 32, .55);
    border-left: 4px solid var(--red); padding: 12px 0 12px 14px;      /* the vertical padding is what makes the red bar stand taller than the line of text */
    max-width: 60ch;
}
/* side by side when there is room; each button needs ~140px, so on a
   320px phone (276px of content) they wrap and stack instead of
   overflowing the nowrap labels */
.hero__actions { display: flex; flex-wrap: wrap; gap: 10px; }
.hero__actions .btn--outline { flex: 1 1 140px; }
.hero__actions .btn--outline { background: rgba(35, 31, 32, .42); color: var(--white); }   /* a dark backing over the photo */

/* THE TALL HERO (a trial: delete this one block to go back to the hero that
   ends at the bottom of the first screen). The headline and buttons fill
   the first full screen; the kitchen photo then carries on for another 30%
   of a screen before the shield-point edge and the credentials strip. */
@media (min-width: 768px) {      /* not on phones: a landscape photo stretched over 130% of a tall narrow screen is zoomed to mush */
    .hero { grid-template-rows: minmax(100vh, auto) 30vh auto; grid-template-rows: minmax(100svh, auto) 30svh auto; }
    .hero > .trust { grid-row: 3; }
}
/* the buttons ride down with the scroll (script.js, heroScroll, feeds --drop)
   from the foot of the first screen to the foot of the photo, so they stay
   in view through the extra stretch. On the buttons, not their row: GSAP's
   intro moves the row and, once it has, pins the row's own translate to none. */
.hero__actions .btn { translate: 0 var(--drop, 0px); }

/* TRUST: the white credentials strip under the hero photo, at every size.
   Its top edge dips to a point in the middle (the shield's V): the photo
   behind fills the dip and a red rule follows it. Phones stack the three
   credentials, centred; from 768px they sit left, centre and right. */
.trust {
    position: relative; isolation: isolate;
    display: flex; flex-direction: column; align-items: center; gap: 10px;
    padding: calc(var(--vee) + 20px) var(--gutter) 18px;
    font-family: var(--font-body); font-size: 14px; font-weight: 500; letter-spacing: .04em;
    color: var(--ink);
}
/* the white is its own layer and starts 2px BELOW the red rule's top edge,
   tucked under it. When the white and the red were cut along the very same
   diagonal, anti-aliasing let a hairline of white show above the red. */
.trust::after {
    content: ""; position: absolute; inset: 0; z-index: -1; background: var(--white);
    clip-path: polygon(0 2px, 50% calc(var(--vee) + 2px), 100% 2px, 100% 100%, 0 100%);
}
.trust::before {
    content: ""; position: absolute; left: 0; right: 0; top: 0; height: calc(var(--vee) + 5px);
    background: var(--grad-brand-smooth);
    clip-path: polygon(0 0, 50% var(--vee), 100% 0, 100% 5px, 50% calc(var(--vee) + 5px), 0 5px);
}
.trust__item { display: flex; align-items: center; gap: 8px; }
.trust__icon { display: block; width: 20px; height: 20px; flex: none; }

/* ---------- FOLLOW BAND: a second strip under the credentials ---------- */
.follow {
    display: flex; flex-direction: column; align-items: center; gap: 14px;
    background: var(--white); border-top: 1px solid var(--grey-300); border-bottom: 1px solid var(--grey-300); padding: 26px var(--gutter);
}
.follow__item { display: flex; align-items: center; gap: 12px; font-size: 15px; letter-spacing: .02em; color: var(--ink); }
.follow__link {
    display: inline-flex; align-items: center; gap: 10px; padding: 9px 18px 9px 14px;
    font-weight: 600; color: var(--ink); background: var(--white);
    border: 2px solid var(--grey-300); border-radius: 999px;       /* a pill: reads as a button, not a word */
    transition: border-color .25s, color .25s, transform .25s var(--ease-out), box-shadow .25s var(--ease-out);
}
.follow__link:hover, .follow__link:focus-visible { border-color: var(--red); color: var(--red-dark); transform: translateY(-2px); box-shadow: 0 8px 18px rgba(35, 31, 32, .14); }
.follow__icon { width: 24px; height: 24px; flex: none; }
@media (max-width: 359px) { .follow__item { font-size: 13px; gap: 7px; white-space: nowrap; } .follow__link { gap: 6px; padding: 7px 11px 7px 9px; } .follow__icon { width: 18px; height: 18px; } }   /* the smallest phones: keep each phrase on one line */
@media (min-width: 768px) {
    /* two equal halves, so the hairline between the phrases stands exactly on the
       page's centre line: plumb with the point of the V and the middle credential */
    .follow { display: grid; grid-template-columns: 1fr 1fr; gap: 0; padding: 0; }
    .follow__item { font-size: 16px; padding: 38px 24px; justify-content: center; }      /* each phrase centred in its own half */
    .follow__item + .follow__item { border-left: 1px solid var(--grey-300); }              /* the bar runs the band's full height, line to line */
    .follow__icon { width: 26px; height: 26px; }
}

/* ---------- SECTION SHELLS ---------- */
.section {
    width: 100%;
    padding: 72px var(--gutter);
    scroll-margin-top: var(--nav-h);
}
/* empty sections stay 100vw x 100vh so we can see them while building;
   a built section sizes to its content */
.section.placeholder {
    width: 100%; min-height: 100vh;   /* 100% = viewport width without the scrollbar sliver 100vw adds */
    display: grid; place-items: center;
}
.section__inner { width: min(100%, 1200px); margin-inline: auto; }
.section__head { text-align: center; max-width: 62ch; margin: 0 auto 40px; }
.section__eyebrow {
    font-family: var(--font-ui); font-weight: 500; font-size: 13px;
    letter-spacing: .18em; text-transform: uppercase; color: var(--red);
    margin-bottom: 10px;
}
.section__title {
    font-family: var(--font-display); font-weight: 400;
    font-size: clamp(40px, 8vw, 72px); line-height: 1; letter-spacing: .01em;
    text-transform: uppercase;
}
.section__lede {
    margin-top: 14px; font-size: 16px; line-height: 1.6; color: var(--ink);
}
.placeholder__note {
    margin-top: 12px; max-width: 60ch;
    font-size: 15px; color: var(--grey-700);
}

/* ---------- SERVICES ---------- */
.services { display: grid; gap: 32px; }
.service {
    display: grid; grid-template-columns: 64px 1fr; gap: 18px;
    align-items: start;
}
/* MASK, NOT IMG: an <img> can't be recoloured by CSS. Using the SVG as
   a mask means the box paints its background (the brand gradient) only
   where the icon has ink. Same trick as the trust icons, one asset each,
   and the files stay plain black SVGs that work anywhere else. */
/* two registered colours, so the icon's gradient can FADE to white (a plain
   custom property, or a gradient itself, cannot be transitioned) */
@property --ico-a { syntax: "<color>"; inherits: false; initial-value: #ED1C24; }
@property --ico-b { syntax: "<color>"; inherits: false; initial-value: #BA1E23; }
.service__icon { position: relative; width: 64px; aspect-ratio: 1; }
/* THE ICON is painted by ::after: the icon's box, masked by the SVG. Its
   fill is the brand gradient built from --ico-a / --ico-b; on hover both
   fade to white. */
.service__icon::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(90deg, var(--ico-a) 0%, var(--ico-a) 50%, var(--ico-b) 100%);
    -webkit-mask: var(--icon) center / contain no-repeat;
            mask: var(--icon) center / contain no-repeat;
    transition: --ico-a .35s ease, --ico-b .35s ease;
}
/* THE TILE is ::before: brand red with rounded corners, faded out at rest;
   on hover it fades in while the lines fade to white. It HUGS THE DRAWING,
   not the square box: each SVG's artwork sits differently inside its box
   (the kitchen and bathroom are wide and short, the other two near square),
   so each icon carries its artwork's insets (--at --ar --ab --al, measured
   from the SVGs' bounding boxes, stroke included) and the tile is that
   rectangle plus --pad. Re-measure if an icon file changes. */
.service__icon::before {
    --pad: 7px;                            /* enough that a square corner in the drawing (the shower's) clears the tile's rounded corner */
    content: ""; position: absolute; border-radius: 9px;
    inset: calc(var(--at) - var(--pad)) calc(var(--ar) - var(--pad)) calc(var(--ab) - var(--pad)) calc(var(--al) - var(--pad));
    background: var(--grad-brand);
    opacity: 0; transition: opacity .35s ease;
}
.service__icon--kitchen  { --icon: url("assets/icon-kitchen.svg"); --at: 11.48%; --ar: 3.7%; --ab: 11.48%; --al: 3.7%; }
.service__icon--bathroom { --icon: url("assets/icon-bathroom.svg"); --at: 10.69%; --ar: 3.7%; --ab: 10.68%; --al: 3.7%; }
.service__icon--basement { --icon: url("assets/icon-basement.svg"); --at: 3.7%; --ar: 4.54%; --ab: 3.71%; --al: 4.54%; }
.service__icon--other    { --icon: url("assets/icon-other.svg"); --at: 3.7%; --ar: 4.02%; --ab: 3.71%; --al: 4.02%; }
.service__title {
    font-family: var(--font-ui); font-weight: 600; font-size: 17px;
    letter-spacing: .1em; text-transform: uppercase; line-height: 1.2;
    margin-bottom: 8px;
}
.service__text { font-size: 16px; line-height: 1.6; max-width: 46ch; }
/* THE WHOLE BLOCK IS THE LINK: the title's link stretches over the block,
   so the icon is clickable too. The cue line and a small lift on the icon
   say so. */
.service { position: relative; }
}
}
.service__link { color: inherit; text-decoration: none; }
.service__link::after { content: ""; position: absolute; inset: -10px; }
.service__link:focus-visible { outline: none; }
.service:has(.service__link:focus-visible) { outline: 3px solid var(--red); outline-offset: 10px; }
.service__icon { transition: transform .35s var(--ease-out); }
.service__title { transition: color .25s; }
.service__more {
    display: inline-block; margin-top: 10px;
    font-family: var(--font-ui); font-weight: 600; font-size: 13px; letter-spacing: .12em; text-transform: uppercase;
    color: var(--red-dark); border-bottom: 2px solid transparent; transition: border-color .25s;
}
.service:hover .service__icon { transform: translateY(-4px); }
.service:hover .service__icon::before, .service:has(.service__link:focus-visible) .service__icon::before { opacity: 1; }
.service:hover .service__icon::after,  .service:has(.service__link:focus-visible) .service__icon::after  { --ico-a: #FFFFFF; --ico-b: #FFFFFF; }
@media (prefers-reduced-motion: reduce) { .service__icon, .service__icon::before, .service__icon::after { transition: none; } }
.service:hover .service__title { color: var(--red-dark); }
.service:hover .service__more, .service:has(.service__link:focus-visible) .service__more { border-bottom-color: currentColor; }

/* ---------- OUR WORK ---------- */
/* segmented control: two cards, the active one goes ink with a brand
   rule on top. role=tab buttons; the panels below are the tabpanels */
/* THE SEGMENT TABS as photo cards: the house for Residential, the
   towers for Commercial, rounded, the words on an ink fade at the foot.
   The active tab carries the gradient rule and shows its photo brighter;
   the other sits darker until chosen. */
.segments { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 32px; }
.segment {
    position: relative; overflow: hidden; isolation: isolate;
    border-radius: 16px; aspect-ratio: 3 / 4; padding: 14px;   /* tall on phones so the words have room */
    display: flex; flex-direction: column; justify-content: flex-end; gap: 6px;   /* the words stack at the foot */
    text-align: left; color: var(--white); background: var(--ink);
    box-shadow: 0 10px 26px rgba(35, 31, 32, .22);
}
.segment__photo {
    position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
    filter: saturate(.55) brightness(.75); transform: scale(1.02);
    transition: filter .35s, transform .6s var(--ease-out);
}
.segment::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(to top, rgba(35,31,32,.88) 0%, rgba(35,31,32,.4) 45%, rgba(35,31,32,.05) 80%);
}
/* the rule runs in from the left when a card is chosen, like the rails */
.segment::before {
    content: ""; position: absolute; inset: 0 0 auto 0; height: 5px; z-index: 2;
    background: var(--grad-brand);
    transform: scaleX(0); transform-origin: 0 50%; transition: transform .55s var(--ease-out);
}
.segment__title, .segment__sub { position: relative; z-index: 1; }
.segment__title {
    display: block; font-family: var(--font-display); font-size: clamp(20px, 7vw, 28px); line-height: 1;
    letter-spacing: .02em; text-transform: uppercase;
}
.segment__sub { display: block; font-size: 13px; line-height: 1.4; color: var(--grey-300); }
.segment:hover .segment__photo, .segment:focus-visible .segment__photo { filter: saturate(.9) brightness(.95); transform: scale(1.06); }
.segment.is-active .segment__photo { filter: none; transform: scale(1); }
.segment.is-active::before { transform: scaleX(1); }
.segment.is-active .segment__sub { color: var(--white); }
.segment:focus-visible { outline: 3px solid var(--red); outline-offset: 3px; }
/* the narrowest phones: the two cards stack, each a wide card */
@media (max-width: 359px) {
    .segments { grid-template-columns: 1fr; }
    .segment { aspect-ratio: 16 / 9; }
}

.work__intro { max-width: 62ch; margin: 0 auto 28px; font-size: 16px; line-height: 1.6; text-align: center; }

/* filter chips */
.filters { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-bottom: 28px; }
.filter {
    min-height: 44px; padding: 10px 18px;
    font-family: var(--font-ui); font-weight: 500; font-size: 14px;
    letter-spacing: .1em; text-transform: uppercase;
    border: 2px solid var(--grey-300); color: var(--ink);
    transition: background-color .25s, color .25s, border-color .25s;
}
.filter:hover { border-color: var(--red-dark); }
.filter.is-active { background: var(--red-dark); border-color: var(--red-dark); color: var(--white); }

/* CSS-ONLY FILTERING: the grid carries data-filter, JS only changes that
   one attribute. A pair whose category doesn't match gets display:none,
   which removes its layout box, so its lazy images never fetch. */
.gallery { display: grid; gap: 24px; }
.gallery[data-filter="kitchens"]  .pair:not([data-category="kitchens"]),
.gallery[data-filter="bathrooms"] .pair:not([data-category="bathrooms"]),
.gallery[data-filter="basements"] .pair:not([data-category="basements"]),
.gallery[data-filter="more"]      .pair:not([data-category="more"]) { display: none; }

/* THE HORIZONTAL CAROUSEL (bathrooms, more: script.js galleryCarousel adds
   .is-carousel to the window and the list, and the two arrows). The list
   becomes a row; GSAP slides it so the chosen card sits in the middle of
   the window, full size, with its neighbours peeking in smaller and dimmed
   either side. Tapping a neighbour brings it to the middle. */
.gallery-window { position: relative; }
.gallery-window.is-carousel { overflow: hidden; padding: 14px 0 12px; margin-inline: calc(-1 * var(--gutter)); }   /* out to the screen's edges: the neighbours show at the sides */
/* THE RED HAIRLINES, the reviews carousel's turned on its side: a rail along
   the top and the bottom of the window, fading out towards the ends, and a
   bar between every pair of cards that travels with them (drawn on the
   track as a repeating gradient: script.js gives it the card width and gap,
   so it is not scaled or dimmed with the neighbours). */
.gallery-window.is-carousel::before, .gallery-window.is-carousel::after {
    content: ""; position: absolute; left: 0; right: 0; height: 1px; z-index: 1; pointer-events: none; opacity: .6;
    background: linear-gradient(to right, transparent 0%, var(--red-dark) 14%, var(--red-dark) 86%, transparent 100%);
}
.gallery-window.is-carousel::before { top: 0; }
.gallery-window.is-carousel::after  { bottom: 0; }
.gallery.is-carousel { position: relative; }
.gallery.is-carousel::before {
    content: ""; position: absolute; top: -14px; bottom: -12px; left: 0; right: -600%; pointer-events: none; opacity: .6;      /* up and down through the window's padding: the bars meet the rails */
    background: repeating-linear-gradient(to right,
        transparent 0, transparent calc(var(--card-w, 560px) + var(--card-gap, 28px) / 2 - .5px),
        var(--red-dark) calc(var(--card-w, 560px) + var(--card-gap, 28px) / 2 - .5px), var(--red-dark) calc(var(--card-w, 560px) + var(--card-gap, 28px) / 2 + .5px),
        transparent calc(var(--card-w, 560px) + var(--card-gap, 28px) / 2 + .5px), transparent calc(var(--card-w, 560px) + var(--card-gap, 28px)));
}
/* the card in the middle lifts on the same soft shadow as the centred review */
.gallery.is-carousel .pair__figure { transition: box-shadow .4s var(--ease-out); }
.gallery.is-carousel .pair.is-focus .pair__figure { box-shadow: 0 22px 44px rgba(35, 31, 32, .34); }
.gallery.is-carousel { display: flex; gap: 20px; align-items: start; will-change: transform; }
.gallery.is-carousel .pair { flex: 0 0 min(78vw, 560px); scale: .88; opacity: .5; transition: scale .5s var(--ease-out), opacity .5s; }      /* scale, not transform: GSAP's fade owns transform */
.gallery.is-carousel .pair.is-focus { scale: 1; opacity: 1; }
.gallery.is-carousel .pair:not(.is-focus) .pair__media { cursor: default; }
.gal-arrow {
    position: absolute; top: 50%; translate: 0 -50%; z-index: 3;
    width: 48px; height: 48px; border-radius: 50%; display: grid; place-items: center;
    background: var(--white); color: var(--ink); border: 2px solid var(--grey-300);
    box-shadow: 0 6px 18px rgba(35, 31, 32, .22);
    transition: border-color .2s, color .2s, opacity .3s, transform .25s var(--ease-out);
}
.gal-arrow svg { width: 22px; height: 22px; }
.gal-arrow--prev { left: 10px; } .gal-arrow--next { right: 10px; }
.gal-arrow:hover, .gal-arrow:focus-visible { border-color: var(--red); color: var(--red); transform: scale(1.06); }
.gal-arrow[disabled] { opacity: .3; pointer-events: none; }
.gallery-window:not(.is-carousel) .gal-arrow { display: none; }
@media (min-width: 768px) {
    .gallery-window.is-carousel { margin-inline: 0; padding-block: 12px; }
    .gallery.is-carousel { gap: 28px; }
    .gallery.is-carousel .pair { flex-basis: min(45%, 450px); }      /* about a fifth smaller than first cut: the whole card fits a laptop screen */
    .gallery:not(.is-carousel) { max-width: 920px; margin-inline: auto; }
    .gal-arrow { width: 56px; height: 56px; }
    .gal-arrow--prev { left: 18px; } .gal-arrow--next { right: 18px; }
}
@media (prefers-reduced-motion: reduce) { .gallery.is-carousel .pair { transition: none; } }

/* BEFORE/AFTER CARD: both photos stacked in a square; the after photo
   is clipped to a zero-width strip on the left and wipes across on
   hover, or on tap via the .is-after class the flip button toggles */
.pair__figure { background: var(--white); border: 1px solid var(--grey-300); }
.pair__media { position: relative; aspect-ratio: 1; overflow: hidden; background: var(--grey-100); cursor: pointer; }
.pair__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.pair__after { clip-path: inset(0 100% 0 0); }     /* script.js wipes it in from the left */
/* THE RAIL, the reviews carousel's bar laid along the top: a thin track,
   a red fill that runs left to right with the wipe, and the two words
   as the controls, BEFORE at the left end and AFTER at the right */
.pair__rail {
    position: absolute; top: 0; left: 0; right: 0; height: 6px; z-index: 2;
    background: rgba(35, 31, 32, .35);
}
.pair__rail-fill {
    position: absolute; inset: 0;
    background: linear-gradient(to right, var(--red-dark), var(--red));
    clip-path: inset(0 100% 0 0);
}
.pair__switch {
    position: absolute; top: 6px; left: 0; right: 0; z-index: 2;
    display: flex; justify-content: space-between;
}
/* the words are buttons and look it: translucent ink cards with a
   white keyline; the active one fills red */
.pair__opt {
    margin: 10px; min-height: 36px; padding: 8px 14px;
    font-family: var(--font-ui); font-weight: 600; font-size: 12px;
    letter-spacing: .2em; text-transform: uppercase; color: var(--white);
    background: rgba(35, 31, 32, .55); border: 1px solid rgba(255, 255, 255, .6);
    backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
    transition: background-color .25s, border-color .25s;
}
.pair__opt:hover, .pair__opt:focus-visible { border-color: var(--white); background: rgba(35, 31, 32, .75); }
.pair__opt.is-on { background: var(--red-dark); border-color: var(--red-dark); }
/* THE HINT (script.js): a finger by the AFTER button of the first photo,
   its outline drawing itself in the brand gradient, until the first tap */
.pair { position: relative; }
.pair__hint {
    position: absolute; top: 46px; right: 14px; z-index: 3; width: 46px; height: 46px;
    pointer-events: none; opacity: 0;
    filter: drop-shadow(0 2px 4px rgba(35, 31, 32, .6));
}
.pair__hint path { fill: none; stroke: url(#grad-brand); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.pair__caption { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; }
.pair__title { font-family: var(--font-ui); font-weight: 600; font-size: 15px; letter-spacing: .06em; text-transform: uppercase; }

/* commercial panel: copy + property-type list */
.commercial { display: grid; gap: 32px; }
.commercial__title {
    font-family: var(--font-display); font-weight: 400; font-size: clamp(30px, 6vw, 44px);
    line-height: 1; letter-spacing: .01em; text-transform: uppercase; margin-bottom: 14px;
}
.commercial__copy p { font-size: 16px; line-height: 1.6; margin-bottom: 14px; }
.commercial__cta { margin-top: 8px; }
.commercial__list { display: grid; gap: 10px; }
.commercial__item {
    display: grid; grid-template-columns: minmax(0, 1fr) 44px; column-gap: 16px; row-gap: 2px;
    align-items: center; padding: 14px 16px;
    border-left: 4px solid var(--red); background: var(--white);
}
/* the icon sits on the right, spanning both lines: the SVG is the
   stencil, the brand gradient the paint (same trick as the services) */
.commercial__icon {
    grid-column: 2; grid-row: 1 / 3; width: 44px; aspect-ratio: 1;
    background: var(--grad-brand);
    -webkit-mask: var(--icon) center / contain no-repeat;
            mask: var(--icon) center / contain no-repeat;
}
.commercial__icon--apartment { --icon: url("assets/icon-commercial-apartment.svg"); }
.commercial__icon--funeral   { --icon: url("assets/icon-commercial-funeral.svg"); }
.commercial__icon--hospital  { --icon: url("assets/icon-commercial-hospital.svg"); }
.commercial__icon--office    { --icon: url("assets/icon-commercial-office.svg"); }
.commercial__icon--flood     { --icon: url("assets/icon-commercial-flood.svg"); }
.commercial__item strong { font-family: var(--font-ui); font-weight: 600; font-size: 15px; letter-spacing: .06em; text-transform: uppercase; }
.commercial__item span { font-size: 14px; color: var(--ink); }

/* ---------- REVIEWS: scroll carousel ----------
   Photo cards in one column. The job's BEFORE photo is the resting
   background; the AFTER photo sits on top clipped to nothing and is
   wiped in bottom-to-top by a scrubbed GSAP timeline as the card's
   middle crosses the window's middle. script.js pins the section,
   drives the column's y and every wipe from scroll position, and adds
   .is-carousel; without JS (or with reduced motion) the column is a
   plain stacked list. Text rides on a frosted panel. */
.reviews-layout { display: grid; gap: 24px; }
.reviews-window { position: relative; }
.reviews { display: flex; flex-direction: column; gap: 20px; }
.review {
    position: relative; isolation: isolate; overflow: hidden; flex: none;
    min-height: 340px;
    display: flex; flex-direction: column; justify-content: flex-end;
    padding: 14px;
    background: var(--ink); color: var(--white);
}
.review__bg { position: absolute; inset: 0; z-index: -1; }
.review__bg img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* THE WIPE. The after photo sits in a layer that GSAP animates from
   inset(100% 0 0 0) to inset(0% 0 0 0). The rail on the right edge
   has a red fill that gets the SAME tween, and the sideways "After"
   label lives inside that fill, so as the wipe rises the rail fills
   and "Before" is overtaken by "After". Only clip when a before photo
   exists underneath to reveal from. */
.review__after-layer { position: absolute; inset: 0; }
.has-before .review__after-layer,
.has-before .review__rail-fill { clip-path: inset(100% 0 0 0); }

/* the rail is a thin loading bar on the right edge */
.review__rail {
    position: absolute; top: 0; right: 0; bottom: 0; width: 6px; z-index: 2;
    background: rgba(35, 31, 32, .35);
}
.review__rail-fill {
    position: absolute; inset: 0;
    background: linear-gradient(to top, var(--red-dark), var(--red));
}
/* the tag is one sideways word just left of the bar. script.js moves
   it up with the fill's leading edge (GSAP owns its transform, so the
   180-degree turn is set there too) and flips it to AFTER halfway */
.review__tag {
    position: absolute; right: 14px; bottom: 12px; z-index: 2;
    display: grid; writing-mode: vertical-rl;
    font-family: var(--font-ui); font-weight: 600; font-size: 12px;
    letter-spacing: .2em; text-transform: uppercase; white-space: nowrap;
    color: var(--white); text-shadow: 0 1px 3px rgba(35, 31, 32, .7);
}
.review__tag-word { grid-area: 1 / 1; transition: opacity .25s; }
.review__tag-word--after { opacity: 0; }
.review__tag.is-after .review__tag-word--before { opacity: 0; }
.review__tag.is-after .review__tag-word--after  { opacity: 1; }
/* a card with no before photo parks its tag at the top */
.review:not(.has-before) .review__tag { bottom: auto; top: 12px; }
/* on the photo (phones, reduced motion) the glass panel leaves the rail and tag clear */
.review > .review__glass { margin-right: 40px; }

/* progress readout and hint: only meaningful in carousel mode */
.reviews-progress, .reviews-hint, .reviews-vprogress { display: none; }
.is-carousel .reviews-progress {
    display: flex; align-items: center; gap: 12px; margin-top: 22px;
    font-family: var(--font-ui); font-weight: 500; font-size: 14px; letter-spacing: .12em;
}
.reviews-progress__track { position: relative; flex: 1; max-width: 160px; height: 2px; background: var(--grey-300); }
.reviews-progress__fill {
    position: absolute; inset: 0; background: var(--grad-brand);
    transform-origin: left; transform: scaleX(0);
}
.reviews-progress__total { color: var(--grey-700); }
.is-carousel .reviews-hint { display: block; margin-top: 10px; font-size: 13px; color: var(--grey-700); }

/* CAROUSEL MODE: the section becomes one viewport tall (it gets
   pinned), the head sits above (phone) or beside (desktop) a window
   that clips the travelling column, with soft edges top and bottom */
.section--reviews.is-carousel {
    height: 100svh; padding: calc(var(--nav-h) + 20px) var(--gutter) 0;
    display: grid;
}
.is-carousel .reviews-layout { height: 100%; grid-template-rows: auto 1fr; min-height: 0; }
.is-carousel .reviews-head { margin-bottom: 0; }
.is-carousel .reviews-window {
    min-height: 0; overflow: hidden;
    /* ONE FADE FOR EVERYTHING IN THE WINDOW, at the top only: the photos and
       the two rails are masked together, so the pictures fade out on exactly
       the line where the red rails do. script.js sets --fade to the free
       space above the centred card, so the card in focus is never touched.
       No fade at the bottom: rails and photos run down to the edge of the
       screen and, past the pin, in under the slanted band below. */
    --fade: 48px;
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--fade));
            mask-image: linear-gradient(to bottom, transparent 0, #000 var(--fade));
}
/* THE RED HAIRLINES (carousel mode). Two rails run down the sides of the
   column and FADE OUT towards the top and bottom of the window (a gradient,
   not a hard stop); a rule sits between every pair of cards (script.js adds
   those li.reviews__rule, so the markup and the static list stay clean) and
   travels with them, solid from rail to rail. The rails are
   behind the cards. */
.is-carousel .reviews-window::before, .is-carousel .reviews-window::after {
    content: ""; position: absolute; top: 0; bottom: 0; width: 1px; z-index: 0;
    background: var(--red-dark); opacity: .6;       /* solid: the window's mask does the fading */
}
.is-carousel .reviews-window::before { left: 0; }
.is-carousel .reviews-window::after  { right: 0; }
.is-carousel .reviews { position: relative; z-index: 1; padding-inline: 16px; }      /* the cards sit just inside the rails */
.reviews__rule {
    flex: none; height: 1px; margin-inline: -16px; list-style: none; opacity: .6;
    background: var(--red-dark);      /* solid from rail to rail */
}
/* THE CARD IN FOCUS (the one the scroll has brought to the middle) lifts off
   the column on a soft shadow. No coloured frame: a solid red border around
   it was tried and dropped. */
.is-carousel .review { box-shadow: 0 0 0 rgba(35, 31, 32, 0); transition: box-shadow .4s var(--ease-out); will-change: transform; background: var(--grey-300); }      /* a light ground: if a photo is ever a beat late it is not a black slab */
.is-carousel .reviews { will-change: transform; }
.is-carousel .review.is-focus { box-shadow: 0 22px 44px rgba(35, 31, 32, .34); z-index: 2; }
@media (prefers-reduced-motion: reduce) { .is-carousel .review { transition: none; } }
.is-carousel .review { min-height: 300px; }
.is-carousel .section__lede { display: none; }   /* phone height budget: the review text takes its place */

/* the active review's text, moved into the left column by script.js.
   There it is A WHITE CARD like a reviews widget: the name in red with the
   stars under it, the Facebook mark top right (every review is from
   Facebook; the word stays in the markup for screen readers), the quote,
   then See the job. The footer is display:contents so its name, source
   and button can take their own cells of the card's grid. */
.reviews-current { margin-top: 20px; }
.reviews-current .review__glass {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 16px;
    padding: 22px 24px 12px;
    background: var(--white); border: 0; border-top: 3px solid var(--red);
    box-shadow: 0 14px 34px rgba(35, 31, 32, .13), 0 2px 6px rgba(35, 31, 32, .06);
    -webkit-backdrop-filter: none; backdrop-filter: none;
    color: var(--ink);
}
.reviews-current .review__glass::before { display: none; }
.reviews-current .review__meta { display: contents; }
.reviews-current .review__name { grid-area: 1 / 1; font-size: 17px; color: var(--red-dark); }
.reviews-current .review__stars { grid-area: 2 / 1; }
.reviews-current .review__source {
    grid-area: 1 / 2 / span 2 / auto; align-self: center;
    width: 34px; height: 34px; overflow: hidden; font-size: 0; color: transparent;
    background: url("assets/icon-facebook.svg") center / contain no-repeat;
}
.reviews-current .review__quote { grid-area: 3 / 1 / auto / -1; margin-top: 12px; padding-bottom: 10px; }
.reviews-current .review__quote p { font-size: 17px; }
.reviews-current .review__job { grid-area: 4 / 1 / auto / -1; justify-self: end; margin: 0; color: var(--red-dark); }
/* GLASS: a translucent ink tint plus backdrop blur. The blur samples
   the photo behind the panel, so the panel reads as frosted glass
   rather than a grey box. Browsers without backdrop-filter just get
   the tint, which is still legible. */
.review__glass {
    position: relative;
    display: flex; flex-direction: column; gap: 12px;
    padding: 18px 18px 14px;
    background: rgba(35, 31, 32, .58);
    -webkit-backdrop-filter: blur(14px) saturate(1.3);
            backdrop-filter: blur(14px) saturate(1.3);
    border: 1px solid rgba(255, 255, 255, .16);
}
/* opening quote mark as a decoration, in the display face */
.review__glass::before {
    content: "\201C"; position: absolute; top: 4px; right: 14px;
    font-family: var(--font-display); font-size: 84px; line-height: 1;
    color: var(--red); opacity: .55; pointer-events: none;
}
.review__stars { display: flex; gap: 3px; }
.review__star { width: 17px; height: 17px; fill: var(--gold); }
.review__quote p { font-size: 16px; line-height: 1.6; }
.review--featured .review__quote p { font-size: 17px; }
.review__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; }
.review__name {
    font-style: normal; font-family: var(--font-ui); font-weight: 600; font-size: 15px;
    letter-spacing: .08em; text-transform: uppercase;
}
.review__source { font-size: 13px; color: var(--grey-300); }
.review__job {
    margin-left: auto; min-height: 44px; padding: 8px 0;
    font-family: var(--font-ui); font-weight: 500; font-size: 13px; letter-spacing: .08em; text-transform: uppercase;
    color: var(--white); border-bottom: 2px solid var(--red);
}
.review__job::after { content: " \2197"; }
.review__job { text-decoration: none; display: inline-block; }      /* the link form too (a review that points at a Facebook post) */
/* a long review shows its first lines and trails off in "..."; the link under it opens the whole post */
.reviews-current .review__quote--long p { display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden; }
@media (max-width: 767px) { .reviews-current .review__quote--long p { -webkit-line-clamp: 4; } }

/* ---------- MEET PHIL: a two-beat story ----------
   Each beat is a photo and a block of copy. Phones stack photo over
   copy; from 768px the beats sit side by side and alternate sides, so
   the eye travels family -> craft down the page. */
.story { display: grid; gap: 48px; counter-reset: beat; }
.beat { display: grid; gap: 20px; }
.beat__media { position: relative; }
.beat__photo { width: 100%; height: auto; display: block; }
/* two corners rounded, two square, mirrored between the beats: the
   family photo rounds top-right and bottom-left, the craft photo
   top-left and bottom-right, so the pair reads as a matched set */
.beat:nth-child(odd)  .beat__photo { border-radius: 0 56px 0 56px; }
.beat:nth-child(even) .beat__photo { border-radius: 56px 0 56px 0; }
/* THE MORPH (beat 1): one frame, two photos. Static (no JS, reduced
   motion): a 3:2 frame showing the family. Live (.is-live, script.js): the
   stage reserves a fixed block (16:15, caption included) and the frame
   inside it starts portrait-shaped on Phil, then reshapes to landscape as
   the page scrolls, the photos crossfading. Centred in the stage, so the
   frame grows sideways and shrinks vertically without moving the page. */
.morph__frame { position: relative; overflow: hidden; aspect-ratio: 3 / 2; border-radius: 0 56px 0 56px; background: var(--grey-300); }
.beat .morph__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
.morph__img--self { opacity: 0; }
/* FIT THE SCREEN: both photo blocks are sized from the viewport's height
   (less the header bar and some air), so the whole photo is visible at
   once and never needs scrolling; the width follows from the shape. */
.morph.is-live {
    aspect-ratio: 16 / 15; display: flex; flex-direction: column; justify-content: flex-start; align-items: center;   /* the frame hangs from the top: when it flattens, the spare room collects below it */
    width: min(100%, calc((100svh - 170px) * 16 / 15)); margin-inline: auto;
}
.morph.is-live .morph__frame { flex: none; width: 66%; aspect-ratio: 3 / 4; }     /* script.js drives both from here */
.morph.is-live .beat__caption { align-self: flex-start; }
/* THE STACK (beat 2): three prints on one spot, the last on top and
   square to the frame, the two under it turned a few degrees so their
   corners show. script.js flies them in from the left to these resting
   transforms (kept in step with STACK_REST there). */
.stack { position: relative; aspect-ratio: 4 / 5; width: min(100%, calc((100svh - 200px) * 4 / 5)); margin-inline: auto; }
.beat .stack__photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; box-shadow: 0 2px 5px rgba(35, 31, 32, .38), 0 14px 30px rgba(35, 31, 32, .34); }   /* a tight contact shadow plus a cast one: each print visibly sits ON the one below */
.stack__photo:nth-child(1) { transform: translate(-20px, 14px) rotate(-5deg); }
.stack__photo:nth-child(2) { transform: translate(16px, -12px) rotate(3.5deg); }
.beat__media .beat__caption { margin-top: 12px; }
/* under the stack: clear of the tilted prints' corners, and lined up with the stack, not the column */
.beat--work .beat__caption { width: min(100%, calc((100svh - 200px) * 4 / 5)); margin: 46px auto 0; }
/* THE LAST WORD. At rest "integrity" is bold in the wordmark's red. While
   script.js types the paragraph it is first typed plain (.is-plain),
   backspaced under the cursor, then retyped like this. */
.type-word { font-weight: 700; color: var(--red-dark); }
.type-word.is-plain { font-weight: inherit; color: inherit; }
.type-cursor { display: inline-block; margin-left: 1px; font-weight: 400; color: var(--ink); animation: type-blink .9s steps(1) infinite; }
@keyframes type-blink { 50% { opacity: 0; } }
/* THE FLIP BUTTON: a labelled pill in the stack's bottom right, tucked
   inside the top photo's rounded corner. Sends the top print to the
   back of the pile. Same translucent ink + white keyline as the
   BEFORE / AFTER buttons. */
.stack__next {
    position: absolute; right: 40px; bottom: 26px; z-index: 20;
    display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 8px 16px 8px 12px; border-radius: 22px;
    font-family: var(--font-ui); font-weight: 600; font-size: 12px; letter-spacing: .14em; text-transform: uppercase; white-space: nowrap;
    color: var(--white); background: rgba(35, 31, 32, .62); border: 1px solid rgba(255, 255, 255, .7);
    -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
    transition: background-color .25s, border-color .25s, transform .25s var(--ease-out);
}
.stack__next svg { width: 20px; height: 20px; flex: none; }
.stack__next:hover, .stack__next:focus-visible { background: var(--red-dark); border-color: var(--red-dark); transform: translateY(-2px); }
.beat__caption {
    margin-top: 10px; font-family: var(--font-ui); font-weight: 500; font-size: 13px;
    letter-spacing: .1em; text-transform: uppercase; color: var(--grey-700);
}
.beat__step {
    font-family: var(--font-ui); font-weight: 500; font-size: 13px;
    letter-spacing: .18em; text-transform: uppercase; color: var(--red); margin-bottom: 8px;
}
.beat__title {
    font-family: var(--font-display); font-weight: 400; font-size: clamp(30px, 6vw, 44px);
    line-height: 1; letter-spacing: .01em; text-transform: uppercase; margin-bottom: 14px;
}
.beat__body p:not(.beat__step) { font-size: 16px; line-height: 1.65; margin-bottom: 14px; }
.about__cta-row { text-align: center; margin-top: 48px; }
/* THE ARROW (script.js, ctaArrow): an SVG laid over the section's inner
   box, drawn in its pixel space. A thin black line from under the work
   text, curving down and across to the estimate button, with a small
   symmetrical head. Clean and flat like the rest of the site (a fat
   textured "marker" version was tried and dropped: it fought the design). */
.section--phil .section__inner { position: relative; }
.cta-arrow { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 1; }
.cta-arrow path { fill: none; stroke: var(--ink); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- AREAS SERVED (screen 1: copy + list) ---------- */
.section--areas { min-height: 100svh; display: grid; align-content: center; }
.areas { display: grid; gap: 28px; }
.areas--list .areas__body { max-width: 900px; margin-inline: auto; }

/* ---------- SERVICE CHECK (screen 2: full-bleed map + address panel) ---------- */
/* .section.section--check: two classes so this beats the desktop
   .section { padding: 96px } rule that comes later in the file */
.section.section--check { padding: 0; height: 100svh; min-height: 640px; position: relative; scroll-margin-top: 0; }
/* isolation: Leaflet's panes carry z-index 400+; this keeps them inside
   the section's own stacking context so they can never sit over the
   fixed nav (z-index 50 in the root context) */
.check { position: relative; height: 100%; isolation: isolate; }
/* thin brand-gradient rules along the map's top and bottom edges, above Leaflet's panes and the panel */
.check::after {
    content: ""; position: absolute; inset: 0; z-index: 600; pointer-events: none;
    border-style: solid; border-width: 4px 0; border-image: var(--grad-brand) 1;
}
.check__map { position: absolute; inset: 0; background: var(--grey-100); }
.check__map .areas__svg { width: 100%; height: 100%; }
.check__panel {
    position: absolute; left: 14px; right: 14px; bottom: 14px; z-index: 500;   /* above Leaflet's panes (400) */
    max-height: calc(100% - 28px);                            /* never taller than the map it sits on */
    overflow: visible;                                        /* the suggestion list may hang outside the panel */
    padding: 16px 18px 12px;
    background: rgba(255, 255, 255, .94);
    -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
    border: 1px solid var(--grey-300); border-top: 4px solid; border-image: var(--grad-brand) 1;
    box-shadow: 0 12px 40px rgba(35, 31, 32, .22);
}
.check__title {
    font-family: var(--font-display); font-weight: 400; font-size: clamp(28px, 5vw, 34px);
    line-height: 1; letter-spacing: .01em; text-transform: uppercase; margin: 0 0 10px;
}
.check__label { display: block; font-family: var(--font-ui); font-weight: 500; font-size: 12px; letter-spacing: .1em; text-transform: uppercase; margin-bottom: 4px; }
.check__field { position: relative; margin-bottom: 10px; }
.check__grid { display: grid; grid-template-columns: minmax(0, 1fr) 64px 92px; gap: 8px; }
.check__input {
    width: 100%; min-width: 0; min-height: 46px; padding: 9px 12px;
    font: inherit; font-size: 16px; color: var(--ink);
    background: var(--white); border: 2px solid var(--grey-300); border-radius: 0;
}
.check__input:focus { outline: none; border-color: var(--red-dark); }
.check__btn { width: 100%; margin-top: 4px; }
/* suggestion listbox under the street field */
.check__suggest {
    position: absolute; left: 0; right: 0; z-index: 10;
    max-height: 260px; overflow-y: auto;
    background: var(--white); border: 2px solid var(--red-dark);
    box-shadow: 0 12px 28px rgba(35, 31, 32, .22);
    /* phones: the panel is docked at the bottom, so the list opens UP */
    bottom: 100%; border-bottom: 0;
}
@media (min-width: 768px) {
    .check__suggest { bottom: auto; top: 100%; border-top: 0; border-bottom: 2px solid var(--red-dark); }   /* desktop: opens down */
}
.check__option { padding: 10px 12px; font-size: 14px; line-height: 1.3; cursor: pointer; border-top: 1px solid var(--grey-100); }
.check__option strong { display: block; font-weight: 500; }
.check__option span { color: var(--grey-700); font-size: 13px; }
.check__option:hover, .check__option[aria-selected="true"] { background: #FBE4E5; }
.check__result { margin-top: 10px; font-size: 15px; line-height: 1.5; }
.check__result:empty { display: none; }
.check__result.is-yes { color: #1D7A3A; font-weight: 500; }
.check__result.is-no  { color: var(--red-dark); font-weight: 500; }
.check__result.is-err { color: var(--grey-700); }
.check__result a { color: var(--red-dark); text-decoration: underline; text-underline-offset: 3px; }
.check__note { margin-top: 8px; font-size: 12px; line-height: 1.4; color: var(--grey-700); }
/* the checked address on the map */
/* ---------- SERVICE AREA EDITOR (only with ?edit-area in the URL) ---------- */
.section--check.is-editing .check__panel { display: none; }
.section--check.is-editing .check__map { cursor: crosshair; }
.area-editor {
    position: absolute; left: 14px; right: 14px; bottom: 14px; z-index: 600;
    display: grid; gap: 8px;
    padding: 12px 14px;
    background: rgba(255, 255, 255, .96); border: 2px solid var(--ink);
    font-size: 13px; line-height: 1.4;
}
.area-editor strong { font-family: var(--font-ui); font-weight: 600; font-size: 14px; letter-spacing: .1em; text-transform: uppercase; }
.area-editor__status { color: var(--grey-700); }
.area-editor__row { display: flex; flex-wrap: wrap; gap: 6px; }
.area-editor button {
    min-height: 36px; padding: 6px 12px;
    font-family: var(--font-ui); font-weight: 500; font-size: 13px; letter-spacing: .06em; text-transform: uppercase;
    color: var(--white); background: var(--ink);
}
.area-editor button[data-act="export"] { background: var(--red-dark); }
.area-editor__out { width: 100%; font: 12px/1.3 monospace; padding: 6px; border: 1px solid var(--grey-300); resize: vertical; }
.area-editor p { color: var(--grey-700); margin: 0; }
@media (min-width: 768px) { .area-editor { left: auto; width: min(560px, 46vw); } }

/* a white halo behind the red pin so it reads on the grey map, plus a drop */
.map-pin img {
    display: block;
    filter: drop-shadow(0 0 1.5px #FFFFFF) drop-shadow(0 0 1.5px #FFFFFF) drop-shadow(0 3px 4px rgba(35, 31, 32, .45));
}
.areas__svg { width: 100%; height: 100%; display: block; background: var(--grey-100); }
.check__map.is-live .areas__svg { display: none; }     /* the live map took over */
/* Leaflet as a static cutout: blank outside the counties, basemap in
   brand greys inside (the grayscale filter hits the tile pane only, so
   the red outlines and ink markers in the other panes keep their colour) */
.leaflet-container { font-family: var(--font-body); background: var(--white); cursor: default; }
.leaflet-tile-pane { filter: grayscale(1) contrast(.9) brightness(1.06); }
.map-clip { position: absolute; width: 0; height: 0; }
.leaflet-control-attribution {
    margin: 0 8px 8px 0 !important; padding: 2px 8px;
    font-family: var(--font-body, inherit); font-size: 10px; line-height: 1.6;
    background: rgba(255, 255, 255, .85); color: var(--grey-700);
}
.leaflet-control-attribution a { color: var(--grey-700); }
.map-tip {
    font-family: var(--font-ui); font-weight: 500; font-size: 12px; letter-spacing: .08em; text-transform: uppercase;
    color: var(--ink); background: var(--white); border: 1px solid var(--grey-300); border-radius: 0;
    box-shadow: 0 4px 14px rgba(35, 31, 32, .18); padding: 3px 7px;
}
.map-tip--pin { background: rgba(255, 255, 255, .9); border-color: transparent; box-shadow: none; padding: 1px 5px; }
.map-tip--pin::before { display: none; }
.map-tip--home { color: var(--red-dark); font-weight: 600; border-color: var(--red); }
@media (max-width: 767px) { .map-tip--pin { display: none; } }   /* phones: dots and the home label only; hover/tap still names a town */
.map-home img { display: block; width: 100%; height: 100%; max-width: none; filter: drop-shadow(0 0 1.5px #fff) drop-shadow(0 2px 3px rgba(35, 31, 32, .45)); }   /* fixed size (the global img rule must not squash it); a white halo lifts it off the place names under it */
/* the map's own styling (SVG fallback): red service counties, ink cities */
.map__neighbor { fill: var(--grey-100); stroke: var(--grey-500); stroke-width: 1.2; stroke-linejoin: round; }
.map__neighbor-label {
    font-family: var(--font-ui); font-weight: 500; font-size: 17px; letter-spacing: .12em; text-transform: uppercase;
    fill: var(--grey-500); text-anchor: middle; pointer-events: none;
}
.map__ring { fill: url(#map-ring-fill); stroke: var(--red); stroke-width: 2.5; stroke-dasharray: 10 8; }
.map__county { fill: var(--white); stroke: var(--red-dark); stroke-width: 2; stroke-linejoin: round; transition: fill .25s; }
.map__county:hover { fill: #FBE4E5; }
.map__county-label {
    font-family: var(--font-display); font-size: 30px; letter-spacing: .06em; text-transform: uppercase;
    fill: var(--grey-500); text-anchor: middle; pointer-events: none;
}
.map__city circle { fill: var(--ink); stroke: var(--white); stroke-width: 1.5; }
.map__city text { font-family: var(--font-body); font-size: 14px; font-weight: 500; fill: var(--ink); paint-order: stroke; stroke: var(--white); stroke-width: 4px; stroke-linejoin: round; }
.map__home-halo { fill: var(--red); opacity: .18; }
.map__home-dot { fill: var(--red-dark); stroke: var(--white); stroke-width: 3; }
.map__home-label { font-family: var(--font-ui); font-weight: 600; font-size: 15px; letter-spacing: .1em; text-transform: uppercase; fill: var(--red-dark); text-anchor: middle; paint-order: stroke; stroke: var(--white); stroke-width: 5px; stroke-linejoin: round; }
.map__ring-label { font-family: var(--font-ui); font-weight: 500; font-size: 14px; letter-spacing: .14em; text-transform: uppercase; fill: var(--red-dark); }
@media (max-width: 767px) {
    .map__city text { font-size: 17px; }
    .map__county-label { font-size: 36px; }
    .map__home-label { font-size: 18px; }
    .map__neighbor-label { font-size: 22px; }
}
.areas__copy { font-size: 16px; line-height: 1.65; margin-bottom: 20px; }
.counties { display: grid; gap: 10px; }
.county { padding: 12px 16px; border-left: 4px solid var(--red); background: var(--white); }
.county__name { font-family: var(--font-ui); font-weight: 600; font-size: 15px; letter-spacing: .06em; text-transform: uppercase; margin-bottom: 2px; }
.county__cities { font-size: 14px; line-height: 1.5; }
.areas__note { margin-top: 18px; font-size: 14px; color: var(--grey-700); }
.areas__link { color: var(--red-dark); text-decoration: underline; text-underline-offset: 3px; }

/* ---------- QUALIFICATIONS: badge row ---------- */
.badges { display: grid; grid-template-columns: 1fr; gap: 36px; }      /* phones: one badge per row, each whole and centred (two across left an odd one out and ragged titles) */
@media (min-width: 600px) { .badges { grid-template-columns: repeat(3, 1fr); gap: 28px 16px; } }
.badge {
    display: grid; justify-items: center; align-content: start; text-align: center; gap: 10px;
    padding: 8px 6px;
    /* align-content start: the row stretches every badge to the tallest
       one, and stretched rows would push a short badge's title down */
}
/* same mask trick as the service icons: the SVG is the stencil, the
   brand gradient is the paint */
.badge__mark {
    width: 96px; aspect-ratio: 1;
    background: var(--grad-brand);
    -webkit-mask: var(--icon) center / contain no-repeat;
            mask: var(--icon) center / contain no-repeat;
}
.badge__mark--ohio  { --icon: url("assets/icon-ohio.svg"); }
.badge__mark--water { --icon: url("assets/icon-water.svg"); }
.badge__mark--plank { --icon: url("assets/icon-plank.svg"); }
/* the issuer logos are the point of the card: big, with the title and
   the description under them; the wide IICRC lockup is shorter so its
   width fits the card */
.badge__logo { height: 96px; width: 100%; object-fit: contain; }   /* every logo gets the same slot, so the titles line up */
.badge__logo--wide { object-fit: contain; max-width: 250px; }                          /* the wide IICRC lockup just letterboxes inside it */
/* FAQ: an accordion of questions with red hairlines between them and a
   plus that turns into a minus. THE FOOT IS THE HERO'S SHIELD POINT: the
   section is clipped to a shallow V with the red rule along the cut, and it
   rides down over the top of the contact section by the depth of the V. */
.section--faq {
    --vee: clamp(22px, 3.4vw, 62px);
    position: relative; isolation: isolate; z-index: 2;
    margin-bottom: calc(-1 * var(--vee) - 1px); padding-bottom: calc(var(--vee) + 72px);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--vee)), 50% 100%, 0 calc(100% - var(--vee)));
}
.section--faq::before {                     /* the white stops 2px above the cut, tucked under the red rule (no hairline beneath) */
    content: ""; position: absolute; inset: 0; z-index: -1; background: var(--white);
    border-radius: 28px 28px 0 0;                                       /* a card's top corners: it slides up over Qualifications */
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--vee) - 2px), 50% calc(100% - 2px), 0 calc(100% - var(--vee) - 2px));
}
.section--faq::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: calc(var(--vee) + 5px); pointer-events: none;
    background: var(--grad-brand-smooth);
    clip-path: polygon(0 0, 50% var(--vee), 100% 0, 100% 5px, 50% 100%, 0 5px);
}
.faq { max-width: 820px; margin-inline: auto; border-top: 1px solid rgba(186, 30, 35, .45); }
.faq__item { border-bottom: 1px solid rgba(186, 30, 35, .45); }
.faq__q {
    list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 18px;
    padding: 20px 4px; min-height: 64px;
    font-family: var(--font-ui); font-weight: 600; font-size: 16px; letter-spacing: .02em; line-height: 1.35; color: var(--ink);
    transition: color .2s;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q:hover, .faq__q:focus-visible, .faq__item[open] .faq__q { color: var(--red-dark); }
.faq__q:focus-visible { outline: 3px solid var(--red); outline-offset: 4px; }
/* the plus: two bars painted in the brand gradient; the upright one turns away when open */
.faq__mark { position: relative; flex: none; width: 22px; height: 22px; }
.faq__mark::before, .faq__mark::after {
    content: ""; position: absolute; left: 50%; top: 50%; translate: -50% -50%; background: var(--grad-brand);
    width: 22px; height: 2.5px; border-radius: 2px; transition: rotate .35s var(--ease-out), opacity .3s;
}
.faq__mark::after { rotate: 90deg; }
.faq__item[open] .faq__mark::after { rotate: 0deg; opacity: 0; }
.faq__a { overflow: hidden; }
.faq__a-inner { padding: 0 4px 24px; }
.faq__a p { font-size: 16px; line-height: 1.65; max-width: 66ch; color: var(--ink); }
@media (min-width: 768px) {
    .faq__q { font-size: 18px; padding: 24px 6px; }
    .faq__a-inner { padding: 2px 6px 30px; }
    .faq__a p { font-size: 17px; }
}
@media (prefers-reduced-motion: reduce) { .faq__mark::before, .faq__mark::after { transition: none; } }
.badge__title { font-family: var(--font-ui); font-weight: 600; font-size: 14px; letter-spacing: .08em; text-transform: uppercase; line-height: 1.25; }
.badge__text { font-size: 14px; line-height: 1.5; color: var(--ink); max-width: 30ch; }

/* ---------- CONTACT: the split shield ----------
   Grid of three: the shield's left half, the white panel, the shield's
   right half. The halves are the real shield paths in two viewBoxes
   (one per side of the centre line), stretched to the panel's height
   with preserveAspectRatio none, so their outer contours become the
   card's sides. --cap is how wide each half is. */
.section.section--contact {
    background: var(--grey-900);
    min-height: 100svh; display: grid; align-content: center;
    padding: calc(var(--nav-h) + 24px) var(--gutter) 40px;
    scroll-margin-top: 0;                  /* its own padding clears the bar */
}
.shield-card__wrap { filter: drop-shadow(0 26px 34px rgba(35, 31, 32, .4)); }
.shield-card {
    --cap: 34px;
    position: relative;
    display: grid; grid-template-columns: var(--cap) minmax(0, 1fr) var(--cap);
}
.shield-card__cap { position: relative; }
.shield-card__half { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.shield-card__panel { background: var(--white); color: var(--ink); padding: 26px 16px 26px; }
/* the intro wordmark under the resting shield; script.js positions it
   and reveals it, so it starts invisible and never catches a click */
.shield-card__lockup {
    position: absolute; left: 50%; top: 50%; transform: translateX(-50%);
    text-align: center; white-space: nowrap; pointer-events: none; opacity: 0; z-index: 3;
}
.lockup__name {
    font-family: var(--font-display); font-size: clamp(44px, 8vw, 76px); line-height: 1;
    letter-spacing: .05em; text-transform: uppercase; color: var(--red);
}
.lockup__tag {
    font-family: var(--font-ui); font-weight: 600; font-size: clamp(13px, 2.3vw, 22px); line-height: 1.2;
    letter-spacing: .14em; text-transform: uppercase; color: var(--ink); margin-top: 6px;
}
.lockup__name .char, .lockup__tag .char { display: inline-block; }
.shield-card__content { display: grid; gap: 36px; }
.shield-card .form__row { grid-template-columns: 1fr; }   /* name, phone, email stack at every width */
.shield-card__content .section__eyebrow { text-align: left; }
.contact-card__title { margin-top: 4px; }
.contact-card__copy { font-size: 16px; line-height: 1.65; margin: 14px 0 26px; max-width: 52ch; }
.contact-card__side { border-top: 1px solid var(--grey-300); padding-top: 30px; }
/* the portrait: a plain circle, centred in its column */
.contact-card__portrait { width: 160px; height: 160px; margin: 0 auto 18px; border-radius: 50%; }
.contact-card__photo { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.contact-card__sub {
    font-family: var(--font-display); font-weight: 400; font-size: 28px; line-height: 1;
    letter-spacing: .02em; text-transform: uppercase; margin-bottom: 16px;
}
.steps { display: grid; gap: 14px; margin-bottom: 30px; }
.step { display: grid; grid-template-columns: 34px 1fr; gap: 12px; align-items: start; }
.step__num { font-family: var(--font-display); font-size: 26px; line-height: 1; color: var(--red); padding-top: 2px; }
.step p { font-size: 15px; line-height: 1.55; }
.step strong { font-weight: 600; }
.contact__details { display: grid; gap: 12px; margin-bottom: 26px; }
.contact__detail { display: grid; grid-template-columns: 20px 1fr; gap: 12px; align-items: start; font-size: 15px; line-height: 1.4; }
.contact__icon { width: 20px; height: 20px; color: var(--red-dark); margin-top: 1px; }
.contact__link { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--red); }
.socials { display: flex; gap: 12px; }
.social {
    display: inline-flex; align-items: center; justify-content: center;
    width: 46px; height: 46px; border-radius: 50%;
    background: var(--ink); color: var(--white);
    transition: background-color .2s, transform .2s var(--ease-out);
}
.social svg { width: 22px; height: 22px; }
.social:hover, .social:focus-visible { background: var(--red-dark); transform: translateY(-2px); }

/* THE FORM: boxed fields and the choice groups as chips (the gallery
   filter pattern), sitting inside the contact card */
.form { position: relative; }
.form__hp { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }   /* the honeypot, off-screen for people */
.form__field, .form__group { margin-bottom: 18px; }
.form__row { display: grid; gap: 0 16px; }
.form__label {
    display: block; margin-bottom: 6px;
    font-family: var(--font-ui); font-weight: 600; font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink);
}
.form__input {
    display: block; width: 100%; min-height: 48px; padding: 10px 14px;
    font: inherit; font-size: 16px; color: var(--ink);
    background: var(--white); border: 2px solid var(--grey-300); border-radius: 0;
    transition: border-color .2s;
}
.form__input::placeholder { color: var(--grey-500); }
.form__input:hover { border-color: var(--grey-500); }
.form__input:focus { outline: none; border-color: var(--red-dark); }
.form__input.is-invalid { border-color: var(--red); }
.form__textarea { min-height: 140px; line-height: 1.5; resize: vertical; }
/* chips: the real radio is visually hidden but keeps focus and the
   keyboard; the chip shows the state */
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip { position: relative; cursor: pointer; }
.chip input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.chip span {
    display: inline-flex; align-items: center; min-height: 44px; padding: 10px 16px;
    font-family: var(--font-ui); font-weight: 500; font-size: 14px; letter-spacing: .08em; text-transform: uppercase;
    border: 2px solid var(--grey-300); color: var(--ink);
    transition: background-color .2s, border-color .2s, color .2s;
}
.chip:hover span { border-color: var(--red-dark); }
.chip input:checked + span { background: var(--red-dark); border-color: var(--red-dark); color: var(--white); }
.chip input:focus-visible + span { outline: 3px solid var(--red); outline-offset: 2px; }
.form__help { margin-top: 8px; font-size: 13px; color: var(--grey-700); }
.form__error { margin: 0 0 12px; font-size: 14px; color: var(--red-dark); font-weight: 500; }
.form__foot { display: flex; flex-direction: column; gap: 10px; align-items: flex-start; margin-top: 4px; }
.form__note { font-size: 12px; line-height: 1.4; color: var(--grey-700); }

/* ---------- UTILITY PAGES (404, thanks) ----------
   The CSP has no 'unsafe-inline' for styles, so these pages cannot use
   style attributes; everything they need is a class here. */
.page-full { min-height: 100vh; display: grid; align-items: center; }
.page-logo { width: 220px; height: auto; margin-bottom: 32px; }
.page-lede { margin-top: 14px; }
.page-links { display: grid; gap: 8px; margin: 24px 0 32px; font-size: 16px; }
.page-links a { color: var(--red-dark); text-decoration: underline; text-underline-offset: 3px; }
.page-cta { margin-top: 32px; }
/* a document page (privacy): readable measure, plain headings */
.page-doc { align-items: start; padding-top: 48px; }
.page-doc .section__inner { max-width: 720px; }
.page-doc .section__title { font-size: clamp(36px, 5vw, 56px); }
.doc__updated { font-size: 14px; color: var(--grey-700); margin: 8px 0 32px; }
.doc__h { font-family: var(--font-ui); font-weight: 600; font-size: 14px; letter-spacing: .12em; text-transform: uppercase; color: var(--red-dark); margin: 32px 0 10px; }
.page-doc p { font-size: 16px; line-height: 1.65; }
.page-doc p + p { margin-top: 12px; }
.page-doc p a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--red); }
.cookies__link { color: var(--red-dark); text-decoration: underline; text-underline-offset: 2px; margin-left: 4px; }

/* ---------- JOB DIALOG ---------- */
.job {
    width: min(100% - 32px, 720px); padding: 0; border: 0;
    margin: auto;                    /* the reset zeroed the UA's margin:auto, which is what centres a modal dialog */
    max-height: calc(100svh - 32px); overflow: auto;
    background: var(--white); color: var(--ink);
    box-shadow: 0 24px 64px rgba(35, 31, 32, .45);
}
/* cap the photo so title + photo + actions fit a 900px-tall screen
   without the dialog needing to scroll */
.job__body .pair__media { aspect-ratio: auto; height: min(58svh, 520px); }
.job::backdrop { background: rgba(35, 31, 32, .82); }
.job[open] { animation: job-in .35s var(--ease-out); }
@keyframes job-in { from { opacity: 0; transform: translateY(16px) scale(.98); } }
.job__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 16px 12px 20px; }
.job__title { font-family: var(--font-display); font-weight: 400; font-size: 28px; line-height: 1; letter-spacing: .02em; text-transform: uppercase; }
.job__close { width: 44px; height: 44px; font-size: 32px; line-height: 1; color: var(--ink); transition: color .2s; }
.job__close:hover, .job__close:active, .job__close:focus-visible { color: var(--red); }
.job__body .pair__figure { border: 0; }
.job__more {
    display: block; padding: 14px 20px 18px;
    font-family: var(--font-ui); font-weight: 500; font-size: 13px; letter-spacing: .1em; text-transform: uppercase;
    color: var(--red-dark);
}
body.has-dialog { overflow: hidden; }
/* alternating surfaces so the empty sections are visible while we build */
.section--services  { background: var(--white); }
.section--work      { background: var(--grey-100); }

/* ---------- DIVIDER: the slanted photo band between Services and Our Work ---------- */
.divider {
    --slant: 9vw;                                   /* the rise of each cut edge */
    --above: var(--white); --below: var(--grey-100);   /* the neighbours' colours fill the corners */
    position: relative; height: clamp(346px, 61vh, 746px);      /* a tall band: about three fifths of a screen */
    background: linear-gradient(to bottom, var(--above) 50%, var(--below) 50%);
}
.divider__media {
    position: absolute; inset: 0; overflow: hidden; background: var(--ink);
    clip-path: polygon(0 0, 100% var(--slant), 100% 100%, 0 calc(100% - var(--slant)));
}
.divider__photo { will-change: transform; display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 45%; }
/* a two-stage band (data-step): the finished photo sits in a layer over the
   first and is clipped to nothing until script.js wipes it down */
.divider__after { position: absolute; inset: 0; clip-path: inset(0 0 100% 0); }
@media (prefers-reduced-motion: reduce) { .divider__after { clip-path: none; } }
/* a pair: two photos side by side with a red seam */
.divider__media--pair { display: grid; grid-template-columns: 1fr 1fr; }
.divider__half { position: relative; overflow: hidden; }
.divider__half + .divider__half { border-left: 4px solid var(--red); }
.divider__photo--phil { object-position: 50% 30%; }
.divider__photo--gabe { object-position: 62% 35%; }
@media (max-width: 767px) {                     /* phones: one above the other, so each photo is the full width and the men are seen */
    .divider__media--pair { grid-template-columns: 1fr; grid-template-rows: 1fr 1fr; }
    .divider__half + .divider__half { border-left: 0; border-top: 4px solid var(--red); }
    .divider__photo--phil { object-position: 50% 22%; }
    .divider__photo--gabe { object-position: 70% 30%; }
}
/* ink tint so the band sits with the dark hero and the grey section, not a bright hole */
.divider__media::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(90deg, rgba(35,31,32,.55) 0%, rgba(35,31,32,.25) 60%, rgba(35,31,32,.45) 100%);
}
/* a brand-red rule along the top cut, like the one under the hero */
.divider::before {
    content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
    background: var(--red);
    clip-path: polygon(0 0, 100% var(--slant), 100% calc(var(--slant) + 5px), 0 5px);
}
/* the mirror: cuts run the other way (high on the right), grey above, white below */
.divider--mirror { --above: var(--grey-100); --below: var(--white); }
/* the barn: a short parallax box (data-grow) and a crop biased to it, low in the frame */
.divider--phil .divider__photo { object-position: 32% 88%; }      /* the barn and the flag sit low and left in the photo */
/* the band under the reviews rides UP over that section's foot by the height
   of its slant, with nothing painted in its top corner: the tile and the
   carousel's red rails run on down to the red cut itself, instead of stopping
   short at a white wedge like the bottom of a box. */
.divider--phil { z-index: 2; margin-top: calc(-1 * var(--slant)); background: linear-gradient(to bottom, transparent 50%, var(--below) 50%); }
.divider--mirror .divider__media { clip-path: polygon(0 var(--slant), 100% 0, 100% calc(100% - var(--slant)), 0 100%); }
.divider--mirror .divider__media::after { background: linear-gradient(90deg, rgba(35,31,32,.45) 0%, rgba(35,31,32,.25) 40%, rgba(35,31,32,.55) 100%); }
.divider--mirror::before { clip-path: polygon(0 var(--slant), 100% 0, 100% 5px, 0 calc(var(--slant) + 5px)); }
@media (min-width: 1024px) { .divider { --slant: 6vw; } }
.section--reviews   { background: var(--white); position: relative; isolation: isolate; }
/* A WHISPER OF TILE behind the words: white subway tile laid on the
   diagonal, drawn as an SVG pattern (thin grey grout lines, nothing else, so
   it is crisp at any size and never shows a seam), at low strength. It fades
   out before it reaches the photo column (on phones, where the words sit
   above the photos, it fades out downwards instead). */
.section--reviews::before {
    content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    background: url("assets/tile-accent.svg");
    opacity: .42;
    -webkit-mask-image: linear-gradient(to bottom, #000 25%, transparent 58%);
            mask-image: linear-gradient(to bottom, #000 25%, transparent 58%);
}
@media (min-width: 1024px) {
    .section--reviews::before {
        right: 46%;
        -webkit-mask-image: linear-gradient(to right, #000 62%, transparent 100%);
                mask-image: linear-gradient(to right, #000 62%, transparent 100%);
    }
}
.section--phil      { background: var(--grey-100); overflow: clip; }   /* clip: the photo's red bar hangs 4px outside it */
.section--areas     { background: var(--white); }
.section--quals     { background: var(--white); min-height: 100svh; display: grid; align-content: center; position: relative; isolation: isolate; }   /* a full screen: the badges converge as it centres */
/* THE COVER. Qualifications is pinned while the FAQ scrolls up over it, and a
   grey veil comes over it as it is covered (script.js, coverQuals sets --dim). */
.section--quals::after { content: ""; position: absolute; inset: 0; z-index: 5; pointer-events: none; background: var(--ink); opacity: var(--dim, 0); }
/* .section--contact: styled in the CONTACT block below */
/* ---------- FOOTER ----------
   The Homicidal Fitness footer in Integrity's palette: white ground,
   type in the ink of the wordmark's RESTORATIONS & REMODELING line, red
   for labels, hairlines, the Pegasus mark and the rolled-in copy of
   every link. Rows dim by colour, not opacity, so a rolled link can
   still reach full red. */
.site-footer {
    --hairline: var(--red);
    background: var(--white); color: var(--ink);
    border-top: 1px solid var(--hairline);
    padding: 64px var(--gutter) 32px;
    font-family: var(--font-ui); text-transform: uppercase;
}
.footer__grid { display: grid; gap: 40px; align-items: start; }
.footer__logo { display: block; width: 165px; height: auto; }
.footer__tag {
    margin-top: 20px; font-weight: 500; font-size: 12px; letter-spacing: 2.5px; line-height: 1.8;
    color: var(--grey-700); max-width: 44ch;
}
.footer__label { display: block; font-weight: 600; font-size: 11px; letter-spacing: 3px; color: var(--red); margin-bottom: 18px; }
.footer__col p { font-weight: 400; font-size: 14px; letter-spacing: .06em; line-height: 1.9; color: var(--ink); }
.footer__mail { color: inherit; text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--red); text-transform: none; letter-spacing: .02em; }
.footer__link {
    display: inline-block; margin-top: 20px;
    font-weight: 600; font-size: 13px; letter-spacing: 2px; color: var(--ink); text-decoration: none;
}
.footer__bottom {
    margin-top: 56px; padding-top: 22px; border-top: 1px solid var(--hairline);
    display: flex; flex-direction: column; gap: 16px; align-items: center; text-align: center;
    font-weight: 500; font-size: 11px; letter-spacing: 2px; color: var(--grey-700);
}
.footer__social { display: flex; gap: 34px; }
.footer__social a { display: inline-block; color: var(--ink); text-decoration: none; font-weight: 600; }
.footer__credit {
    margin-top: 22px; padding-top: 20px; border-top: 1px solid var(--hairline);
    display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 14px;
    font-weight: 500; font-size: 11px; letter-spacing: 2px; color: var(--grey-700); text-align: center;
}
.footer__mark { width: 26px; height: 26px; flex-shrink: 0; color: var(--red); }
.footer__credit a {
    display: inline-block; color: var(--ink); font-weight: 600; text-decoration: none;
    white-space: nowrap;                    /* the URL breaks whole, never mid-word across the char spans */
}
.footer__cookies { font: inherit; letter-spacing: inherit; text-transform: inherit; color: var(--ink); font-weight: 600; transition: color .2s; }
.footer__cookies:hover, .footer__cookies:focus-visible { color: var(--red); }
/* PHONES AND TABLETS: the footer is one centred column. The shield, the line
   under it, each block's label, words and link all sit on the centre line. */
@media (max-width: 1023px) {
    .footer__grid { justify-items: center; text-align: center; }
    .footer__logo { margin-inline: auto; }
    .footer__tag { margin-inline: auto; }
    .footer__social { flex-wrap: wrap; justify-content: center; gap: 12px 28px; }
}
/* the roll reveals red */
.site-footer a[data-roll] .trackContent[aria-hidden] { color: var(--red); }
/* a rolled link is an overflow-hidden inline-block, so its baseline is
   its bottom edge and it floats above the text beside it; aligning the
   box to the line's top puts the glyphs back on the line's baseline */
.site-footer a[data-roll] { vertical-align: top; }

/* ---------- COOKIE NOTICE ----------
   A card along the foot of the screen, over everything but the veil. It
   rises in, and slides away once a choice is made. */
.cookies {
    position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 58;
    display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 10px 10px 16px;
    background: var(--white); color: var(--ink); border-top: 3px solid var(--red);
    box-shadow: 0 14px 40px rgba(35, 31, 32, .32), 0 2px 8px rgba(35, 31, 32, .12);
    transform: translateY(calc(100% + 24px)); transition: transform .6s cubic-bezier(.65, 0, .35, 1);
}
.cookies[hidden] { display: none; }
.cookies.is-in { transform: none; transition: transform .6s var(--ease-out); }
.cookies__body { display: flex; align-items: center; gap: 10px; }
/* the cookie: the SVG is the stencil, the brand gradient the paint (as the service icons) */
.cookies__icon { flex: none; width: 26px; aspect-ratio: 1; background: var(--grad-brand); -webkit-mask: url("assets/icon-cookie.svg") center / contain no-repeat; mask: url("assets/icon-cookie.svg") center / contain no-repeat; }
.cookies__text { font-family: var(--font-ui); font-weight: 500; font-size: 13px; letter-spacing: .08em; text-transform: uppercase; }
.cookies__actions { display: flex; gap: 8px; flex: none; }
.cookies .cookies__btn { min-height: 40px; font-size: 12.5px; padding: 10px 16px; box-shadow: none; }      /* two classes: holds its size against the big desktop .btn rules */
.cookies .cookies__btn--decline { color: var(--ink); box-shadow: inset 0 0 0 2px var(--grey-300); background: var(--white); }
.cookies .cookies__btn--decline:hover, .cookies .cookies__btn--decline:focus-visible { box-shadow: inset 0 0 0 2px var(--ink); }
@media (min-width: 768px) { .cookies { left: 24px; right: auto; bottom: 24px; gap: 28px; padding: 12px 12px 12px 20px; } }
@media (max-width: 479px) {      /* phones: everything on one line */
    .cookies { gap: 8px; padding: 8px 8px 8px 12px; }
    .cookies__body { gap: 8px; }
    .cookies__icon { width: 22px; }
    .cookies__text { font-size: 11.5px; letter-spacing: .04em; white-space: nowrap; }
    .cookies__actions { gap: 6px; }
    .cookies .cookies__btn { padding: 10px 11px; font-size: 12px; letter-spacing: .06em; }
}
@media (max-width: 359px) { .cookies { left: 8px; right: 8px; padding-left: 10px; } .cookies__icon { width: 20px; } .cookies__text { font-size: 10.5px; letter-spacing: .02em; } .cookies .cookies__btn { padding: 10px 8px; font-size: 11.5px; } }
@media (prefers-reduced-motion: reduce) { .cookies, .cookies.is-in { transition: none; } }

/* ---------- VEIL: the dip between sections on a menu click (script.js) ---------- */
.veil {
    position: fixed; inset: 0; z-index: 60;     /* over the header (50) */
    background: var(--ink);
    opacity: 0; visibility: hidden; pointer-events: none;
}

/* ---------- ROLLING TEXT (letter windows built by script.js) ---------- */
[data-roll] { overflow: hidden; }
[data-roll] .word { display: inline-flex; }       /* keeps the space between words */
.letterWindow { display: inline-block; height: 1lh; overflow: hidden; }
.letterTrack { display: flex; flex-direction: column; align-items: center; will-change: transform; }      /* always on its own layer: the text does not switch rendering modes as the roll starts and ends */
.trackContent { height: 1lh; display: flex; align-items: center; justify-content: center; }

/* ---------- TABLET AND UP: hero layout ----------
   Two breakpoints on purpose. The hero's desktop composition (corner
   buttons, side-lit overlay, icon trust bar) works from 768px. The
   3 + shield + 3 nav needs ~900px of width, so it waits for 1024px;
   tablets keep the hamburger. */
@media (min-width: 768px) {
    :root { --nav-h: 80px; --gutter: 40px; }
    .nav__shield { width: 48px; }
    .nav__wordmark { width: 132px; }
    .site-header::before { height: 150px; }
    .hero__photo { object-position: center 60%; }

    .hero__media::after {
        background: linear-gradient(
            78deg,
            rgba(35,31,32, var(--overlay)) 0%,
            rgba(35,31,32, calc(var(--overlay) * .72)) 42%,
            rgba(35,31,32, calc(var(--overlay) * .14)) 72%,
            rgba(35,31,32, 0) 100%
        );
    }
    .hero__content {
        align-self: stretch;
        padding: calc(var(--nav-h) + 96px) var(--gutter) 40px;
        gap: 26px;
    }
    .hero__title { font-size: clamp(60px, 6.2vw, 96px); line-height: .94; max-width: 760px; }
    .hero__note { font-size: clamp(20px, 1.8vw, 26px); padding: 16px 0 16px 20px; max-width: 760px; }
    .hero__copy { margin-top: auto; }         /* with the buttons' auto margin below: the words sit centred between the nav and the buttons, with room to ride down on scroll */
    .hero__actions {
        margin-top: auto;                     /* pushes the buttons to the bottom edge */
        justify-content: space-between;
    }
    .hero__actions .btn { flex: none; }
    .btn { font-size: 16px; padding: 18px 40px; }
    .btn--primary { font-size: 18px; padding: 19px 42px; }

    .trust { padding: calc(var(--vee) + 18px) var(--gutter) 16px; gap: 8px 14px; }
    /* THREE PLACES on one line: the first flush left and the third flush right
       (the same gutters as the two buttons above), the middle one centred
       exactly on the page's centre line, which is the shield's axis and the
       point of the V. Equal 1fr side columns are what pin the middle to the
       centre whatever the side items' widths. No dots: the space separates them. */
    .trust { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; column-gap: 16px; }
    .trust__item:nth-child(1) { justify-self: start; }
    .trust__item:nth-child(2) { justify-self: center; }
    .trust__item:nth-child(3) { justify-self: end; }
}

/* services: one wider column on tablets (two columns at 768 leave only
   ~190px for text), two columns with bigger icons from 1024 */
@media (min-width: 768px) {
    .section { padding: 96px var(--gutter); }
    .section__head { margin-bottom: 56px; }
    .section__lede { font-size: 18px; }
    .services { gap: 44px; max-width: 640px; margin-inline: auto; }
    .service { grid-template-columns: 80px 1fr; gap: 28px; }
    .service__icon { width: 80px; }
    .service__title { font-size: 18px; }
    .service__text { font-size: 17px; max-width: none; }
}
@media (min-width: 1024px) {
    .services { grid-template-columns: 1fr 1fr; gap: 56px 64px; max-width: none; }
    .service { grid-template-columns: 96px 1fr; }
    .service__icon { width: 96px; }
}

/* our work: two-up gallery and side-by-side commercial from tablet */
@media (min-width: 768px) {
    .segments { margin-bottom: 40px; gap: 20px; }
    .segment { aspect-ratio: 2 / 1; border-radius: 20px; padding: 24px; gap: 8px; }
    .segment__title { font-size: 40px; }
    .segment__sub { font-size: 15px; }
    .work__intro { font-size: 17px; }
    .gallery { grid-template-columns: 1fr 1fr; gap: 32px; }
    .commercial { grid-template-columns: 1.2fr 1fr; gap: 48px; align-items: start; }
    .commercial__copy p { font-size: 17px; }
    .review { min-height: 380px; }
    .reviews { max-width: 640px; margin-inline: auto; }
    /* carousel: head on the left, column window on the right */
    .is-carousel .reviews-layout {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); grid-template-rows: 1fr;
        align-items: center; gap: 48px;
    }
    /* the head must fit beside the window with the longest review showing,
       so the title and lede come down a size in carousel mode */
    .is-carousel .reviews-head { text-align: left; margin: 0; max-width: 46ch; align-self: start; padding-top: 2vh; }
    .is-carousel .section__title { font-size: clamp(40px, 4.4vw, 60px); }
    .is-carousel .section__lede { display: block; font-size: 15px; margin-top: 10px; }
    .is-carousel .reviews-progress { margin-top: 16px; }
    .is-carousel .reviews-window { height: 100%; }
    .is-carousel .review { min-height: 360px; }
    .is-carousel .reviews { max-width: none; }
    .reviews-current { margin-top: 22px; }
    .reviews-current .review__quote p { font-size: 17px; line-height: 1.55; }

    /* meet Phil: photo beside the copy, alternating sides beat by beat */
    .story { gap: 72px; }
    .beat { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 48px; align-items: center; }
    .beat:nth-child(even) .beat__media { order: 2; }
    .beat:nth-child(odd)  .beat__photo { border-radius: 0 88px 0 88px; }
    .beat:nth-child(even) .beat__photo { border-radius: 88px 0 88px 0; }
    .morph__frame { border-radius: 0 88px 0 88px; }
    /* CLOSING THE GAP between the two beats. Once the top frame has flattened
       to the family photo, its stage has about 220px of spare room at the
       bottom. The first beat's text lines up with the top of the photo, and
       the work beat tucks up into that spare room. HOW FAR is measured by
       script.js (philStory), because it depends on the window: on a short
       screen both photo blocks scale down and there is far less room. Only
       when the stage is live (:has); the static page has nothing to tuck into. */
    .beat:has(.morph.is-live) { align-items: start; }
    .beat:has(.morph.is-live) .beat__body { padding-top: 30px; }
    .beat__body p:not(.beat__step) { font-size: 17px; }

    /* split shield: wider caps, roomier panel */
    .shield-card { --cap: 90px; }
    .shield-card__panel { padding: 44px 36px 40px; }
    .contact-card__copy { font-size: 17px; }
    .form__row { grid-template-columns: 1fr 1fr; }
    .form__foot { flex-direction: row; align-items: center; gap: 18px; }

    /* qualifications: still two across here (four is cramped at tablet width) */
    .badges { gap: 36px 32px; }
    .badge { padding: 12px 10px; gap: 14px; }
    .badge__mark { width: 128px; }
    .badge__logo { height: 128px; }
    .badge__title { font-size: 15px; }
    .badge__text { font-size: 14px; }

    /* areas served: two-column county list; the checker panel docks top-left */
    .counties { grid-template-columns: 1fr 1fr; }
    .areas__copy { font-size: 17px; text-align: center; }
    /* desktop: docked top-left over the map, never taller than the room under the nav */
    .section--check { min-height: 720px; }
    .check__panel {
        left: var(--gutter); right: auto; top: calc(var(--nav-h) + 20px); bottom: auto;
        width: min(440px, 40vw); max-height: calc(100% - var(--nav-h) - 40px);
        padding: 20px 22px 16px;
    }
    .check__grid { grid-template-columns: minmax(0, 1fr) 72px 104px; }
}
@media (min-width: 1024px) {
    .badges { grid-template-columns: repeat(3, 1fr); max-width: 1040px; margin-inline: auto; }   /* qualifications: three across, centred */

    /* footer: three columns, legal row and credit row inline */
    .site-footer { padding: 90px var(--gutter) 40px; }
    .footer__grid { grid-template-columns: 1.4fr 1fr 1fr; gap: 5vw; }
    .footer__logo { width: 210px; }
    .footer__bottom { margin-top: 70px; flex-direction: row; justify-content: space-between; text-align: left; }
    .footer__credit { flex-direction: row; gap: 12px; }

    /* split shield: form left, next steps right, a hairline between.
       Everything is tightened so the whole card sits inside one
       900px-tall screen under the nav: wider than it is tall. */
    .section.section--contact { padding-top: calc(64px + 20px); padding-bottom: 28px; }
    .shield-card { --cap: 150px; }
    .shield-card__panel { padding: 24px 40px 22px; }
    .shield-card__content { grid-template-columns: minmax(0, 1.25fr) minmax(0, .75fr); gap: 40px; align-items: start; }
    .contact-card__title { font-size: clamp(32px, 2.6vw, 40px); }
    .contact-card__copy { font-size: 15px; margin: 8px 0 14px; max-width: none; }
    /* name, phone and email stack (three narrow boxes read squished), so
       every field is a little shorter to keep the card on one screen */
    .shield-card .form__field, .shield-card .form__group { margin-bottom: 10px; }
    .shield-card .form__label { margin-bottom: 4px; font-size: 11px; }
    .shield-card .form__input { min-height: 44px; padding: 8px 12px; }
    .shield-card .form__textarea { min-height: 76px; }
    .shield-card .chip span { min-height: 40px; padding: 8px 14px; }
    .shield-card .form__help { margin-top: 5px; }
    .contact-card__side { border-top: 0; border-left: 1px solid var(--grey-300); padding: 2px 0 0 32px; }
    .contact-card__portrait { width: 180px; height: 180px; margin: 0 auto 14px; }
    .contact-card__sub { font-size: 24px; margin-bottom: 10px; }
    .steps { gap: 10px; margin-bottom: 18px; }
    .step p { font-size: 14px; }
    .contact__details { gap: 8px; margin-bottom: 16px; }
    .contact__detail { font-size: 14px; }
    .social { width: 42px; height: 42px; }
}
@media (min-width: 1024px) {
    .is-carousel .reviews-layout { gap: 80px; }
    .is-carousel .review { min-height: 440px; }
}

/* landscape phones and short laptops: the hero can't afford 176px of
   top padding above the headline, so it tightens up */
@media (min-width: 768px) and (max-height: 640px) {
    .hero__content { padding-top: calc(var(--nav-h) + 24px); gap: 16px; }
    .hero__title { font-size: clamp(44px, 7vh, 72px); }
}
/* ...but from 1024px the logo is centred and hangs about 150px down (shield
   plus wordmark), and a wide headline ran underneath it. Start below it. */
@media (min-width: 1024px) and (max-height: 640px) {
    .hero__content { padding-top: 168px; gap: 14px; }
}

/* ---------- DESKTOP: full nav ---------- */
@media (min-width: 1024px) {
    :root { --nav-h: 96px; --gutter: 48px; }

    /* THE FULL NAV lives over the hero only. Once the page scrolls past
       the hero (.is-scrolled) these rules stop applying and the header
       falls back to the phone layout: a slim bar, shield + wordmark on
       the left, a hamburger on the right, the links in the sheet. A
       96px bar of six links was covering photos further down. */
    .site-header:not(.is-scrolled) .nav {
        display: grid;
        grid-template-columns: 1fr auto 1fr;
        grid-template-rows: var(--nav-h);   /* fixed row: the brand overflows it, links centre in it */
        align-items: center;
    }
    .site-header:not(.is-scrolled) .nav__toggle { display: none; }
    .site-header:not(.is-scrolled) .nav__menu {
        position: static; inset: auto; transform: none; visibility: visible;
        background: none; padding: 0;
        display: contents;                     /* its children join the nav grid */
    }
    .site-header:not(.is-scrolled) .nav__list { flex-direction: row; gap: clamp(20px, 2.5vw, 36px); }
    .site-header:not(.is-scrolled) .nav__list--left  { grid-column: 1; justify-content: end; padding-right: clamp(20px, 2.5vw, 36px); }
    .site-header:not(.is-scrolled) .nav__list--right { grid-column: 3; justify-content: start; padding-left: clamp(20px, 2.5vw, 36px); }
    .site-header:not(.is-scrolled) .nav__cta { display: none; }   /* the hero carries the CTA on desktop */

    /* the shield sits in the centre column, vertically centred on the
       link row (lowered vs the comp), wordmark hanging beneath it */
    .site-header:not(.is-scrolled) .nav__brand {
        grid-column: 2; grid-row: 1;
        flex-direction: column; gap: 6px;
        align-self: start;
        padding-top: calc((var(--nav-h) - 84px) / 2);
    }
    .site-header:not(.is-scrolled) .nav__shield { width: 80px; }
    .site-header:not(.is-scrolled) .nav__wordmark { width: 170px; }
    .site-header:not(.is-scrolled) .nav__link { font-size: clamp(14px, 1.15vw, 16px); padding: 8px 0; }
    /* the compact bar: same height and menu top as on phones. The logo
       sizes are pinned here so the scroll-driven shrink (script.js sets
       inline widths) cannot regrow the logo inside the bar before the
       glide back to the centre starts. */
    .site-header.is-scrolled { height: 64px; }
    .site-header.is-scrolled .nav__shield { width: 48px !important; }
    .site-header.is-scrolled .nav__wordmark { width: 132px !important; }
    /* on a wide screen the sheet is a drawer off the right edge, not a
       full-screen curtain */
    .site-header.is-scrolled .nav__menu {
        top: 64px; left: auto; width: min(400px, 100%);
        padding: 40px 48px;
        box-shadow: -18px 0 40px rgba(35, 31, 32, .35);
    }
    .section { scroll-margin-top: 64px; }  /* anchors land under the compact bar */

}

/* ---------- MOTION ---------- */
/* script.js checks the same query and skips its timelines; this covers
   the CSS side so nothing moves for people who asked it not to */
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* =====================================================================
   PHONE AND TABLET REWORKS (kept last so they win over the blocks above)
   ===================================================================== */

/* ---------- REVIEWS on phones: the text above the photo, as on desktop ----------
   The active review (stars, quote, name, no glass) sits under the title
   in .reviews-current, which script.js sizes to the longest review so
   the window below never jumps. A vertical 01..08 bar runs beside the
   window; the horizontal bar and the hint are desktop-only. */
@media (max-width: 767px) {
    .section--reviews.is-carousel { padding-top: calc(var(--nav-h) + 12px); padding-bottom: 0; }
    .is-carousel .reviews-layout { grid-template-columns: 26px minmax(0, 1fr); grid-template-rows: auto 1fr; gap: 12px 10px; }
    .is-carousel .reviews-head { grid-column: 1 / -1; }
    .is-carousel .reviews-head .section__eyebrow { margin-bottom: 4px; }
    .is-carousel .section__title { font-size: clamp(30px, 8.6vw, 36px); }
    .is-carousel .reviews-progress, .is-carousel .reviews-hint { display: none; }
    .reviews-current { margin-top: 10px; text-align: left; }
    .reviews-current .review__glass { padding: 12px 14px 8px; gap: 2px 12px; }
    .reviews-current .review__name { font-size: 15px; }
    .reviews-current .review__source { width: 28px; height: 28px; }
    .reviews-current .review__quote { margin-top: 6px; padding-bottom: 4px; }
    .reviews-current .review__quote p { font-size: 15px; line-height: 1.5; }
    .is-carousel .reviews-vprogress {
        display: flex; flex-direction: column; align-items: center; gap: 8px; min-height: 0;
        font-family: var(--font-ui); font-weight: 500; font-size: 12px; letter-spacing: .1em;
    }
    .reviews-vprogress__track { position: relative; flex: 1; width: 2px; background: var(--grey-300); }
    .reviews-vprogress__fill { position: absolute; inset: 0; background: linear-gradient(to bottom, var(--red), var(--red-dark)); transform-origin: top; transform: scaleY(0); }
    .reviews-vprogress__total { color: var(--grey-700); }
    .is-carousel .review { min-height: 260px; }
    .is-carousel .reviews { padding-inline: 10px; }
    .reviews__rule { margin-inline: -10px; }
    /* no mask on phones: masking a moving column is repainted every frame and
       was part of the lag. The ground is plain white here, so a white fade
       laid over the window's top edge looks the same and costs nothing. */
    .is-carousel .reviews-window { -webkit-mask-image: none; mask-image: none; }
    .section--reviews.is-carousel::after {      /* script.js gives --win-top (where the window starts) and --fade */
        content: ""; position: absolute; left: calc(var(--gutter) + 36px); right: 0; top: var(--win-top, 0); height: var(--fade, 20px); z-index: 3; pointer-events: none;
        background: linear-gradient(to bottom, var(--white), rgba(255, 255, 255, 0));
    }
}
/* short phones: the quote is clamped so the photo keeps a usable window */
@media (max-width: 767px) and (max-height: 700px) {
    .is-carousel .reviews-head .section__eyebrow { display: none; }
    .is-carousel .section__title { font-size: 28px; }
    .reviews-current { margin-top: 6px; }
    .reviews-current .review__quote p { font-size: 14px; line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
    .reviews-current .review__name { font-size: 14px; }
}

/* a phone on its side (wide but very short): the side-by-side reviews layout
   applies, so the left column has to slim down to fit the height */
@media (min-width: 768px) and (max-height: 520px) {
    .section--reviews.is-carousel { padding-top: calc(var(--nav-h) + 8px); }
    .is-carousel .reviews-head { padding-top: 0; }
    .is-carousel .reviews-head .section__eyebrow, .is-carousel .section__lede, .is-carousel .reviews-hint { display: none; }
    .is-carousel .section__title { font-size: 28px; }
    .is-carousel .reviews-progress { margin-top: 8px; }
    .reviews-current { margin-top: 10px; }
    .reviews-current .review__glass { padding: 12px 14px 6px; gap: 2px 12px; }
    .reviews-current .review__name { font-size: 14px; }
    .reviews-current .review__source { width: 26px; height: 26px; }
    .reviews-current .review__quote { margin-top: 6px; padding-bottom: 2px; }
    .reviews-current .review__quote p { font-size: 13.5px; line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
    .reviews-current .review__job { min-height: 36px; padding: 4px 0; }
    .is-carousel .review { min-height: 230px; }
}

/* ---------- MAP on phones: the checker is a bottom sheet ----------
   .is-sheet is set by script.js on phones; .is-open slides the form up
   from under the map's foot to where it always sat. */
.check__open, .check__close { display: none; }
.check.is-sheet { overflow: hidden; }
.check.is-sheet .check__open {
    display: flex; position: absolute; left: 14px; right: 14px; bottom: 40px; z-index: 500;   /* clear of the map credit in the corner */
    white-space: normal; text-align: center; line-height: 1.25; padding: 14px 16px;
    transition: opacity .25s, transform .25s var(--ease-out), box-shadow .25s var(--ease-out);
}
.check.is-sheet.is-open .check__open { opacity: 0; pointer-events: none; }
.check.is-sheet:not(.is-open) .check__open { transition-delay: .35s; }      /* the button waits for the sheet to be most of the way down */
.check.is-sheet .check__panel {
    transform: translateY(calc(100% + 40px)); visibility: hidden;
    transition: transform .65s cubic-bezier(.65, 0, .35, 1), visibility 0s .65s;      /* the CLOSE: eased and unhurried; the open (below) stays quick */
}
.check.is-sheet.is-open .check__panel { transform: none; visibility: visible; transition: transform .45s var(--ease-out); }
.check.is-sheet .check__close {
    display: grid; place-items: center; position: absolute; top: 4px; right: 4px;
    width: 44px; height: 44px; font-size: 28px; line-height: 1; color: var(--ink); transition: color .2s;
}
.check.is-sheet .check__close:hover, .check.is-sheet .check__close:active, .check.is-sheet .check__close:focus-visible { color: var(--red); }
@media (prefers-reduced-motion: reduce) {
    .check.is-sheet .check__panel, .check.is-sheet.is-open .check__panel { transition: none; }
}

/* ---------- CONTACT below 1024px: no split shield ----------
   The section is white and the form sits straight on it, full width.
   While script.js plays the intro (.is-intro) the section is the logo's
   grey with the shield and wordmark centred in the first screen. */
.contact-intro { display: none; }
@media (max-width: 1023px) {
    .section.section--contact {
        position: relative; background: var(--white);
        align-content: start; padding: calc(var(--nav-h) + 18px) var(--gutter) 44px;
    }
    .section.section--contact.is-intro { background: var(--grey-900); }
    .section--contact.is-intro .contact-card__side { border-top-color: transparent; }   /* its hairline would show on the grey before its content fades in */
    .section--contact.is-intro .contact-intro {
        display: grid; place-content: center; justify-items: center; text-align: center;
        position: absolute; top: 0; left: 0; right: 0; height: 100svh; pointer-events: none;
    }
    .contact-intro__shield { width: min(46vw, 200px); height: auto; margin-bottom: 18px; filter: drop-shadow(0 18px 26px rgba(35, 31, 32, .4)); }
    .shield-card__wrap { filter: none; }
    .shield-card { display: block; }
    .shield-card__cap, .shield-card__lockup { display: none; }
    .shield-card__panel { padding: 0; background: none; }
    .shield-card__content { max-width: 640px; margin-inline: auto; }
}
/* the phone form: every field a little shorter so name to Send fits one screen */
@media (max-width: 767px) {
    .contact-card__title { font-size: clamp(28px, 8vw, 34px); margin-top: 2px; }
    .contact-card__copy { font-size: 14px; line-height: 1.5; margin: 6px 0 12px; }
    .shield-card .form__field, .shield-card .form__group { margin-bottom: 10px; }
    .shield-card .form__label { margin-bottom: 4px; font-size: 11px; }
    .shield-card .form__input { min-height: 44px; padding: 8px 12px; }
    .shield-card .form__textarea { min-height: 70px; }
    .shield-card .chips { gap: 6px; }
    .shield-card .chip span { min-height: 40px; padding: 8px 10px; font-size: 12px; letter-spacing: .05em; }
    .shield-card .form__help { margin-top: 4px; font-size: 12px; }
    .shield-card .form__foot { gap: 6px; }
    .shield-card .form__foot .btn { width: 100%; }
}
/* short phones (older iPhone SE size): the intro copy goes and every field
   tightens once more, so name to Send still fits the screen */
@media (max-width: 767px) and (max-height: 700px) {
    .section.section--contact { padding-top: calc(var(--nav-h) + 10px); }
    .contact-card__title { font-size: 26px; }
    .contact-card__copy { display: none; }
    .shield-card .section__eyebrow { margin-bottom: 2px; }
    .shield-card .form { margin-top: 8px; }
    .shield-card .form__field, .shield-card .form__group { margin-bottom: 7px; }
    .shield-card .form__label { margin-bottom: 3px; }
    .shield-card .form__input { min-height: 42px; padding: 7px 12px; }
    .shield-card .form__textarea { min-height: 54px; }
    .shield-card .chip span { min-height: 38px; padding: 7px 9px; }
    .shield-card .form__help { display: none; }
    .shield-card .form__note { display: none; }
}
