/* Brixwood Builders — homepage (Hero build stage, Finished jobs, Where we work) */

/* ------------------------------------------------------------- hero stage */
.hero-stage {
  position: relative;
  height: 480vh;
  background: var(--bg);
}
.hero-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  /* the bar used to be this column's first row; now that it sits outside, this
     hands .hero-body back the same space, so nothing in the hero moves */
  padding-top: var(--hero-bar-h);
  overflow: hidden;
  background: var(--bg);
  color: var(--ink);
  display: flex;
  flex-direction: column;
}

.hero-bg {
  position: absolute;
  inset: 0;
  background: var(--bg);
  z-index: 0;
  pointer-events: none;
}
.hero-image {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 64%;
  z-index: 1;
  background-repeat: no-repeat, no-repeat;
  background-position: center, right center;
  background-blend-mode: multiply, normal;
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  pointer-events: none;
}
.hero-veil {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

/* The bar's height, needed twice below: once to pull the hero back up under
   the bar, once to give .hero-body the same top space it had when the bar was
   the hero's first flex row. Measured rather than derived — the nav plate's
   height is content-driven and no token expresses it. */
:root { --hero-bar-h: calc(var(--nav-top) + 44px); }

/* top row: logo + nav. It lives outside the hero (see index.html) because
   .cover sits in the root stacking context at z-index 6 and would paint over
   anything inside .hero-sticky — so this has to outrank it from out here. */
.hero-top {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  justify-content: center;
  /* out of the hero in the markup, but still overlaying it on screen: without
     this the bar would push the whole hero down by its own height */
  margin-bottom: calc(var(--hero-bar-h) * -1);
}

/* headline + subhead */
.hero-body {
  position: relative;
  z-index: 3;
  flex: 1;
  display: flex;
  align-items: center;
  padding: 0 56px;
}
.hero-body__col {
  max-width: 560px;
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.hero-headline {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  font-family: var(--font-display);
  font-size: 56px;
  line-height: 1.04;
  letter-spacing: -0.03em;
  font-weight: 800;
  text-wrap: pretty;
}
.hero-headline .accent { color: var(--accent); }
.hero-word {
  display: inline-block;
  transform-origin: left center;
  will-change: transform;
}
.hero-line2 { display: block; }
.hero-sub {
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.hero-sub p {
  margin: 0;
  max-width: 496px;
  font-size: 19px;
  line-height: 1.6;
  color: var(--ink-2);
  text-wrap: balance;
}
.hero-sub__actions {
  display: flex;
  align-items: center;
  gap: 28px;
  margin-top: 8px;
}

/* blueprint grid */
.hero-grid {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 46%;
  z-index: 2;
  pointer-events: none;
  opacity: 0.4;
  background-image:
    linear-gradient(90deg, var(--hair) 1px, transparent 1px 52px),
    linear-gradient(180deg, var(--hair) 1px, transparent 1px 52px);
  background-size: 52px 52px;
  background-position: 4px 6px, 4px 6px;
  -webkit-mask-image:
    linear-gradient(90deg, rgba(0,0,0,1) 0%, rgba(0,0,0,1) 38%, rgba(0,0,0,0) 82%),
    linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 20%, rgba(0,0,0,1) 70%, rgba(0,0,0,0) 100%);
  mask-image:
    linear-gradient(90deg, rgba(0,0,0,1) 0%, rgba(0,0,0,1) 38%, rgba(0,0,0,0) 82%),
    linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 20%, rgba(0,0,0,1) 70%, rgba(0,0,0,0) 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* the rising "We build ___" word list */
.hero-wordlist {
  position: absolute;
  z-index: 3;
  pointer-events: none;
  will-change: transform;
  font-family: var(--font-display);
  left: 50%;
  top: calc(50vh - 32px);
  opacity: 0;
}
.hero-wordlist > div {
  font-weight: 800;
  font-size: 66px;
  line-height: 81px;
  letter-spacing: -0.03em;
  white-space: nowrap;
  color: var(--hair-2);
  transition: color 0.45s ease;
}

/* ----------------------------------------------------------- finished jobs */
.cover {
  position: relative;
  z-index: 6;
  margin-top: -100vh;
  background: var(--bg);
}
.recent {
  position: relative;
  font-family: var(--font-body);
  font-weight: 450;
  padding: 0 56px 96px;
}
.recent__inner {
  max-width: 1240px;
  margin: 0 auto;
  position: relative;
}
.recent__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 48px 0 20px;
  border-bottom: 1px solid var(--hair);
}
.recent__head h2 {
  margin: 0;
  font-family: var(--font-heading);
  font-size: 32px;
  line-height: 1.08;
  letter-spacing: -0.022em;
  font-weight: 600;
  color: var(--ink);
}
.recent__track {
  position: absolute;
  left: 7px;
  top: 148px;
  bottom: 24px;
  width: 1.5px;
  background: var(--hair);
  -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 6%, rgba(0,0,0,1) 88%, rgba(0,0,0,0) 100%);
  mask-image: linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 6%, rgba(0,0,0,1) 88%, rgba(0,0,0,0) 100%);
}
.recent__progress {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 0%;
  background: linear-gradient(to bottom, var(--accent) 0%, var(--accent) 70%, var(--ink-3) 100%);
  opacity: 0;
  transition: opacity 240ms ease;
}
.recent__item {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
  gap: 40px;
  padding: 60px 0 0;
}
.recent__place {
  position: sticky;
  top: 96px;
  align-self: start;
  padding-left: 48px;
}
.recent__dot {
  position: absolute;
  left: 0;
  top: 6px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--hair-2);
  display: flex;
  align-items: center;
  justify-content: center;
}
.recent__dot::after {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
}
.recent__place span {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.recent__shots { display: flex; flex-direction: column; gap: 22px; min-width: 0; }
.rail {
  position: relative;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 20px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  cursor: grab;
  touch-action: pan-y;
  padding: 10px 0;
  -webkit-mask-image: linear-gradient(to right, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 2%, rgba(0,0,0,1) 98%, rgba(0,0,0,0) 100%);
  mask-image: linear-gradient(to right, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 2%, rgba(0,0,0,1) 98%, rgba(0,0,0,0) 100%);
}
.rail::-webkit-scrollbar { display: none; }
.rail__card {
  position: relative;
  cursor: pointer;
  flex: 0 0 58%;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  overflow: hidden;
  background: repeating-linear-gradient(135deg, var(--surf-2) 0px, var(--surf-2) 10px, var(--surf) 10px, var(--surf) 20px);
  will-change: transform, opacity, filter;
  user-select: none;
}
.rail__card-img {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
}

/* ----------------------------------------------------------- where we work */
.where {
  position: relative;
  min-height: 78vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg);
  font-family: var(--font-body);
  font-weight: 450;
}
.where__copy {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 64px 56px;
  text-align: center;
}
.where__eyebrow {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 18px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.where__copy h2 {
  margin: 0;
  max-width: 890px;
  font-family: var(--font-heading);
  font-size: 40px;
  line-height: 1.14;
  letter-spacing: -0.022em;
  font-weight: 600;
  color: var(--ink);
  text-wrap: pretty;
}
.where__copy p {
  margin: 0;
  max-width: 710px;
  font-size: 19px;
  line-height: 1.65;
  color: var(--ink-2);
  text-wrap: pretty;
}
/* The number under the closing line, which offers the call the line just asked
   for. A text link and not a CTA: the hero owns the pill, and this is meant to
   read as the sentence's own answer rather than a second button competing with
   it. Montserrat 450, as the number is everywhere else it appears.

   Underlined because, standing alone under a paragraph, an unmarked number
   reads as one more line of copy instead of the thing to press. The rule is
   --hair-2 so the mark sits under the number without boxing it in, and goes to
   full ink on hover — the global a:hover fades a link to --ink-3, which is the
   wrong direction for the one thing on this section you are meant to press.

   The 44px is hit area, not artwork: the number stays 19px and the box grows
   around it, so it is thumb-sized on a phone without looking like a button. */
.where__phone {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 4px;
  font-family: var(--font-body);
  font-weight: 450;
  font-size: 19px;
  color: var(--ink);
  white-space: nowrap;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 6px;
  text-decoration-color: var(--hair-2);
  transition: text-decoration-color 0.2s ease;
}
.where__phone:hover,
.where__phone:focus-visible {
  color: var(--ink);
  text-decoration-color: var(--ink);
}

.where__map {
  position: relative;
  flex: 0 0 auto;
  width: 100%;
  height: 30vh;
  -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 46%);
  mask-image: linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 46%);
}

