/* ============================================================
   Sprucebird v2 — motion.css
   Motion layer over cinematic-paper.css. Loaded AFTER it on
   every page. Companion script: /scripts/motion.js
   Progressive enhancement only:
     · no-JS  → html has no .js class → nothing here hides content
     · reduced motion → everything instant / visible
     · Firefox → parallax + view transitions silently skipped
   ============================================================ */

/* ---- Easing + duration tokens -------------------------------- */
:root {
  --ease-expo-out:     cubic-bezier(0.16, 1, 0.3, 1);  /* entrances / reveals */
  --ease-quart-out:    cubic-bezier(0.25, 1, 0.5, 1);  /* small UI moves */
  --ease-in-out-quart: cubic-bezier(0.76, 0, 0.24, 1); /* underlines, A-to-B */
  --ease-out-cubic:    cubic-bezier(0.33, 1, 0.68, 1); /* opacity-only fades */
}

/* ---- Lenis recommended base styles ---------------------------- */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }

/* ---- Link underline wipe (footer + body links) ----------------
   Grows from the left on enter, wipes out through the right on exit.
   Static affordance is fine under reduced motion (transition killed
   by the global reduce block at the bottom of this file).
   NOTE: transitions background-size — a deliberate, accepted exception
   to the transform/opacity/clip-path/filter whitelist: it is paint-only
   on a 1px gradient (no layout/reflow), measured perf impact nil. */
.foot__col a, .foot__base a, .foot__contact a,
.prose a, .page-intro__crumb a, .contact__aside a {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-size: 0% 1px;
  background-position: 100% 100%;
  transition: background-size .45s var(--ease-in-out-quart), color .3s var(--ease-out-cubic);
}
.foot__col a:hover, .foot__base a:hover, .foot__contact a:hover,
.prose a:hover, .page-intro__crumb a:hover, .contact__aside a:hover {
  background-size: 100% 1px;
  background-position: 0% 100%;
}

/* ---- Nav link two-line text swap (structure built by motion.js) */
html.js .nav__link .nav__swap {
  display: block;
  overflow: hidden;
  position: relative;
}
html.js .nav__swap-line {
  display: block;
  transition: transform .4s var(--ease-in-out-quart);
}
html.js .nav__swap-line:nth-child(2) {
  position: absolute;
  top: 100%; left: 0; width: 100%;
}
@media (hover: hover) and (pointer: fine) {
  html.js .nav__link:hover .nav__swap-line { transform: translateY(-100%); }
}

/* keep the hover swap inert in the mobile overlay (taps, no hover) */
@media (max-width: 880px) {
  html.js .nav__link:hover .nav__swap-line { transform: none; }
}

/* ============================================================
   MOBILE NAV OVERLAY — morphing toggle · scroll lock · stagger
   ============================================================ */
/* body scroll lock while the overlay is open (class set by cinematic.js) */
html.sb-nav-open, body.sb-nav-open { overflow: hidden; }

@media (max-width: 880px) {
  /* hamburger ⇄ X (transform/opacity only) */
  .nav__toggle span { transition: background .25s var(--ease-out-cubic); }
  .nav__toggle span::before,
  .nav__toggle span::after { transition: transform .4s var(--ease-in-out-quart); }
  body.sb-nav-open .nav .nav__toggle span { background: transparent; }
  body.sb-nav-open .nav .nav__toggle span::before { transform: translateY(0) rotate(45deg); }
  body.sb-nav-open .nav .nav__toggle span::after  { transform: translateY(0) rotate(-45deg); }
}

@media (max-width: 880px) and (prefers-reduced-motion: no-preference) {
  /* per-item entrance delay (links 01-04, CTA, email) */
  .nav__links > :nth-child(1) { --sb-nav-d: .10s; }
  .nav__links > :nth-child(2) { --sb-nav-d: .19s; }
  .nav__links > :nth-child(3) { --sb-nav-d: .28s; }
  .nav__links > :nth-child(4) { --sb-nav-d: .37s; }
  .nav__links > :nth-child(5) { --sb-nav-d: .46s; }
  .nav__links > :nth-child(6) { --sb-nav-d: .52s; }

  /* fade-rise stagger — works even if motion.js never wrapped the text */
  .nav__links > * {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity .35s var(--ease-out-cubic), transform .6s var(--ease-expo-out);
  }
  .nav__links.is-open > * {
    opacity: 1;
    transform: none;
    transition-delay: var(--sb-nav-d, 0s);
  }

  /* line-mask rise on the link text (reuses the .nav__swap wrap) */
  html.js .nav__link .nav__swap { clip-path: inset(-0.2em 0); }
  html.js .nav__links:not(.is-open) .nav__link .nav__swap-line:first-child {
    transform: translateY(115%);
    transition: none;
  }
  html.js .nav__links.is-open .nav__link .nav__swap-line:first-child {
    transform: translateY(0);
    transition: transform .9s var(--ease-expo-out) var(--sb-nav-d, 0s);
  }
}

