/*
 * Hero canvas — scroll-driven frame sequence (WOW 1).
 * Adapted to the theme design system: charcoal backdrop, Outfit / Work Sans,
 * red #b93338 accents, existing .btn for the CTA.
 */

.hero-canvas {
  position: relative;
  /* Tall section = the scroll room. The inner stage sticks (CSS) for the
     500vh - 100vh = 400vh of scroll. GSAP only SCRUBS the frames against
     this range — it does NOT pin (a GSAP pin here added its own pin-spacing
     ON TOP, double-counting the distance). CSS sticky anchors; GSAP scrubs. */
  height: 500vh;
  background: var(--color-charcoal);
  /* Pull up under the fixed header so the canvas is full-bleed and the
     transparent header floats over it. */
  margin-top: calc(var(--header-h-mobile) * -1);
  /* Cushioned release: the stage lifts -12vh via --release (see
     .hero-canvas__sticky). This negative margin-bottom pulls the marquee up
     by the SAME amount so the lift leaves no charcoal gap behind it. The
     section's own box is unchanged — the hero ScrollTrigger end is safe. */
  margin-bottom: calc(-12vh * var(--release, 0));
}
@media (min-width: 1024px) {
  .hero-canvas { margin-top: calc(var(--header-h) * -1); }
}

/* CSS position: sticky does the anchoring — no GSAP pin involved.
   The translateY (--release, set by hero-canvas.js, ease-in) gives the
   stage upward momentum in the final stretch so the sticky release blends
   into motion instead of jolting from a dead stop. */
.hero-canvas__sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  width: 100%;
  overflow: hidden;
  transform: translate3d(0, calc(-12vh * var(--release, 0)), 0);
}

/* Canvas fills the sticky stage; JS handles cover-fit + DPR scaling. */
.hero-canvas__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  background: var(--color-charcoal);
}

/* Mobile-only vertical video (9:16). Hidden on desktop, where the canvas
   frame-scrub is used instead. Shown via the mobile media query below. */
.hero-canvas__video {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--color-charcoal);
}

/* Black veil — sits above the canvas, below the text. Starts at 0.8 opacity
   and JS fades it to 0 across the scroll, so the house emerges from darkness
   while the logo / beats stay fully legible on top. */
.hero-canvas__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: #000;
  opacity: 0.8;
  pointer-events: none;
}

/* Permanent bottom gradient — grounds the animation and keeps the beats /
   CTA / scroll hint readable even at scroll-end when the veil is gone. */
.hero-canvas__gradient {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 50%;
  z-index: 1;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 100%);
  pointer-events: none;
}

/* Vignette — radial edge-darkening for a cinematic framed look. Sits with
   the veil / gradient (z-index 1), below all text. */
.hero-canvas__vignette {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(ellipse 78% 78% at 50% 47%,
              rgba(0, 0, 0, 0) 55%, rgba(0, 0, 0, 0.55) 100%);
}

/* Film grain — fine desaturated SVG noise at low opacity over the dark
   layers for a 35mm texture. Static (no animation) to keep the hero calm.
   Tune the strength with `opacity` below. */
.hero-canvas__grain {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.07;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
}

/* Overlay — centered brand + tagline, fades out in the first ~30% of scroll */
.hero-canvas__overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: var(--color-white);
  pointer-events: none;
  padding-inline: var(--gutter);
}

/* Title is now the white vertical logo (isotipo + CONSTRUCTION wordmark). */
.hero-canvas__title {
  margin: 0;
  line-height: 0;
}
.hero-canvas__logo {
  display: block;
  width: clamp(200px, 25vw, 390px);
  height: auto;
  filter: drop-shadow(0 10px 56px rgba(0, 0, 0, 0.65));
}

/* Tagline — promoted from a tiny caption to a confident statement line.
   The logo SVG viewBox is now cropped to its real content bounds, so the
   gap here is purely this margin (no phantom SVG whitespace). */
.hero-canvas__tagline {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.125rem, 2vw, 1.875rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-top: var(--space-3);
  color: #ffffff;
  text-shadow: 0 3px 26px rgba(0, 0, 0, 0.7);
}
.hero-canvas__num {
  color: var(--color-red-on-dark);
  font-weight: 800;
  margin-right: 0.45rem;
}

/* Scroll-storytelling beats — narrate the build mid-scroll.
   Centered lower-third; all three stack at the same anchor and the JS
   cross-fades them. Parent handles horizontal centering; children only
   get translateY + opacity from JS, so there's no transform conflict. */
.hero-canvas__beats {
  position: absolute;
  left: 50%;
  bottom: clamp(6rem, 18vh, 12rem);
  transform: translateX(-50%);
  z-index: 2;
  width: min(48ch, 88vw);
  text-align: center;
  pointer-events: none;
}
.hero-canvas__beat {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  opacity: 0;
  will-change: opacity, transform;
}
.hero-canvas__beat-num {
  display: inline-block;
  font-family: var(--font-display);
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  color: var(--color-red-on-dark);
  margin-bottom: var(--space-2);
}
.hero-canvas__beat-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(1.75rem, 3.4vw, 3rem);
  letter-spacing: var(--tracking-tight);
  line-height: 1.04;
  color: var(--color-white);
  margin: 0 0 var(--space-2);
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.65);
}
.hero-canvas__beat-text {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(0.95rem, 1.2vw, 1.0625rem);
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.9);
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.75);
  margin: 0;
}

