/* =========================================================
   SHOAIB SALON — hero
   The salon's own banner artwork across the top, with the
   statement copy centred beneath it.

   The artwork is 2000x750 with the wordmark, tagline and address
   set into it, so it is shown WHOLE — the frame carries that same
   8:3 ratio and there is no max-height anywhere. A height clamp on
   a fixed-ratio box is exactly what crops it. Height on a short,
   wide window is instead controlled by capping the banner's WIDTH
   off the viewport height, which scales the picture down rather
   than cutting into it. Nothing is ever cropped.

   Nothing is laid over it either. The artwork is already
   composed — its own lettering occupies the left third — so an
   overlay or a badge would land on top of the address.

   Loads after styles.css.
   ========================================================= */

.hero{
  position:relative;
  background:var(--ink);
  /* Just enough to clear the fixed nav — any more reads as a dark band
     above a full-bleed image. */
  padding:clamp(74px,8vw,98px) 0 clamp(56px,7vw,88px);
  overflow:hidden;
  isolation:isolate;
}

/* A soft pool of the brand green behind the composition. */
.hero__glow{
  position:absolute; inset:0; z-index:0; pointer-events:none;
  background:
    radial-gradient(58% 62% at 72% 34%, rgba(24,59,30,.62) 0%, rgba(24,59,30,0) 68%),
    radial-gradient(46% 50% at 12% 78%, rgba(201,162,39,.10) 0%, rgba(201,162,39,0) 70%);
}

/* ---------- Banner ---------- */
/* Full bleed: no wrapper, no gutters, no width cap — the banner runs
   edge to edge of the viewport. The section itself has no horizontal
   padding, so width:100% here is the full screen width. */
.hero__banner-wrap{
  position:relative; z-index:2;
  width:100%;
  margin-bottom:clamp(34px,5vw,60px);
}
.hero__banner{
  /* The artwork's own ratio. No max-height: a height clamp is what crops
     a fixed-ratio box, and this must stay WHOLE — the wordmark, the
     tagline and the address are all set into the picture, so anything cut
     off is words lost. At 8:3 a full-width banner stays shorter than the
     viewport on every normal screen, so no cap is needed to keep it from
     overflowing. */
  position:relative;
  /* The walk-in's own ratio, matching both the poster served above 620px
     and the video that replaces it - 1440x810 and 1920x1080 are the same
     1.7778 to four decimals, so the handover moves nothing. */
  aspect-ratio:1920/1080;
}
/* Must track the <picture> breakpoint exactly. If the box ratio and the
   chosen file ever disagree, object-fit:cover below would crop the
   difference away — which is the one thing this banner must never do. */
@media (max-width:620px){
  /* True 9:16, and the exact ratio of BOTH the portrait poster (720x1280)
     and the portrait video (1080x1920). They agree to four decimals, so
     object-fit:cover has nothing to shave off and the handover from still
     to video moves nothing. */
  .hero__banner{ aspect-ratio:9/16; }
}
.hero__banner picture{ display:block; width:100%; height:100%; }
.hero__banner img{
  width:100%; height:100%;
  /* Box and image share a ratio, so cover and contain are identical
     here — cover simply avoids a hairline gap from rounding. */
  object-fit:cover; object-position:50% 50%;
}

/* The shared .media slot styles every photo on the site for a card: it
   rounds the corners, puts a grayscale/sepia grade over the picture and
   scales it on hover. All three are wrong here. This banner is not a
   photo in a card — it is finished artwork, run full width, and the ask
   was for it EXACTLY as supplied. A grade would shift its colour away
   from the file, rounded corners would cut into a full-bleed frame, and
   nothing spanning the top of the page should move under the pointer. */
.hero__banner{
  /* A frame that runs to the edges of the screen should not have
     corners rounded off against them. */
  border-radius:0;
}
.hero__banner img{
  /* .media puts a grayscale/sepia film grade on every photo on the
     site. A <video> is not an <img>, so the video never got it — and
     a graded still handing over to an ungraded video is a visible
     shift in colour, which is the one thing this handover must not
     be. Taking it off the still matches the two exactly.

     It could have been matched the other way, by grading the video
     instead. It is not, deliberately: that would run a four-function
     filter over every decoded frame while the visitor is scrubbing,
     and smooth scrubbing matters more here than the grade — most of
     all on a phone. It also happens to be the right call for the
     picture: this is the establishing shot of the room, and the warm
     light in it is the thing being sold. */
  filter:none;
  /* .media animates transform and filter on hover. Nothing on a
     full-screen backdrop should react to the pointer, and a running
     transform would fight the scrub. */
  transition:none;
}
.hero__banner:hover img{ transform:none; filter:none; }

.hero__inner{
  position:relative; z-index:2;
  width:100%; max-width:var(--wrap); margin-inline:auto;
  padding-inline:var(--gut);
  text-align:center;
}
.hero__copy{ min-width:0; }

