/* NextGen Roofing — 2037 editorial-futurist theme.
   Core mechanic: sections are wrapped in tall "tracks"; the panel inside each
   track is position:sticky, so as you scroll, each new panel rises up and
   covers the one before it (see .stack-track / .stack-panel below). On small
   screens this degrades to plain stacked sections — sticky+fixed-height panels
   fight mobile browser chrome and touch-scroll physics badly enough that it's
   not worth forcing the effect there. */

:root {
  --ink: #0b0d10;
  --ink-2: #14171b;
  --panel: #1a1e23;
  --platinum: #ece9e2;
  --platinum-dim: rgba(236,233,226,0.62);
  --champagne: #cbb079;
  --champagne-2: #e8cf9f;
  --line: rgba(236,233,226,0.14);
  --line-strong: rgba(236,233,226,0.28);
  --radius: 4px;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  background: var(--ink);
  color: var(--platinum);
  line-height: 1.6;
}

h1, h2, h3 {
  font-family: 'Syne', -apple-system, sans-serif;
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.01em;
  margin: 0;
}
a { color: inherit; }
.muted { color: var(--platinum-dim); }
.container { max-width: 1180px; margin: 0 auto; padding: 0 1.75rem; width: 100%; }
.eyebrow {
  display: inline-flex; align-items: center; gap: 0.6rem;
  font-family: 'Inter', sans-serif; font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.22em; text-transform: uppercase; color: var(--champagne);
}
.eyebrow::before { content: ''; width: 1.5rem; height: 1px; background: var(--champagne); }

/* ---------- ambient sunburst ----------
   A fixed, grayscale, ever-present decorative layer — sits above every panel
   (regardless of scroll position), centered, screen-blended so it lightens
   whatever's beneath (photo or solid panel alike) without ever obscuring it.
   Two independently-spinning conic-gradient layers (opposite directions,
   different speeds/sizes/step counts so they interfere into something more
   complex than one uniform ray pattern) plus a slow-pulsing radial core. */