/* CTA — reuses .btn .btn--primary. Pinned bottom-center, revealed by JS. */
.hero-canvas__cta {
  position: absolute;
  bottom: var(--space-9);
  left: 50%;
  z-index: 3;
  transform: translateX(-50%) translateY(20px);
  opacity: 0;
  pointer-events: auto;
}
.hero-canvas__cta:hover { transform: translateX(-50%) translateY(-1px); }

/* Scroll hint — minimal, only on this scroll-driven hero */
.hero-canvas__scroll-hint {
  position: absolute;
  bottom: var(--space-5);
  right: var(--gutter);
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-display);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}
.hero-canvas__scroll-hint::after {
  content: '';
  width: 1px;
  height: 28px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.6), transparent);
  animation: heroCanvasScroll 1.8s ease-in-out infinite;
}
@keyframes heroCanvasScroll {
  0%, 100% { transform: scaleY(1);   transform-origin: top; }
  50%      { transform: scaleY(0.4); transform-origin: top; }
}

/* Vertical scroll-progress indicator — fills as the house is built.
   Driven by --scroll-progress (0-1), set by hero-canvas.js. */
.hero-canvas__progress {
  position: absolute;
  left: var(--gutter);
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  width: 2px;
  height: clamp(80px, 13vh, 132px);
  background: rgba(255, 255, 255, 0.16);
  border-radius: 2px;
  overflow: hidden;
  pointer-events: none;
}
.hero-canvas__progress-fill {
  position: absolute;
  inset: 0;
  background: var(--color-red);
  transform-origin: top;
  transform: scaleY(var(--scroll-progress, 0));
}

/* Preloader — covers the stage while the 64 frames decode, then CSS-fades
   out once hero-canvas.js adds .is-done. Charcoal backdrop = seamless
   handoff into the canvas (which is also charcoal until the veil lifts). */
.hero-canvas__preloader {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  background: var(--color-charcoal);
  transition: opacity 0.7s ease;
}
.hero-canvas__preloader.is-done {
  opacity: 0;
  pointer-events: none;
}
.hero-canvas__preloader-label {
  font-family: var(--font-display);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
}
.hero-canvas__preloader-pct {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(2.5rem, 7vw, 4.5rem);
  line-height: 1;
  color: var(--color-white);
}
.hero-canvas__preloader-bar {
  width: clamp(150px, 24vw, 240px);
  height: 2px;
  background: rgba(255, 255, 255, 0.12);
  border-radius: 2px;
  overflow: hidden;
}
.hero-canvas__preloader-fill {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--color-red);
  transform-origin: left;
  transform: scaleX(0);
  transition: transform 0.25s ease;
}

/* Mobile scroll cue — hero-canvas.js adds .is-cue to the section after the
   video finishes (only if the user hasn't scrolled). A bouncing chevron,
   fixed to the bottom of the viewport, invites the user to keep scrolling.
   Removed on the first scroll. */
.hero-canvas__scroll-cue { display: none; }
@media (hover: none) and (pointer: coarse) {
  .hero-canvas.is-cue .hero-canvas__scroll-cue {
    display: block;
    position: fixed;
    left: 50%;
    bottom: calc(var(--space-5) + env(safe-area-inset-bottom, 0px));
    z-index: 6;
    width: 18px;
    height: 18px;
    border-right: 2px solid rgba(255, 255, 255, 0.9);
    border-bottom: 2px solid rgba(255, 255, 255, 0.9);
    filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.6));
    pointer-events: none;
    animation: heroCueBounce 1.5s ease-in-out infinite;
  }
}
@keyframes heroCueBounce {
  0%, 100% { transform: translate(-50%, 0)   rotate(45deg); opacity: 0.55; }
  50%      { transform: translate(-50%, 9px) rotate(45deg); opacity: 1; }
}

/* Mobile — vertical video hero. One screen, no scroll scrub: the 9:16 video
   loops on its own, so the canvas, preloader and scroll-only chrome are hidden
   and the CTA shows statically. */
@media (hover: none) and (pointer: coarse) {
  .hero-canvas { height: 100vh; height: 100dvh; }
  .hero-canvas__media,
  .hero-canvas__preloader { display: none; }
  .hero-canvas__video { display: block; }
  /* Fixed dark level on mobile — the video stays darkened throughout (the
     animated darken/clear envelope was removed because its steps looked rough). */
  .hero-canvas__veil { opacity: 0.5; }
  .hero-canvas__beats,
  .hero-canvas__progress,
  .hero-canvas__scroll-hint { display: none; }
  .hero-canvas__cta {
    bottom: var(--space-7);
    opacity: 1;
    transform: translateX(-50%);
  }
}