/* --------------------------------------------------------------- lightbox */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  backdrop-filter: blur(22px) saturate(112%);
  -webkit-backdrop-filter: blur(22px) saturate(112%);
  cursor: default;
}
/* Sized from the width alone, so aspect-ratio always has a free dimension to
   derive and the box keeps the card's 4:3 whatever the screen. Setting height
   AND max-width instead left aspect-ratio nothing to do once both were pinned:
   on a phone the box came out 312x675, a portrait hole that cropped a
   landscape photograph down to its middle strip. The min() picks whichever
   budget runs out first — the height one on a laptop, the width one on a
   phone, where the photograph now spans the screen rather than the drop. */
.lightbox__box {
  position: relative;
  width: min(92vw, calc(80vh * 4 / 3));
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  overflow: hidden;
  cursor: zoom-in;
  touch-action: none;
  box-shadow: var(--lift-3);
}
.lightbox__inner {
  position: absolute;
  inset: 0;
  transform-origin: 50% 50%;
  will-change: transform;
  background: repeating-linear-gradient(135deg, var(--surf-2) 0px, var(--surf-2) 10px, var(--surf) 10px, var(--surf) 20px);
}

@media (max-width: 900px) {
  .hero-body { padding: 0 var(--page-pad-x-fluid); }
  .recent { padding-left: var(--page-pad-x-fluid); padding-right: var(--page-pad-x-fluid); }
  .recent__item { grid-template-columns: 1fr; gap: 20px; }
  /* relative, not static: .recent__dot is absolutely positioned inside this
     box, and unsticking it entirely made all three dots pile up on the section */
  .recent__place { position: relative; top: auto; padding-left: 28px; }
  .where__copy { padding: 64px var(--page-pad-x-fluid); }
}