.hero__title{
  margin:0 0 1.2rem;
  font-family:var(--display);
  font-weight:800; font-stretch:112%;
  font-size:clamp(2.4rem, 6.4vw, 4.6rem);
  line-height:.98; letter-spacing:-.02em; text-transform:uppercase;
  color:var(--white);
}
.hero__title .line{ display:block; overflow:hidden; }
.hero__title .line > span{ display:block; }
.hero__title em{ font-style:normal; color:var(--gold); }

.hero__lede{
  margin:0 auto 1.8rem; max-width:52ch;
  font-size:clamp(.96rem,1.4vw,1.08rem);
  line-height:1.68; color:var(--muted);
}
.hero__cta{ display:flex; flex-wrap:wrap; gap:12px; justify-content:center; }

/* =========================================================
   ENTRANCE
   The photo is never hidden — it is the biggest thing here and
   should paint the moment it decodes. Only the type animates.
   ========================================================= */
.js .hero__title .line > span{ opacity:0; transform:translateY(104%); }
.js .hero__title.is-in .line > span{
  opacity:1; transform:none;
  transition:transform 1s var(--ease), opacity .6s var(--ease);
}
.js .hero__title.is-in .line:nth-child(1) > span{ transition-delay:.10s; }
.js .hero__title.is-in .line:nth-child(2) > span{ transition-delay:.20s; }
.js .hero__title.is-in .line:nth-child(3) > span{ transition-delay:.30s; }

.js .hero .h-in{ opacity:0; transform:translateY(16px); }
.js .hero .h-in.is-in{
  opacity:1; transform:none;
  transition:opacity .7s var(--ease), transform .8s var(--ease);
  transition-delay:calc(var(--i, 0) * 90ms + .25s);
}

/* =========================================================
   RESPONSIVE
   ========================================================= */
@media (max-width:1000px){
  .hero{ padding-top:clamp(88px,14vw,116px); }
  /* Below this width the page is narrower than the height cap would
     ever allow, so let the banner simply fill the wrapper. */
  .hero__banner-wrap{ grid-template-columns:minmax(0,1fr); }
}

@media (max-width:600px){
  /* 8.4vw, not 11: the headline's longest line is "GROOM MAKEUP",
     and .line clips its overflow, so this is measured to fit rather
     than guessed. */
  .hero__title{ font-size:clamp(1.7rem, 8.4vw, 2.6rem); }
}

/* =========================================================
   MOTION PREFERENCES
   ========================================================= */
@media (prefers-reduced-motion:reduce){
  .js .hero__title .line > span,
  .js .hero .h-in{ opacity:1 !important; transform:none !important; }
}

/* =========================================================
   PRINT
   ========================================================= */
@media print{
  .hero{ background:#fff; padding-top:0; }
  .hero__glow{ display:none !important; }
  .hero__title,.hero__lede{ color:#000 !important; }
  .hero__banner{ box-shadow:none; border-color:#ccc; }
  .hero__banner-wrap{ grid-template-columns:minmax(0,1fr); }
}

/* =========================================================
   SCROLL-SCRUBBED WALK-IN
   The video sits exactly on top of its own first frame and fades in once
   it is buffered, so the handover is invisible. Everything that
   restructures the page is gated behind .is-scrub, which scrub.js only
   adds after the file is in memory - until then this section lays out
   exactly as it did before the video existed.
   ========================================================= */
.hero__scrub{
  position:absolute; inset:0;
  width:100%; height:100%;
  /* Same ratio as the box, so like the poster this neither crops nor
     letterboxes. */
  object-fit:cover; object-position:50% 50%;
  opacity:0;
  transition:opacity .6s var(--ease);
  pointer-events:none;
}
.hero__scrub.is-live{ opacity:1; }

/* The track is the scroll runway; the stage is what pins inside it. Their
   height difference IS the scrub distance, and scrub.js reads it back from
   the DOM rather than assuming it - change --scrub-run here and the JS
   follows. At 220svh on a 900px screen that is about 11px of scrolling per
   frame across 180 frames. */
.hero.is-scrub{
  --scrub-run:220svh;
  /* position:sticky dies inside an overflow:hidden ancestor, because that
     ancestor becomes the scroll container. clip crops identically without
     creating one. styles.css does the same on html and body for the same
     reason. */
  overflow:clip;
}
.hero.is-scrub .hero__banner-wrap{
  height:calc(100svh + var(--scrub-run));
  margin-bottom:0;
}
.hero.is-scrub .hero__scrub-stage{
  position:sticky; top:0;
  height:100svh;
  display:flex; align-items:center; justify-content:center;
}
/* Full bleed: edge to edge and floor to ceiling. aspect-ratio is released
   so the frame takes the shape of the screen, and object-fit:cover on the
   video and poster inside decides what falls outside. This is the one
   picture on the site that is deliberately cropped - it carries no text,
   and the walk is centred, so filling the screen costs nothing. */
.hero.is-scrub .hero__banner{
  width:100%; height:100%;
  aspect-ratio:auto;
  margin-inline:0;
  border-radius:0;
}
/* The copy that follows the pinned stage needs its breathing room back,
   since the track's margin was zeroed above. */
.hero.is-scrub .hero__inner{ padding-top:clamp(34px,5vw,60px); }

@media (prefers-reduced-motion:reduce){
  .hero__scrub{ display:none !important; }
}