.ambient-burst {
  position: fixed; inset: 0; z-index: 250; pointer-events: none;
  overflow: hidden; mix-blend-mode: screen;
  display: flex; align-items: center; justify-content: center;
}
.sunburst {
  position: absolute; width: 200vmax; height: 200vmax;
  background: conic-gradient(
    from 0deg,
    rgba(180,180,180,0.03) 0deg, rgba(160,160,160,0.06) 9deg, rgba(140,140,140,0.10) 18deg,
    rgba(120,120,120,0.14) 27deg, rgba(100,100,100,0.18) 36deg, rgba(80,80,80,0.22) 45deg,
    rgba(60,60,60,0.28) 54deg, rgba(40,40,40,0.35) 63deg, rgba(30,30,30,0.45) 72deg,
    rgba(20,20,20,0.55) 81deg, rgba(180,180,180,0.03) 90deg, rgba(160,160,160,0.06) 99deg,
    rgba(140,140,140,0.10) 108deg, rgba(120,120,120,0.14) 117deg, rgba(100,100,100,0.18) 126deg,
    rgba(80,80,80,0.22) 135deg, rgba(60,60,60,0.28) 144deg, rgba(40,40,40,0.35) 153deg,
    rgba(30,30,30,0.45) 162deg, rgba(20,20,20,0.55) 171deg, rgba(180,180,180,0.03) 180deg,
    rgba(160,160,160,0.06) 189deg, rgba(140,140,140,0.10) 198deg, rgba(120,120,120,0.14) 207deg,
    rgba(100,100,100,0.18) 216deg, rgba(80,80,80,0.22) 225deg, rgba(60,60,60,0.28) 234deg,
    rgba(40,40,40,0.35) 243deg, rgba(30,30,30,0.45) 252deg, rgba(20,20,20,0.55) 261deg,
    rgba(180,180,180,0.03) 270deg, rgba(160,160,160,0.06) 279deg, rgba(140,140,140,0.10) 288deg,
    rgba(120,120,120,0.14) 297deg, rgba(100,100,100,0.18) 306deg, rgba(80,80,80,0.22) 315deg,
    rgba(60,60,60,0.28) 324deg, rgba(40,40,40,0.35) 333deg, rgba(30,30,30,0.45) 342deg,
    rgba(20,20,20,0.55) 351deg, rgba(180,180,180,0.03) 360deg
  );
  filter: blur(1px);
  animation: burstSpin 60s linear infinite;
}
.sunburst-reverse {
  position: absolute; width: 180vmax; height: 180vmax;
  background: conic-gradient(
    from 45deg,
    transparent 0deg, rgba(100,100,100,0.04) 5deg, transparent 10deg,
    rgba(120,120,120,0.07) 15deg, transparent 20deg,
    rgba(90,90,90,0.05) 25deg, transparent 30deg,
    rgba(80,80,80,0.06) 35deg, transparent 40deg,
    rgba(110,110,110,0.04) 45deg, transparent 50deg,
    rgba(70,70,70,0.08) 55deg, transparent 60deg,
    rgba(100,100,100,0.05) 65deg, transparent 70deg,
    rgba(85,85,85,0.06) 75deg, transparent 80deg,
    rgba(95,95,95,0.04) 85deg, transparent 90deg
  );
  background-size: 90deg 90deg;
  filter: blur(2px);
  animation: burstSpinReverse 90s linear infinite;
}
.core {
  position: absolute; width: 60vmax; height: 60vmax; border-radius: 50%;
  background: radial-gradient(
    circle at center,
    rgba(90,90,90,0.35) 0%, rgba(60,60,60,0.15) 25%, rgba(30,30,30,0.05) 45%, transparent 70%
  );
  animation: burstPulse 8s ease-in-out infinite;
}
@keyframes burstSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes burstSpinReverse { from { transform: rotate(360deg); } to { transform: rotate(0deg); } }
@keyframes burstPulse {
  0%, 100% { transform: scale(1); opacity: 0.8; }
  50% { transform: scale(1.08); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .sunburst, .sunburst-reverse, .core { animation: none; }
}
/* blur() over an element this large is the expensive part — the browser has
   to rasterize and blur a canvas many times the size of the actual screen,
   every frame, for the whole time it's rotating. That's cheap to shrug off
   on a desktop GPU and not on a mid/low-range phone. Mobile drops both blur
   filters entirely, drops the second (reverse) layer so there's only one
   rotating gradient to paint instead of two, and shrinks everything closer
   to actual viewport size instead of the desktop's deliberately-oversized
   "fragment of something huge" look. */
@media (max-width: 760px) {
  .sunburst { width: 140vmax; height: 140vmax; filter: none; }
  .sunburst-reverse { display: none; }
  .core { width: 70vmax; height: 70vmax; }
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.6rem;
  padding: 0.95rem 2rem; border-radius: 999px; border: 1px solid var(--champagne);
  background: transparent; color: var(--champagne-2); text-decoration: none;
  font-weight: 700; font-size: 0.92rem; letter-spacing: 0.02em; cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, transform 0.15s ease;
}
.btn:hover { background: var(--champagne); color: var(--ink); transform: translateY(-1px); }
.btn-solid { background: var(--champagne); color: var(--ink); }
.btn-solid:hover { background: var(--champagne-2); }
.btn-block { width: 100%; }
.btn-lg { padding: 1.1rem 2.5rem; font-size: 1rem; }

/* ---------- header (fixed HUD bar, above everything) ---------- */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 500;
  padding: 1.5rem 0; transition: padding 0.3s ease, background 0.3s ease, border-color 0.3s ease;
  border-bottom: 1px solid transparent;
}
.site-header.is-scrolled {
  padding: 1rem 0; background: rgba(11,13,16,0.82); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-bottom-color: var(--line);
}
/* The shared editor toolbar (public/themes/_shared/css/editor.css) is a
   fixed 44px bar pinned to top:0 with z-index:200 — every editor-enabled
   theme has to push its own fixed header down below it in edit mode, or
   the theme's header (z-index:500 here, so it wins the overlap) sits on
   top of the toolbar and blocks its buttons, including "I'm Done". */