/* ============================================================
   MOTION (everything below is skipped under reduced motion)
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {

  /* ---- Preloader retune (overrides cinematic-paper values) ---- */
  .preloader {
    transition: opacity .8s var(--ease-in-out-quart),
                visibility .8s var(--ease-in-out-quart),
                transform .8s var(--ease-in-out-quart);
  }
  .preloader.is-done { transform: translateY(-2%); }
  .preloader__svg path { transition: stroke-dashoffset 1.1s var(--ease); }
  .preloader__svg.is-drawn path {
    transition: stroke-dashoffset 1.1s var(--ease), fill .8s ease .1s;
  }
  .preloader__word { animation: introMark .8s var(--ease) .45s forwards; }

  /* ---- 1 · Line-masked headline reveals ----------------------
     motion.js splits these into .line > .line-inner after
     document.fonts.ready. Pre-hidden only when JS is present;
     failsafe animation un-hides if splitting never completes. */
  html.js .hero__title, html.js .head__title, html.js .statement__big,
  html.js .stakes__big, html.js .cta__title, html.js .page-intro__title {
    opacity: 0;
    animation: sb-failsafe .4s var(--ease-out-cubic) 4s forwards;
  }
  html.js .sb-split-done { opacity: 1; animation: none; }

  /* clip-path, not overflow:hidden — Cormorant descenders need room */
  html.js .line { display: block; clip-path: inset(-0.25em 0); }
  html.js .line-inner {
    display: block;
    transform: translateY(115%);
    transition: transform 1.15s var(--ease-expo-out);
    transition-delay: var(--sb-line-d, 0ms);
  }
  html.js .sb-lines-in .line-inner { transform: translateY(0); }
  html.js .sb-resplit .line-inner { transition: none; }

  /* ---- Hero intro choreography (index only) -------------------
     body.sb-hero-go is added by motion.js the moment the hero
     headline reveal starts (after the preloader lifts). */
  html.js .hero__sub, html.js .hero__ctas {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity .7s var(--ease-out-cubic), transform 1s var(--ease-expo-out);
    animation: sb-failsafe .4s var(--ease-out-cubic) 4.5s forwards;
  }
  html.js .sb-hero-go .hero__sub  { opacity: 1; transform: none; transition-delay: .35s; animation: none; }
  html.js .sb-hero-go .hero__ctas { opacity: 1; transform: none; transition-delay: .5s;  animation: none; }

  html.js .hero__meta span {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity .55s var(--ease-out-cubic), transform .95s var(--ease-expo-out);
    animation: sb-failsafe .4s var(--ease-out-cubic) 4.5s forwards;
  }
  html.js .sb-hero-go .hero__meta span { opacity: 1; transform: none; animation: none; }
  html.js .sb-hero-go .hero__meta span:nth-child(1) { transition-delay: .6s; }
  html.js .sb-hero-go .hero__meta span:nth-child(2) { transition-delay: .69s; }
  html.js .sb-hero-go .hero__meta span:nth-child(3) { transition-delay: .78s; }

  /* ---- 2 · Scroll reveal retune ------------------------------ */
  .reveal {
    transform: translateY(24px);
    transition: opacity .55s var(--ease-out-cubic), transform .95s var(--ease-expo-out);
  }

  /* Stagger groups: motion.js tags containers .sb-group and their
     children .sb-si with a per-item --sb-d delay (90ms steps).
     A .reveal container that becomes a group stops moving itself —
     only its children animate. Children animate with keyframes
     (fill: backwards) so their own hover transitions stay intact. */
  html.js .sb-group.reveal { opacity: 1; transform: none; transition: none; }
  html.js .sb-si { opacity: 0; }
  html.js .sb-group.in .sb-si {
    opacity: 1;
    animation: sb-si-fade .55s var(--ease-out-cubic) var(--sb-d, 0ms) backwards,
               sb-si-rise .95s var(--ease-expo-out) var(--sb-d, 0ms) backwards;
  }

  /* ---- 3 · Scroll-driven parallax (CSS only, Chromium) --------
     `translate` composes with existing transforms (hero motif is
     centered via transform) and with the hover `scale` below. */
  @supports (animation-timeline: view()) {
    html.js .hero__motif,
    html.js .case__img .motif,
    html.js .feat__well .motif {
      animation: sb-drift linear both;
      animation-timeline: view();
    }
  }

  /* ---- 4 · Cross-document view transitions (MPA) -------------- */
  @view-transition { navigation: auto; }
  ::view-transition-old(root) {
    animation: sb-vt-out .35s var(--ease-out-cubic) both;
  }
  ::view-transition-new(root) {
    animation: sb-vt-in .5s var(--ease-expo-out) .1s both;
  }
  .nav { view-transition-name: site-header; }

  /* ---- 5 · Case-card hover: motif scale-settle ---------------- */
  html.js .case__img .motif { scale: 1.06; transition: scale .9s var(--ease-expo-out); }
  html.js .case:hover .case__img .motif { scale: 1; }

  /* ---- 6 · Card flip-up entrance -------------------------------
     Cards tip up from their bottom edge and settle flat (3D rotateX,
     origin at the bottom). motion.js tags standalone .reveal cards
     with .sb-flip and stagger children with .sb-si--flip.
     Flips run as keyframes (backwards fill, no forwards) so the
     element's own hover transitions stay intact afterwards; opacity
     keeps using the existing fade (transition or sb-si-fade). */
  html.js .sb-flip.reveal { transform: none; }
  html.js .sb-flip.reveal.in {
    transform-origin: 50% 100%;
    animation: sb-flip-in 1.05s var(--ease-expo-out) backwards;
  }
  html.js .sb-flip.reveal[data-delay="1"].in { animation-delay: .08s; }
  html.js .sb-flip.reveal[data-delay="2"].in { animation-delay: .16s; }
  html.js .sb-flip.reveal[data-delay="3"].in { animation-delay: .24s; }
  html.js .sb-group.in .sb-si--flip {
    transform-origin: 50% 100%;
    animation: sb-si-fade .55s var(--ease-out-cubic) var(--sb-d, 0ms) backwards,
               sb-flip-in 1.05s var(--ease-expo-out) var(--sb-d, 0ms) backwards;
  }

} /* end no-preference */

