/* Building trades scroll hero (core/scroll-hero.js). Loaded only for a site that uses it (ssr.ts head link / site-runtime.js scrollHeroSheet).
   Structure: .cxh > .cxh__pin (sticky) > .cxh__stage (the film) + the look's own headline block (moved in by addScrollHero).
   Phones/tablets (< 900 px): the whole 4:3 frame at full width (stage height = width x 3/4, no crop, no blur); if the viewport height forces
   the stage shorter, the frame is contained on the page background. Desktop (>= 900 px): the same whole frame (stage height = width x 3/4 capped to the viewport, contained, page-background bands at the sides
   when the screen is wider than 4:3), so the roof, car and drive are never cut (core/scroll-hero.js containRect). No blurred
   panels anywhere. No JS / reduced motion: a plain block. */
:root { --cxh-top: 0px; }
.cxp-has-bar { --cxh-top: var(--cxp-bar-h, 0px); }
.cxh { position: relative; background: var(--brand-2, #131210); content-visibility: visible; contain: none; }
.cxh__pin { position: relative; }
.cxh__stage { position: relative; width: 100%; aspect-ratio: var(--cxh-w, 4) / var(--cxh-h, 3); max-height: calc(100vh - var(--cxh-top) - var(--cxh-copy, 0px)); max-height: calc(100svh - var(--cxh-top) - var(--cxh-copy, 0px)); min-height: min(240px, 75vw); overflow: hidden; background: var(--brand-2, #131210); }
.cxh__pic, .cxh__img, .cxh__canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.cxh__img { object-fit: contain; object-position: 50% 50%; }
.cxh__canvas { z-index: 1; opacity: 0; transition: none; }
.cxh.is-live .cxh__canvas { opacity: 1; }
.cxh__bar { position: absolute; z-index: 3; top: max(10px, env(safe-area-inset-top)); left: 10px; right: 10px; display: flex; gap: 8px; justify-content: flex-end; font: 700 15px/1 system-ui, sans-serif; }
.cxh__bar a { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 46px; padding: 0 18px; border-radius: 12px; text-decoration: none; color: #fff !important; background: rgba(12, 12, 14, .72); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, .18); white-space: nowrap; }
.cxh__bar .cxh__go { background: var(--accent-fill, #C49A66); color: var(--accent-ink, #131210) !important; border-color: transparent; }
/* Phones and tablets: the headline and the quote buttons are straight under the film, so the bar over the picture is not needed (and would cover the sky and roof line). */
@media (max-width: 899px) { .cxh__bar { display: none; } }
/* Phones: exact 4:3, never shortened (tablets keep the max-height no-clip rule above) */
@media (max-width: 599px) { .cxh__stage { max-height: none; min-height: 0; } }
@media (min-width: 900px) {
  /* Desktop: the WHOLE frame, never cropped (owner 29 Oct: the house, car and driveway were cut off). The stage is full width and as tall as the
     frame at that width (width x 3/4), capped to the viewport; when the viewport is wider than 4:3 the frame is contained and the rest of the
     stage is the page background (no blur). Same maths as core/scroll-hero.js containRect for the canvas. */
  .cxh__stage { aspect-ratio: auto; max-height: none; min-height: 360px; height: min(calc(100vh - var(--cxh-top) - var(--cxh-hdr, 80px)), calc(100vw * var(--cxh-h, 3) / var(--cxh-w, 4))); height: min(calc(100svh - var(--cxh-top) - var(--cxh-hdr, 80px)), calc(100vw * var(--cxh-h, 3) / var(--cxh-w, 4))); }
  .cxh__img { object-fit: contain; object-position: 50% 50%; }
  /* The frame is drawn ~30% wider than the contained frame where the roof and car allow (core/scroll-hero.js desktopRect) and its edges fade into the
     page background: the canvas carries a CSS mask (--cxh-mask-c, set by the script; the poster <img> gets its own inline mask), the stage behind it is the page background. */
  .cxh.is-fx .cxh__canvas { -webkit-mask-image: var(--cxh-mask-c); mask-image: var(--cxh-mask-c); -webkit-mask-composite: source-in; mask-composite: intersect; }
  .cxh.is-fx.is-live .cxh__pic { visibility: hidden; }
  /* bottom left, over the foreground (lawn / footpath: below the house, steps and letterbox in every frame; the right corner is the preview chat bubble), never over the sky or the house */
  /* the page header stays fixed on desktop (below), so it carries the quote button: no second one over the film */
  .cxh__bar { display: none; }
  /* Wide 16:9 set (record has frames_w; core/scroll-hero.js removes data-cxh-wide when another set is in use): the stage is the whole viewport below the fixed
     header and the frame covers it edge to edge (canvas: focalCoverRect; poster <img>: cover, roof anchored near the top). No mask, no bands. */
  .cxh[data-cxh-wide] .cxh__stage { aspect-ratio: auto; max-height: none; min-height: 360px; height: calc(100vh - var(--cxh-top) - var(--cxh-hdr, 80px)); height: calc(100svh - var(--cxh-top) - var(--cxh-hdr, 80px)); }
  .cxh[data-cxh-wide] .cxh__img { object-fit: cover; object-position: 50% 10%; }
  .cxh.is-wide.is-live .cxh__pic { visibility: hidden; }
  .cxh__bar { top: auto; bottom: 14px; left: clamp(12px, 2vw, 32px); right: auto; }
  .cxh__bar a { min-height: 40px; padding: 0 14px; font-size: 14px; border-radius: 10px; }
}
.cxh__progress { position: absolute; z-index: 3; left: 0; right: 0; bottom: 0; height: 3px; background: var(--accent-fill, #C49A66); transform: scaleX(0); transform-origin: 0 50%; will-change: transform; }
/* the scrub: only with JS and when motion is allowed. The section is ~500vh; the pin holds while the scroll plays the build, and the
   last 10% of the scroll stays on the final frame (core/scroll-hero.js HOLD). Desktop pins only the stage on screen (the headline block
   below it is pinned too but off screen), so it gets a little more length for the same scrub time. */
@media (prefers-reduced-motion: no-preference) {
  /* the quote button only once the page header (with its own Get a quote) has scrolled away: never two at once */
  html.cxh-js .cxh__bar { opacity: 0; pointer-events: none; transition: opacity .25s; }
  html.cxh-js .cxh.is-pinned .cxh__bar { opacity: 1; pointer-events: auto; }
  html.cxh-js .cxh { height: 500vh; height: 500svh; }
  html.cxh-js .cxh__pin { position: sticky; top: var(--cxh-top); }
  /* the look's own sticky header would sit on top of the pinned film (hiding the roof): it scrolls away with the page instead */
  html.cxh-js [data-style]:has([data-cx-scrollhero]) > header { position: static !important; margin-bottom: 0 !important; }
}
/* Desktop (>= 900 px): the page header stays fixed at the top for the whole page, film included (owner 30 Oct). The pinned film sits BELOW it:
   the pin and the stage height both subtract the header's height (--cxh-hdr, measured by core/scroll-hero.js; 80px until then), so the roof is
   never under the header and the focal-box fit uses the space actually visible. Anchor links land below it too. */
@media (min-width: 900px) {
  html.cxh-js [data-style]:has([data-cx-scrollhero]) > header { position: sticky !important; top: var(--cxh-top) !important; z-index: 40; margin-bottom: 0 !important; }
  html.cxh-js [data-style]:has([data-cx-scrollhero]) [id] { scroll-margin-top: calc(var(--cxh-top) + var(--cxh-hdr, 80px) + 8px); }
}
@media (prefers-reduced-motion: no-preference) and (min-width: 900px) {
  html.cxh-js .cxh__pin { top: calc(var(--cxh-top) + var(--cxh-hdr, 80px)); }
}
@media (prefers-reduced-motion: no-preference) and (min-width: 900px) { html.cxh-js .cxh { height: 560vh; height: 560svh; } }
@media (prefers-reduced-motion: reduce) { .cxh__progress { display: none; } }
/* An ACTIVE site already has the phone's fixed Call / Quote bar: no second pair on phones. */
@media (max-width: 760px) { .cx-site:has(.cx-actbar) .cxh__bar { display: none; } }
/* the look's own hero inside the pin: its photo column is gone, so the copy takes the full width */
[data-cx-film="after"] { display: block !important; min-height: 0 !important; }
[data-cx-film="after"] > * { max-width: min(100%, 1100px); }
.mo-hero[data-cx-film="after"] { display: grid !important; grid-template-columns: minmax(0, 1fr) !important; }

/* The headline block's empty right side (desktop): a tall frame that slowly crossfades through real job photos (record.hero_reel), each with its caption.
   Pure CSS (no JS): slide i starts i x 6 s into a 6 s x n loop. Reduced motion / phones: hidden on phones, the first photo static on desktop. */
.cxh__reel { display: none; }
@media (min-width: 900px) {
  [data-cx-film="after"].has-reel { display: grid !important; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr) !important; gap: clamp(24px, 4vw, 64px); align-items: stretch; }
  [data-cx-film="after"].has-reel > * { max-width: none; }
  .cxh__reel { display: block; position: relative; margin: 0; min-height: 420px; overflow: hidden; background: var(--brand-2, #131210); border: 1px solid rgba(255, 255, 255, .1); }
  .cxh__slide { position: absolute; inset: 0; opacity: 0; }
  .cxh__slide:first-child { opacity: 1; }
  .cxh__slide img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
  .cxh__slide figcaption { position: absolute; left: 0; right: 0; bottom: 0; padding: 40px 16px 14px; font: 500 12px/1.3 ui-monospace, 'SF Mono', Menlo, monospace; letter-spacing: .06em; text-transform: uppercase; color: #fff; background: linear-gradient(transparent, rgba(8, 8, 9, .78)); }
}
@media (min-width: 900px) and (prefers-reduced-motion: no-preference) {
  .cxh__slide { animation: cxh-reel-4 calc(6s * var(--n)) linear infinite; animation-delay: calc(6s * var(--i) - 1.2s); animation-fill-mode: backwards; }
  .cxh__slide:first-child { opacity: 0; }
}
@keyframes cxh-reel-2 { 0% { opacity: 0; } 10.00% { opacity: 1; } 50.00% { opacity: 1; } 60.00% { opacity: 0; } 100% { opacity: 0; } }
.cxh__reel[data-cxh-reel="2"] .cxh__slide { animation-name: cxh-reel-2; }
@keyframes cxh-reel-3 { 0% { opacity: 0; } 6.67% { opacity: 1; } 33.33% { opacity: 1; } 40.00% { opacity: 0; } 100% { opacity: 0; } }
.cxh__reel[data-cxh-reel="3"] .cxh__slide { animation-name: cxh-reel-3; }
@keyframes cxh-reel-4 { 0% { opacity: 0; } 5.00% { opacity: 1; } 25.00% { opacity: 1; } 30.00% { opacity: 0; } 100% { opacity: 0; } }
@keyframes cxh-reel-5 { 0% { opacity: 0; } 4.00% { opacity: 1; } 20.00% { opacity: 1; } 24.00% { opacity: 0; } 100% { opacity: 0; } }
.cxh__reel[data-cxh-reel="5"] .cxh__slide { animation-name: cxh-reel-5; }
@keyframes cxh-reel-6 { 0% { opacity: 0; } 3.33% { opacity: 1; } 16.67% { opacity: 1; } 20.00% { opacity: 0; } 100% { opacity: 0; } }
.cxh__reel[data-cxh-reel="6"] .cxh__slide { animation-name: cxh-reel-6; }