body.is-editable .site-header { top: 44px; }
.header-inner { display: flex; align-items: center; justify-content: space-between; }
.logo { display: flex; align-items: center; gap: 0.6rem; text-decoration: none; }
.logo-mark { width: 9px; height: 9px; border-radius: 50%; background: var(--champagne); box-shadow: 0 0 12px 2px rgba(203,176,121,0.6); }
.logo-text { font-family: 'Syne', sans-serif; font-weight: 700; font-size: 1.05rem; letter-spacing: 0.01em; color: var(--platinum); }
.main-nav { display: flex; align-items: center; gap: 2.25rem; }
.main-nav ul { list-style: none; display: flex; gap: 2rem; margin: 0; padding: 0; }
.main-nav ul a { font-size: 0.82rem; letter-spacing: 0.04em; text-decoration: none; color: var(--platinum-dim); transition: color 0.15s ease; }
.main-nav ul a:hover { color: var(--champagne-2); }
.nav-phone { color: var(--platinum) !important; font-weight: 700; }
.hamburger { display: none; flex-direction: column; gap: 5px; background: none; border: none; cursor: pointer; padding: 0; }
.hamburger span { width: 22px; height: 1.5px; background: var(--platinum); }
.nav-close, .nav-backdrop { display: none; }

/* ---------- stack mechanics ----------
   Every section — hero, work, standard, why, gallery, quote — uses the exact
   same mechanic: `position: fixed` (full viewport, all stacked on the same
   spot, ordered by z-index), and main.js drives each incoming panel's
   translateY directly from scroll position, continuously, from the first
   pixel of its own 100vh track. The previous panel is simply left alone —
   never touched — while the incoming one rises 100% -> 0% in exact lockstep
   with the scrollbar. There is no special case anywhere in this list — quote
   is a fixed 100vh panel just like the rest, sized to fit its content (the
   footer lives inside it, under the map — see .quote-footnote) rather than
   needing any special scroll behavior of its own.
   Track divs remain in normal flow purely as scroll-distance spacers; the
   visible panels are decoupled from them entirely. */
.stack-track { position: relative; }
/* The hero needs no dedicated scroll-distance of its own — main.js starts
   sliding "work" over it from scrollY 0, so the hero's window and the
   document's very first scrollable pixel are the same moment. Every other
   panel needs exactly one track's worth of scroll each — except quote:
   since it's a `position:fixed` panel like the rest, it never contributes
   any height to the document on its own (only its track does), so the
   document must already be tall enough for scrollY to reach the point
   where quote finishes sliding in. With every other track at 100vh, that
   point is one viewport past what the tracks add up to, so quote's track
   carries that missing viewport as trailing buffer — quote still finishes
   settling at the same scroll position, and the extra viewport is simply
   inert scroll room after it, since nothing needs to move once it's the
   last thing on the page. (Its content is sized to fit one screen — see
   below — so there's nothing left over to scroll into anyway.) */
.stack-track--hero { height: 0; }
.stack-track--work, .stack-track--standard, .stack-track--why,
.stack-track--gallery { height: 100vh; }
.stack-track--quote { height: 200vh; }
.stack-panel {
  position: fixed; inset: 0; height: 100vh;
  display: flex; align-items: center; overflow: hidden;
  background: var(--ink);
  will-change: transform;
}
.stack-panel--hero { z-index: 1; }
.stack-panel--work { z-index: 2; transform: translateY(100%); }
.stack-panel--standard { z-index: 3; transform: translateY(100%); }
.stack-panel--why { z-index: 4; transform: translateY(100%); }
.stack-panel--gallery { z-index: 5; transform: translateY(100%); }
.stack-panel--quote { z-index: 6; transform: translateY(100%); background: var(--panel); }

/* ---------- hero panel ---------- */
.hero-media { position: absolute; inset: 0; z-index: 0; }
.hero-media img { width: 100%; height: 100%; object-fit: cover; }
.hero-scrim { position: absolute; inset: 0; background: linear-gradient(0deg, rgba(11,13,16,0.96) 2%, rgba(11,13,16,0.55) 45%, rgba(11,13,16,0.75) 100%); }
.hero-content { position: relative; z-index: 1; padding-top: 6rem; padding-bottom: 5rem; width: 100%; }
.hero-content h1 { font-size: clamp(2.6rem, 7vw, 5.4rem); max-width: 900px; }
.hero-sub { font-size: 1.15rem; color: var(--platinum-dim); max-width: 560px; margin: 1.75rem 0 2.25rem; }
.hero-actions { display: flex; align-items: center; gap: 1.75rem; flex-wrap: wrap; }
.hero-phone { font-size: 0.95rem; font-weight: 700; text-decoration: none; color: var(--platinum); border-bottom: 1px solid var(--line-strong); padding-bottom: 2px; }
.scroll-cue {
  position: absolute; bottom: 2.5rem; left: 50%; transform: translateX(-50%); z-index: 1;
  display: flex; flex-direction: column; align-items: center; gap: 0.6rem;
  font-family: 'Inter', sans-serif; font-size: 0.68rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--platinum-dim);
}
.scroll-cue-line { width: 1px; height: 34px; background: linear-gradient(180deg, var(--champagne), transparent); animation: scrollCuePulse 2.2s ease-in-out infinite; }
@keyframes scrollCuePulse { 0%,100% { opacity: 0.35; } 50% { opacity: 1; } }