/* Touch landscape (very short height): keep the overlay compact so the logo,
   tagline and CTA don't overlap. */
@media (hover: none) and (pointer: coarse) and (orientation: landscape) {
  .hero-canvas__overlay { padding-block: var(--space-3); }
  .hero-canvas__logo { width: auto; height: clamp(60px, 26vh, 116px); }
  .hero-canvas__tagline {
    font-size: clamp(0.72rem, 2.4vh, 0.95rem);
    margin-top: var(--space-2);
  }
  .hero-canvas__cta { bottom: var(--space-3); }
  .hero-canvas.is-cue .hero-canvas__scroll-cue { display: none; }
}

/* Reduced motion — no scroll scrub, so the beats can't cross-fade. Hide them.
   The veil is also cleared so the finished house shows at full brightness. */
@media (prefers-reduced-motion: reduce) {
  .hero-canvas__beats { display: none; }
  .hero-canvas__veil { opacity: 0; }
  /* No scrub = the progress bar would sit frozen at 0 — hide it. */
  .hero-canvas__progress { display: none; }
}

/* Reduced motion — collapse to a single screen showing the finished house */
@media (prefers-reduced-motion: reduce) {
  .hero-canvas { height: 100vh; height: 100dvh; }
  .hero-canvas__scroll-hint { display: none; }
  .hero-canvas__cta { opacity: 1; transform: translateX(-50%); }
}

/* ─── Header over the canvas hero ────────────────────────────────
 * While over the canvas the header is nearly invisible (4% background, no
 * blur) — white nav + white-red logo floating over the animation.
 *
 * The --solidify CSS variable (0-1, driven by hero-canvas.js over the last
 * 15% of the hero scroll) ramps EVERY state-dependent property from the
 * over-hero look toward the full white-glass State C: background opacity
 * 0.04 -> 0.85, blur 0 -> 16px, text white -> charcoal, logo white-red ->
 * color. At --solidify:1 the result is pixel-identical to State C, so when
 * the header finally leaves the hero the handoff is invisible — no snap. */
body.has-hero .site-header.is-on-hero,
body.has-hero .site-header.is-at-top {
  background: rgba(255, 255, 255, calc(0.04 + 0.81 * var(--solidify, 0)));
  -webkit-backdrop-filter: blur(calc(16px * var(--solidify, 0))) saturate(180%);
  backdrop-filter: blur(calc(16px * var(--solidify, 0))) saturate(180%);
  border-bottom-color: rgba(17, 17, 17, calc(0.06 * var(--solidify, 0)));
  /* Lift shadow ramps in with --solidify too, so at --solidify:1 it already
     matches State C's shadow exactly — when is-on-hero drops there is NO
     shadow pop, no "ripped off" jolt. */
  box-shadow: 0 4px 24px rgba(17, 17, 17, calc(0.06 * var(--solidify, 0)));
  color: color-mix(in srgb, #ffffff, var(--color-charcoal) calc(var(--solidify, 0) * 100%));
  /* The scroll IS the timeline — kill the 300ms CSS transition so the
     header tracks the scroll 1:1. With a transition it lagged ~300ms behind
     the scroll and then snapped, which read as the bar being "yanked". */
  transition: none;
}
body.has-hero .site-header.is-on-hero .primary-nav a,
body.has-hero .site-header.is-at-top .primary-nav a,
body.has-hero .site-header.is-on-hero .site-header__phone,
body.has-hero .site-header.is-at-top .site-header__phone {
  color: color-mix(in srgb, rgba(255, 255, 255, 0.95), var(--color-charcoal) calc(var(--solidify, 0) * 100%));
  text-shadow: 0 1px 10px rgba(0, 0, 0, calc(0.5 * (1 - var(--solidify, 0))));
}
body.has-hero .site-header.is-on-hero .site-header__phone,
body.has-hero .site-header.is-at-top .site-header__phone { opacity: 0.9; }
body.has-hero .site-header.is-on-hero .site-header__phone svg,
body.has-hero .site-header.is-at-top .site-header__phone svg { color: var(--color-red); }
body.has-hero .site-header.is-on-hero .menu-toggle,
body.has-hero .site-header.is-at-top .menu-toggle {
  color: color-mix(in srgb, #ffffff, var(--color-charcoal) calc(var(--solidify, 0) * 100%));
}

/* Logo crossfade — white-red variant over the canvas, fading to the color
   variant as --solidify approaches 1 (header about to enter the marquee). */
body.has-hero .site-header.is-on-hero .site-logo__horizontal--dark,
body.has-hero .site-header.is-at-top .site-logo__horizontal--dark { opacity: var(--solidify, 0); }
body.has-hero .site-header.is-on-hero .site-logo__horizontal--light,
body.has-hero .site-header.is-at-top .site-logo__horizontal--light { opacity: calc(1 - var(--solidify, 0)); }
