/* ============================================================
   SOLID BUILD CO. — v2 overrides
   Loaded AFTER styles.css. Only what v2 changes.

   v2 interaction: one scroll gesture = one beat. Nine snap stops — the
   opening frame plus the eight captioned anchors. The snap moves the
   scroll instantly; the video eases between anchors on its own timing
   (app.v2.js TRANSITION_MS), so the move plays rather than jumping.
   ============================================================ */

/* nine stops, one screen each. Height MUST equal stops x 100vh, or the
   surplus becomes a dead tail containing no snap target. */
.walk{height:900vh}

.walk__stops{
  position:absolute; inset:0;
  pointer-events:none;
}
.walk__stop{
  height:100vh;
  scroll-snap-align:start;
  scroll-snap-stop:always;   /* never skip a beat on a fast flick */
}

/* Snapping is switched on only while the walk owns the viewport, so the
   rest of the page keeps native scrolling. Toggled in app.v2.js. */
html.is-snapping{
  scroll-snap-type:y mandatory;
}

/* Escape hatch. With mandatory snapping and snap targets ONLY inside the
   walk, the browser refuses to scroll past the final stop and the rest of
   the page becomes unreachable. Giving the sections below a snap target
   means there is somewhere to go; once the walk no longer owns the
   viewport, is-snapping is dropped and these become inert. */
#services, #experience, #contact{
  scroll-snap-align:start;
}

/* ---------- header: every alpha cut by a further 30% ---------- */
.hdr__pill{
  border-color:rgba(255,255,255,.070);
  background:linear-gradient(100deg, rgba(255,255,255,.063), rgba(255,255,255,.014) 60%, rgba(255,255,255,.035));
  backdrop-filter:blur(13px) saturate(130%);
  -webkit-backdrop-filter:blur(13px) saturate(130%);
  box-shadow:0 8px 26px rgba(0,0,0,.07), inset 0 1px 0 rgba(255,255,255,.084);
}
.hdr[data-theme="dark"] .hdr__pill{
  border-color:rgba(255,255,255,.049);
  background:linear-gradient(100deg, rgba(255,255,255,.035), rgba(255,255,255,.008) 55%, rgba(255,255,255,.021));
  box-shadow:0 8px 26px rgba(0,0,0,.18), inset 0 1px 0 rgba(255,255,255,.035);
}
.hdr[data-theme="bronze"] .hdr__pill{
  border-color:rgba(255,236,210,.056);
  background:linear-gradient(100deg, rgba(255,238,214,.042), rgba(255,238,214,.008) 55%, rgba(255,238,214,.025));
  box-shadow:0 8px 26px rgba(0,0,0,.15), inset 0 1px 0 rgba(255,240,220,.042);
}
.hdr[data-theme="stone"] .hdr__pill{
  border-color:rgba(255,255,255,.140);
  background:linear-gradient(100deg, rgba(255,255,255,.112), rgba(255,255,255,.028) 60%, rgba(255,255,255,.063));
}

/* ---------- services: longer, gentler ---------- */
.svc__row{transition:padding 1.05s var(--ease-soft), background 1.05s var(--ease-soft)}
/* selector length must match styles.css's `.svc__list .svc__row .svc__name`,
   otherwise that rule wins on specificity regardless of load order */
.svc__list .svc__row .svc__name{
  transition:transform 1.05s var(--ease-soft), opacity .8s var(--ease-soft);
}
.svc__right{transition:grid-template-rows 1.05s var(--ease-soft), transform 1.05s var(--ease-soft)}
.svc__num{transition:color .85s var(--ease-soft)}
.svc__desc{
  transition:opacity .8s var(--ease-soft) .14s, transform 1.05s var(--ease-soft) .14s;
}
.svc__row:hover, .svc__row:focus-visible, .svc__row.is-open{padding:26px 0}
.svc__row:hover .svc__name,
.svc__row:focus-visible .svc__name,
.svc__row.is-open .svc__name{transform:translateX(-9%)}
.svc__row:hover .svc__right,
.svc__row:focus-visible .svc__right,
.svc__row.is-open .svc__right{transform:translateX(-12px)}
.svc__list:hover .svc__row:not(:hover) .svc__name{opacity:.7}

/* ---------- contact: image dissolves in from the left ----------
   The base sheet lays a stone-coloured gradient OVER the photo, which
   still leaves a hard vertical edge where the element starts. Masking
   the element itself fades the pixels out instead, so there is no seam. */