/* ---------- "rise" text: a 3D flip, not a slide ----------
   Each word starts lying flat, hinged at its own baseline, rotated 90° away
   from the viewer (rotateX(-90deg) — edge-on, effectively invisible) then
   rotates up to stand straight (0deg) as its section scrolls into view. */
[data-rise] .rise-line { display: block; }
.rise-word-wrap { display: inline-block; vertical-align: top; perspective: 500px; }
.rise-word {
  display: inline-block; transform-origin: 50% 100%;
  transform: rotateX(-90deg); opacity: 0;
  transition: transform 1.9s cubic-bezier(0.16,1,0.3,1), opacity 1s ease;
  will-change: transform, opacity;
}
[data-rise].is-risen .rise-word { transform: rotateX(0deg); opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .rise-word { transition: none; transform: none; opacity: 1; }
}

/* ---------- our work panel ---------- */
.work-inner { display: grid; grid-template-columns: 0.85fr 1.15fr; gap: 4rem; align-items: center; width: 100%; }
.work-copy h2 { font-size: clamp(2rem, 4.2vw, 3.2rem); }
.work-copy p { color: var(--platinum-dim); max-width: 420px; margin-top: 1.5rem; font-size: 1.02rem; }
.work-photos { position: relative; height: 420px; }
.work-photo { position: absolute; border-radius: var(--radius); overflow: hidden; box-shadow: 0 30px 70px -25px rgba(0,0,0,0.7); }
.work-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.work-photo-1 { width: 62%; height: 82%; top: 0; left: 0; z-index: 2; }
.work-photo-2 { width: 55%; height: 62%; bottom: 0; right: 0; z-index: 1; border: 6px solid var(--ink); }
.work-caption { position: absolute; bottom: 0.9rem; left: 0.9rem; font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase; color: #fff; background: rgba(11,13,16,0.55); padding: 0.35rem 0.7rem; border-radius: 999px; backdrop-filter: blur(4px); }

/* ---------- the standard (services) panel ---------- */
.standard-inner { width: 100%; padding-top: 4.5rem; padding-bottom: 3rem; }
.standard-head { max-width: 640px; margin-bottom: 2rem; }
.standard-head h2 { font-size: clamp(2rem, 4vw, 3rem); }
.standard-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0; border-top: 1px solid var(--line); }
.service-row {
  display: flex; align-items: baseline; gap: 1.1rem; padding: 0.9rem 1.25rem 0.9rem 0;
  border-bottom: 1px solid var(--line);
}
.service-row:nth-child(odd) { border-right: 1px solid var(--line); padding-right: 1.75rem; }
.service-row:nth-child(even) { padding-left: 1.75rem; }
.service-index { font-family: 'Syne', sans-serif; font-size: 1.1rem; color: var(--champagne); flex-shrink: 0; }
.service-body h3 { font-family: 'Inter', sans-serif; font-weight: 700; font-size: 1rem; margin-bottom: 0.3rem; }
.service-body p { margin: 0; font-size: 0.86rem; color: var(--platinum-dim); }
body.is-editable .service-row { position: relative; padding-right: 5.5rem !important; }
body.is-editable .service-row:nth-child(even) { padding-right: 5.5rem !important; }
body.is-editable .obt-service-toggle { position: absolute; top: 50%; right: 0; transform: translateY(-50%); }
/* The shared "Change Photo" badge (public/themes/_shared/css/editor.css)
   sits bottom-right on every [data-edit-slot] by default. Work photos and
   gallery items both have their own caption anchored along that same
   bottom edge (gallery's spans the full width, so the overlap is total,
   not just occasional) — a click aimed at the badge lands on the caption
   instead and opens the text editor rather than the photo picker. Moving
   the badge to the top-right for just these two slot types sidesteps it;
   nothing else in this theme occupies that corner. */
body.is-editable .work-photo[data-edit-slot]::after,
body.is-editable .gallery-item[data-edit-slot]::after {
  bottom: auto; top: 0.65rem;
}