/* --------------------------------------------------------------- phone (720) */
/* The desktop hero is a horizontal composition: text left, photo right, and the
   headline flies sideways to sit beside the word list. None of that survives a
   narrow screen, so the whole thing is rotated a quarter turn — text on top,
   photo as a bottom band, and the headline flight stacks the word list under
   the headline instead of beside it (the stacking itself is in home.js, which
   reads its type metrics back out of the CSS below). */
@media (max-width: 720px) {
  /* Must live here, not in main.css: the base `.hero-top { justify-content:
     center }` is in this file, which loads after main.css, so a same-specificity
     override there loses the cascade and the row stays centred. */
  .hero-top { justify-content: center; align-items: center; }
  :root { --hero-bar-h: 48px; }        /* the phone bar's 4px + 44px box */

  /* 480vh of scroll is desktop-wheel thinking; a thumb needs far less */
  .hero-stage { height: 300vh; }

  /* The text block is bottom-anchored at 61vh rather than pinned to the top, so
     it sits upper-middle instead of hard against the nav. That lands its last
     line about 15% into the photo band — and the band's feather is still under
     0.06 alpha there, so the overlap costs nothing and buys the whole drop.
     Capped at 340px so very tall phones don't push it past centre. */
  .hero-body {
    align-items: flex-end;
    padding-top: 0;
    padding-bottom: min(47vh, 408px);
  }
  .hero-body__col { width: 100%; max-width: 100%; gap: 20px; }
  .hero-headline { font-size: clamp(32px, 9.2vw, 44px); }
  .hero-sub { gap: 20px; }
  .hero-sub p { max-width: 100%; font-size: 14.5px; }
  /* the pair is 9px too wide to sit on one row at 402px, so stack them
     deliberately rather than letting them wrap into an uneven gap */
  .hero-sub__actions {
    flex-direction: row;
    align-items: center;
    flex-wrap: nowrap;
    gap: 10px;
  }

  /* The flown word list, sized so the longest word ("With Precision.") keeps a
     real margin at 360px; home.js reads these values back, so changing them
     here is enough to re-time the flight.

     Stacked under the headline the list can no longer show all five words —
     the ones above the active word would sit on top of "We Build" — so on a
     phone it becomes a single-line slot the words travel through, softened at
     both edges so they fade rather than clip. */
  .hero-wordlist {
    font-size: clamp(30px, 9.6vw, 52px);
    line-height: 1.22;
    height: 1.22em;
    overflow: hidden;
    text-align: center;
    -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 26%, rgba(0,0,0,1) 74%, rgba(0,0,0,0) 100%);
    mask-image: linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 26%, rgba(0,0,0,1) 74%, rgba(0,0,0,0) 100%);
  }
  .hero-wordlist > div {
    font-size: inherit;
    line-height: inherit;
  }

  /* Blueprint grid, phone version: full width rather than the desktop's 46%
     strip, and faded out vertically by ~52% of the viewport so it stops just
     above the CTA row. Ending it there means the horizontal rules never sit
     isolated in the empty gap below — what reads on a phone is the vertical
     lines running down from the top, which is the intent. */
  .hero-grid {
    width: 100%;
    opacity: 0.34;
    -webkit-mask-image:
      linear-gradient(90deg, rgba(0,0,0,1) 0%, rgba(0,0,0,1) 52%, rgba(0,0,0,0) 100%),
      linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 10%, rgba(0,0,0,1) 34%, rgba(0,0,0,0) 52%);
    mask-image:
      linear-gradient(90deg, rgba(0,0,0,1) 0%, rgba(0,0,0,1) 52%, rgba(0,0,0,0) 100%),
      linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 10%, rgba(0,0,0,1) 34%, rgba(0,0,0,0) 52%);
  }

  /* photo becomes a bottom band; its feather starts fully transparent at the
     top edge, so the copy above can overlap it without ever showing through */
  .hero-image {
    top: auto;
    bottom: 0;
    height: 46%;
  }

  /* --- finished jobs --- */
  .recent { padding-bottom: 64px; }
  .recent__head { padding-top: 40px; }
  .recent__item { padding-top: 44px; }
  .rail { gap: 14px; }
  .rail__card { flex: 0 0 50%; }   /* home.js re-sizes these; kept in step */

  /* On mobile the timeline track runs under the rail (place and shots now
     stack in one column instead of sitting in separate desktop columns), and
     a scrolled card's near-opaque body was drawing over the line — the stock
     2% edge fade wasn't enough to clear it. Pushed the left fade out into a
     real dead zone so a card fades to nothing well before it reaches the
     line, instead of right at it. Approved on the first rail, then carried to
     all three. */
  .rail {
    -webkit-mask-image: linear-gradient(to right, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 12%, rgba(0,0,0,1) 15%, rgba(0,0,0,1) 98%, rgba(0,0,0,0) 100%);
    mask-image: linear-gradient(to right, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 12%, rgba(0,0,0,1) 15%, rgba(0,0,0,1) 98%, rgba(0,0,0,0) 100%);
  }

  /* --- where we work --- */
  .where { min-height: 0; }
  .where__copy { padding: 56px var(--page-pad-x-fluid) 40px; }
  .where__copy h2 { font-size: clamp(26px, 7.4vw, 32px); }
  /* The copy was enlarged ~27% for desktop only; these two had no phone rule
     of their own, so pin them back to the sizes the phone layout was built
     and verified against. */
  .where__eyebrow { font-size: 14px; }
  .where__copy p { font-size: 15px; }
  .where__phone { font-size: 16px; }
  .where__map { height: 26vh; }
}