/* ---- Keyframes ------------------------------------------------ */
@keyframes sb-failsafe { to { opacity: 1; transform: none; } }
@keyframes sb-si-fade { from { opacity: 0; } }
@keyframes sb-si-rise { from { transform: translateY(var(--sb-rise, 24px)); } }
@keyframes sb-flip-in {
  from { transform: perspective(1100px) rotateX(var(--sb-flip-rot, 16deg)) translateY(var(--sb-flip-y, 46px)); }
}
@keyframes sb-drift {
  from { translate: 0 var(--sb-drift, 6%); }
  to   { translate: 0 calc(-1 * var(--sb-drift, 6%)); }
}
@keyframes sb-vt-out {
  to { opacity: 0; transform: translateY(-10px); }
}
@keyframes sb-vt-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ============================================================
   TOUCH TUNING — no sticky hovers, shorter travel, lighter blur
   ============================================================ */
@media (hover: none) {
  /* sticky-hover bugs: taps must not leave lifted/offset states behind */
  .btn:hover { transform: none; }
  .btn:hover .btn__arrow { transform: none; }
  .case:hover, .case.reveal.in:hover { transform: none; border-color: var(--rule); }
  .svc:hover > :not(.svc__arrow) { transform: none; }
  .svc:hover .svc__arrow { transform: none; }
  html.js .case__img .motif,
  html.js .case:hover .case__img .motif { scale: none; }
  /* cap backdrop blur cost on the scrolled bar */
  .nav.is-scrolled {
    backdrop-filter: blur(4px) saturate(1.1);
    -webkit-backdrop-filter: blur(4px) saturate(1.1);
  }
  /* 44px tap targets (visual layout unchanged via negative margins) */
  .chips label { min-height: 44px; align-items: center; }
  .foot__col a, .foot__base a, .foot__contact a {
    display: inline-block;
    padding: 11px 0;
    margin: -11px 0;
  }
}

@media (hover: none) and (prefers-reduced-motion: no-preference) {
  :root { --sb-drift: 3.5%; --sb-rise: 16px; --sb-flip-rot: 10deg; --sb-flip-y: 26px; }
  html.js .sb-flip.reveal.in { animation-duration: .8s; }
  html.js .sb-group.in .sb-si--flip { animation-duration: .45s, .8s; }
  .reveal {
    transform: translateY(16px);
    transition: opacity .45s var(--ease-out-cubic), transform .75s var(--ease-expo-out);
  }
  html.js .line-inner { transition-duration: .9s; }
  html.js .sb-group.in .sb-si {
    animation-duration: .45s, .75s;
  }
  html.js .hero__sub, html.js .hero__ctas {
    transition: opacity .55s var(--ease-out-cubic), transform .8s var(--ease-expo-out);
  }
}

/* ============================================================
   REDUCED MOTION — everything instant, everything visible
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001s !important;
    animation-delay: 0s !important;
    transition-duration: 0.001s !important;
    transition-delay: 0s !important;
  }
  html.js .hero__title, html.js .head__title, html.js .statement__big,
  html.js .stakes__big, html.js .cta__title, html.js .page-intro__title,
  html.js .hero__sub, html.js .hero__ctas, html.js .hero__meta span,
  html.js .sb-si {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }
  html.js .line-inner { transform: none !important; transition: none !important; }
  html.js .case__img .motif { scale: none !important; }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none !important; }
}

/* Focus treatment — quiet ring for mouse/programmatic focus, visible accent
   ring only for keyboard navigation */
.nav__link:focus { outline: none; }
.nav__link:focus-visible {
  outline: 1.5px solid var(--accent);
  outline-offset: 6px;
}
.nav__links:focus { outline: none; }