/* ---------- why us panel ---------- */
.why-media { position: absolute; inset: 0; z-index: 0; }
.why-media img { width: 100%; height: 100%; object-fit: cover; }
.why-scrim { position: absolute; inset: 0; background: rgba(11,13,16,0.82); }
.why-inner { position: relative; z-index: 1; width: 100%; padding-top: 5rem; padding-bottom: 5rem; }
.why-head { max-width: 620px; margin-bottom: 3rem; }
.why-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem; }
.why-stat-num { display: block; font-family: 'Syne', sans-serif; font-size: clamp(2.4rem, 5vw, 3.6rem); color: var(--champagne-2); }
.why-stat-label { display: block; margin-top: 0.5rem; font-size: 0.88rem; color: var(--platinum-dim); max-width: 220px; }

/* ---------- gallery panel ---------- */
.gallery-inner { width: 100%; padding-top: 4.5rem; padding-bottom: 4.5rem; }
.gallery-head { max-width: 640px; margin-bottom: 2rem; }
.gallery-head h2 { font-size: clamp(2rem, 4vw, 3rem); }
.gallery-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
/* margin:0 resets the browser's default <figure> margin (a UA-stylesheet
   default of ~1em 40px, present in every browser) — without it, each item
   renders 40px inset from its own grid cell and 40px wider than the cell
   on top of that, corrupting the whole grid: images shift right and the
   last column runs off the edge of the screen. Only matters visibly once
   columns get narrow enough (mobile's 2-column layout), which is why this
   went unnoticed at desktop's roomier 4-column width. */
.gallery-item { position: relative; width: 100%; margin: 0; border-radius: var(--radius); overflow: hidden; aspect-ratio: 4/3; }
.gallery-item img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.5s ease; }
.gallery-item:hover img { transform: scale(1.05); }
.gallery-item figcaption { position: absolute; bottom: 0; left: 0; right: 0; padding: 0.9rem; font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase; color: #fff; background: linear-gradient(0deg, rgba(0,0,0,0.75), transparent); }

/* ---------- quote / contact panel ----------
   Kept deliberately tight (smaller gaps/margins than a normal-flow section
   would use) so the whole form and footnote comfortably fit one screen —
   this panel is `position:fixed` and exactly 100vh like every other one in
   the stack, with no special-case scrolling behavior of its own. */
.quote-grid { width: 100%; padding-top: 3rem; padding-bottom: 3rem; display: grid; grid-template-columns: 1fr 1fr; gap: 4rem; }
.quote-copy h2 { font-size: clamp(1.8rem, 3.6vw, 2.6rem); }
.quote-copy p { color: var(--platinum-dim); margin-top: 1rem; max-width: 420px; }
.quote-contact-list { margin-top: 1.25rem; display: flex; flex-direction: column; gap: 0.6rem; }
.quote-contact-list a, .quote-contact-list span { font-size: 0.9rem; text-decoration: none; color: var(--platinum); }
.map-frame { margin-top: 1.25rem; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--line); filter: grayscale(0.4) invert(0.92) contrast(0.9); }

.quote-form { display: flex; flex-direction: column; gap: 0.85rem; }
.form-row { display: flex; flex-direction: column; gap: 0.3rem; }
.form-row-split { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
label { font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--platinum-dim); }
input[type=text], input[type=tel], input[type=email], select, textarea {
  width: 100%; padding: 0.55rem 0; border: none; border-bottom: 1px solid var(--line-strong);
  background: transparent; color: var(--platinum); font-size: 0.95rem; font-family: inherit;
}
input:focus, select:focus, textarea:focus { outline: none; border-bottom-color: var(--champagne); }
select option { color: #000; }
.checkbox-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.45rem; margin-top: 0.4rem; }
.checkbox-item { font-size: 0.82rem; color: var(--platinum-dim); display: flex; align-items: center; gap: 0.5rem; }

/* ---------- footer (third item in the quote grid, after the form) ----------
   A quiet, single flowing line rather than a separate bordered block — it
   reads as a soft close to the page, not a distinct "footer section".
   grid-column spans both of quote-grid's columns so on desktop it sits as
   one full-width row below the two columns (which run roughly the same
   height by design, so this doesn't leave an awkward gap under either one).
   On mobile, quote-grid collapses to a single column, so this just falls
   naturally after the form in normal DOM order — after, not above it. */