.ct__top::after{
  width:58%;
  background:url("assets/exp-1.jpg?v=2") center/cover no-repeat;
  opacity:.55;
  mix-blend-mode:luminosity;
  -webkit-mask-image:linear-gradient(to right,
      rgba(0,0,0,0) 0%,
      rgba(0,0,0,.18) 22%,
      rgba(0,0,0,.55) 45%,
      rgba(0,0,0,.85) 72%,
      rgba(0,0,0,1) 100%);
          mask-image:linear-gradient(to right,
      rgba(0,0,0,0) 0%,
      rgba(0,0,0,.18) 22%,
      rgba(0,0,0,.55) 45%,
      rgba(0,0,0,.85) 72%,
      rgba(0,0,0,1) 100%);
}

@media (max-width:1100px){
  /* full width behind the text on smaller screens, so fade the top too */
  .ct__top::after{
    width:100%; opacity:.30;
    -webkit-mask-image:linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,.7) 55%, rgba(0,0,0,1) 100%);
            mask-image:linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,.7) 55%, rgba(0,0,0,1) 100%);
  }
}

/* ---------- contact: clear the bar, shorter footer ---------- */
.ct__top{
  min-height:auto;
  padding-top:calc(var(--hdr-h) + clamp(96px,12vh,168px));
  padding-bottom:clamp(52px,7vh,88px);
}
.ft{padding:clamp(30px,3.6vh,46px) var(--gutter) 18px}
.ft__lockup{--lockup:clamp(112px,10vw,150px)}
.ft__base{margin-top:clamp(26px,3.4vh,46px); padding-top:16px}
.ft__areas{margin-top:14px}

/* Captions settle in as the move finishes, and leave quickly so they are
   never on screen while the camera is travelling. */
.cap{
  transition:opacity .7s var(--ease) , transform .9s var(--ease-out);
}
.cap:not(.is-on){
  transition:opacity .28s var(--ease), transform .28s var(--ease);
}

@media (max-width:720px){
  .cap{transition:opacity .6s var(--ease), transform .75s var(--ease-out)}

  /* ---------- PHONE HEADER ----------
     At 375px the desktop `1fr auto 1fr` grid collapsed the brand column
     to 0 (mark squashed to 10px) and pushed the Contact button ~89px
     off-screen. Columns are now sized to content, and the text button
     is swapped for the icon, which is the only thing that fits. */
  .hdr{left:12px; right:12px; top:12px}
  .hdr__pill{
    grid-template-columns:auto 1fr auto;
    gap:6px;
    padding:0 8px 0 10px;
    height:56px;
  }
  .hdr:not([data-theme="light"]) .hdr__pill{height:52px; padding:0 8px 0 10px}

  .hdr__brand{margin-left:0}
  .hdr__mark,
  .hdr:not([data-theme="light"]) .hdr__mark{width:30px; height:30px}

  .hdr__nav{justify-self:center; gap:0}
  .hdr__link,
  .hdr:not([data-theme="light"]) .hdr__link{
    padding:6px 8px; font-size:12px; letter-spacing:0;
  }
  .hdr__ind,
  .hdr:not([data-theme="light"]) .hdr__ind{height:26px}

  .hdr .cta,
  .hdr:not([data-theme="light"]) .cta{
    height:34px; padding:0 12px; font-size:10px; letter-spacing:.04em;
  }
  .hdr .cta--icon,
  .hdr:not([data-theme="light"]) .cta--icon{width:34px; padding:0}
  .hdr .cta--icon svg{width:16px; height:16px}

  /* "Contact Us" as text cannot fit a phone — use the envelope instead */
  .hdr[data-action="full"] .cta--full{display:none}
  .hdr[data-action="full"] .cta--icon{display:inline-flex}

  /* ---------- PHONE FOOTER ----------
     The lockup art carries 25% transparent padding and is pulled back by
     that amount. The offset must never exceed the gutter (20px here) or
     the logo hangs off the left edge. 80px x 0.25 = exactly 20px. */
  .ft__lockup{--lockup:80px}
}

@media (prefers-reduced-motion:reduce){
  .walk{height:auto}
  html.is-snapping{scroll-snap-type:none}
  .walk__stops{display:none}
}