.quote-footnote {
  grid-column: 1 / -1;
  display: block; margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--line);
  font-size: 0.75rem; line-height: 1.5; color: rgba(236,233,226,0.4);
}
.quote-footnote p { margin: 0.25rem 0 0; }
.quote-footnote p:first-child { margin-top: 0; }
.quote-footnote span { color: rgba(236,233,226,0.55); }
.quote-footnote span[data-obt-field="business-name"] { color: var(--platinum-dim); }
.quote-footnote span + span::before { content: ' \2014 '; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .scroll-cue-line { animation: none; }
}

/* ---------- responsive ---------- */
@media (max-width: 900px) {
  .main-nav ul, .nav-phone { display: none; }
  .hamburger { display: flex; }
  .main-nav {
    position: fixed; top: 0; right: -100%; height: 100vh; width: 78%; max-width: 320px;
    background: var(--ink-2); flex-direction: column; align-items: flex-start; padding: 5.5rem 2rem 2rem;
    transition: right 0.3s ease; z-index: 600; border-left: 1px solid var(--line);
  }
  .main-nav.open { right: 0; }
  .main-nav.open ul { display: flex; flex-direction: column; gap: 1.5rem; }
  .nav-close {
    display: flex; align-items: center; justify-content: center; position: absolute; top: 1.25rem; right: 1.25rem;
    width: 2.25rem; height: 2.25rem; border-radius: 50%; background: none; border: 1px solid var(--line-strong);
    color: var(--platinum); font-size: 1.4rem; line-height: 1; cursor: pointer;
  }
  .nav-backdrop { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.6); z-index: 590; }
  .nav-backdrop.open { display: block; }

  .work-inner, .quote-grid { grid-template-columns: 1fr; gap: 2.5rem; }
  .work-photos { height: 320px; margin-top: 1rem; }
  .standard-grid { grid-template-columns: 1fr; }
  /* Two columns of checkboxes at phone width means every label wraps onto a
     second line, which makes the whole block feel cramped and hard to scan
     — a plain single-column list reads much cleaner here. */
  .checkbox-grid { grid-template-columns: 1fr; }
  .service-row:nth-child(odd) { border-right: none; padding-right: 0; }
  .service-row:nth-child(even) { padding-left: 0; }
  .why-stats { grid-template-columns: 1fr; gap: 2rem; }
  .gallery-grid { grid-template-columns: repeat(2, 1fr); }
}

/* Sticky-stacking + fixed-height panels fight mobile browser chrome and touch
   momentum scrolling too much to be worth it below ~760px — fall back to a
   plain, reliably-scrolling stack of sections instead of forcing the effect.
   No blanket padding here: every section already has its own inner wrapper
   (.hero-content, .standard-inner, .why-inner, .gallery-inner, .quote-grid)
   with padding sized for its own content — adding padding on .stack-panel
   too just double-stacks on top of that. Only hero and quote get a mobile-
   specific top bump, to clear the fixed header sitting above everything. */
@media (max-width: 760px) {
  .stack-track, .stack-track--hero, .stack-track--work, .stack-track--standard, .stack-track--why,
  .stack-track--gallery, .stack-track--quote { height: auto; }
  /* min-height (not height) so each section fills the screen top to bottom
     at minimum, but can still grow taller if its content genuinely needs
     more room (quote's form, mainly) instead of clipping it. align-items
     switches from the desktop center to flex-start: centering short content
     (e.g. "why"'s heading + 3 stats) inside a full 100vh box leaves a huge,
     uneven gap above it that reads as broken padding — starting from the
     top with the section's own normal padding looks intentional instead. */
  .stack-panel {
    position: static; min-height: 100vh; height: auto; align-items: flex-start;
    transform: none !important; visibility: visible !important;
  }
  .hero-content { padding-top: 8rem; padding-bottom: 3rem; }
  .quote-grid { padding-top: 5.5rem; }
  .scroll-cue { display: none; }

  /* Desktop gets its "slide into view" from the paper-stack mechanic above,
     which is disabled here. main.js applies the mobile equivalent directly
     via inline opacity/transform (tied continuously to scroll position, the
     same technique the desktop stack itself uses) rather than a CSS class +
     transition — no initial hidden state is set here in CSS, on purpose: if
     that JS never ran for any reason, content should just show up plain
     rather than stay stuck invisible. */
}
