/* On Point Tech: motion layer, 2026-11-01.
   Loaded on every public page AFTER the page's own stylesheet. Additive only: it never
   changes layout, colour tokens or copy, it only moves what is already there.

   Rules of the file
   - CSS first. Scroll-driven animation (animation-timeline), view transitions and
     ::details-content do the work; js/motion-20261101.js only feeds pointer coordinates.
   - Every moving thing sits under prefers-reduced-motion: no-preference. Reduce on =
     the page you had before this file.
   - Transform, opacity, clip-path and background-position only. No layout animation.
   - Both themes: colours come from the page's own tokens (--accent-rgb, --ink-rgb,
     --season, --hairline), so light (data-theme=light) and dark both work.
   - Filename carries the date and _headers marks it immutable. Edit = new filename. */

:root {
  --mo-ease: cubic-bezier(0.19, 1, 0.22, 1);
  --mo-aurora-1: rgba(127, 108, 224, 0.34);
  --mo-aurora-2: rgba(143, 195, 232, 0.20);
  --mo-spot: 0.14;
}
:root[data-theme="light"] {
  --mo-aurora-1: rgba(127, 108, 224, 0.26);
  --mo-aurora-2: rgba(46, 196, 196, 0.16);
  --mo-spot: 0.10;
}

/* ---------- 1. Scroll progress hairline (every page) ---------- */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: scroll()) {
    body::after {
      content: "";
      position: fixed;
      top: 0; left: 0;
      width: 100%; height: 2px;
      background: linear-gradient(90deg, var(--accent, #7f6ce0), var(--season, #9d8bff));
      transform-origin: 0 50%;
      transform: scaleX(0);
      z-index: 70;
      pointer-events: none;
      animation: mo-progress linear both;
      animation-timeline: scroll(root);
    }
    @keyframes mo-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  }
}

/* ---------- 2. Nav condenses as you leave the top (desktop) ---------- */
@media (prefers-reduced-motion: no-preference) and (min-width: 1000px) {
  @supports (animation-timeline: scroll()) {
    .nav {
      animation: mo-nav linear both;
      animation-timeline: scroll(root);
      animation-range: 0 220px;
    }
    @keyframes mo-nav {
      from { padding-top: 1.4rem; padding-bottom: 1.4rem; }
      to   { padding-top: 0.75rem; padding-bottom: 0.75rem; }
    }
  }
}

/* ---------- 3. Hero: aurora, word reveal, staged entrance (homepage) ---------- */
.hero2 { position: relative; z-index: 0; }
.hero2::before,
.hero2::after {
  content: "";
  position: absolute;
  z-index: -1;
  border-radius: 50%;
  pointer-events: none;
  filter: blur(64px);
  will-change: transform;
}
.hero2::before {
  width: clamp(260px, 42vw, 620px);
  aspect-ratio: 1;
  top: -8%; left: -6%;
  background: radial-gradient(circle at 40% 40%, var(--mo-aurora-1), transparent 68%);
}
.hero2::after {
  width: clamp(220px, 34vw, 520px);
  aspect-ratio: 1;
  right: -4%; bottom: -10%;
  background: radial-gradient(circle at 60% 60%, var(--mo-aurora-2), transparent 68%);
}
@media (prefers-reduced-motion: no-preference) and (min-width: 1000px) {
  .hero2::before { animation: mo-drift-a 22s ease-in-out infinite alternate; }
  .hero2::after  { animation: mo-drift-b 26s ease-in-out infinite alternate; }
  @keyframes mo-drift-a {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to   { transform: translate3d(14vw, 9vh, 0) scale(1.18); }
  }
  @keyframes mo-drift-b {
    from { transform: translate3d(0, 0, 0) scale(1.1); }
    to   { transform: translate3d(-12vw, -10vh, 0) scale(0.92); }
  }
}

/* Words in the h1 are wrapped as <span class="w"><span>word</span></span> in index.html.
   Each inner span rises out of its own mask; --i is the word index. The padding and
   negative margin give descenders (y, g, j) room inside the mask without moving the line. */
.hero2 h1 .w {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding: 0.14em 0.06em 0.18em;
  margin: -0.14em -0.06em -0.18em;
}
.hero2 h1 .w > span { display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
  .hero2 h1 .w > span {
    transform: translateY(112%);
    animation: mo-word-up 0.95s var(--mo-ease) both;
    animation-delay: calc(0.12s + 0.07s * var(--i, 0));
  }
  @keyframes mo-word-up { to { transform: translateY(0); } }

  .hero2 .eyebrow,
  .hero2 .sub,
  .hero2 .trust,
  .hero2 .q-stage {
    animation: mo-fade-up 0.9s var(--mo-ease) both;
  }
  .hero2 .eyebrow { animation-delay: 0.05s; }
  .hero2 .sub     { animation-delay: 0.55s; }
  .hero2 .trust   { animation-delay: 0.70s; }
  .hero2 .q-stage { animation-delay: 0.45s; }
  @keyframes mo-fade-up {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: translateY(0); }
  }
}

/* ---------- 4. Reveal cascade: siblings that already fade up now arrive in order ---------- */
@media (prefers-reduced-motion: no-preference) {
  .router > a.fade-up:nth-child(2),  .leaks-grid > .fade-up:nth-child(2),  .steps > .fade-up:nth-child(2),
  .pillars > .fade-up:nth-child(2),  .clients > .fade-up:nth-child(2),     .paths-grid > .fade-up:nth-child(2) { transition-delay: 0.09s; }
  .router > a.fade-up:nth-child(3),  .leaks-grid > .fade-up:nth-child(3),  .steps > .fade-up:nth-child(3),
  .pillars > .fade-up:nth-child(3),  .clients > .fade-up:nth-child(3) { transition-delay: 0.18s; }
  .router > a.fade-up:nth-child(4),  .steps > .fade-up:nth-child(4),       .clients > .fade-up:nth-child(4) { transition-delay: 0.27s; }
  .router > a.fade-up:nth-child(5) { transition-delay: 0.36s; }
  .router > a.fade-up:nth-child(6) { transition-delay: 0.45s; }
}

/* ---------- 5. Scroll-driven details (children of the faded blocks, so no fight with the observer) ---------- */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    /* kicker hairline draws itself as the section enters */
    .kicker .line, .funnel-kicker .line {
      transform-origin: 0 50%;
      animation: mo-draw linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 90%;
    }
    @keyframes mo-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }

    /* the accent word in a heading fills with colour as the heading crosses the screen */
    .lp h2 em, .lp h3 em {
      background-image: linear-gradient(90deg, var(--season, #9d8bff) 0 50%, rgba(var(--ink-rgb, 236, 233, 244), 0.30) 50% 100%);
      background-size: 200% 100%;
      background-position: 0% 0;
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;
      animation: mo-fill linear both;
      animation-timeline: view();
      animation-range: entry 30% cover 42%;
    }
    @keyframes mo-fill { from { background-position: 100% 0; } to { background-position: 0% 0; } }

    /* big numbers pop in */
    .stat .n {
      display: inline-block;
      animation: mo-pop linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 85%;
    }
    @keyframes mo-pop {
      from { opacity: 0.2; transform: translateY(0.35em) scale(0.86); }
      to   { opacity: 1;   transform: translateY(0) scale(1); }
    }

    /* the three leak mock-ups drift against the scroll */
    .leak-mock {
      animation: mo-parallax linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
    @keyframes mo-parallax { from { transform: translateY(22px); } to { transform: translateY(-22px); } }

    /* client screenshots wipe in and settle; founder portrait settles its zoom */
    .client-shot {
      animation: mo-wipe linear both;
      animation-timeline: view();
      animation-range: entry 5% entry 75%;
    }
    @keyframes mo-wipe {
      from { clip-path: inset(0 0 100% 0); transform: scale(1.06); }
      to   { clip-path: inset(0 0 0 0);    transform: scale(1); }
    }
    .portrait img {
      animation: mo-settle linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 60%;
    }
    @keyframes mo-settle { from { transform: scale(1.12); } to { transform: scale(1); } }
  }
}

/* ---------- 6. Cards: pointer spotlight, lift, arrow nudge ---------- */
.router a, .leak, .pillar, .path, .client, .ai-tile { position: relative; }
@media (hover: hover) and (pointer: fine) {
  .router a::before, .leak::before, .pillar::before, .path::before, .client::before, .ai-tile::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    opacity: 0;
    background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%), rgba(var(--accent-rgb, 127, 108, 224), var(--mo-spot)), transparent 62%);
    transition: opacity 0.35s ease;
  }
  .router a:hover::before, .leak:hover::before, .pillar:hover::before, .path:hover::before, .client:hover::before, .ai-tile:hover::before { opacity: 1; }
  .leak, .pillar, .path, .client { transition: border-color 0.35s ease, transform 0.45s var(--mo-ease), box-shadow 0.45s ease; }
  .leak:hover, .pillar:hover, .path:hover, .client:hover {
    border-color: rgba(var(--accent-rgb, 127, 108, 224), 0.55);
    transform: translateY(-3px);
  }
  .router a .go { display: inline-block; transition: transform 0.35s var(--mo-ease); }
  .router a:hover .go { transform: translateX(5px); }
  .client-shot { transition: transform 0.6s var(--mo-ease); }
  .client:hover .client-shot { transform: scale(1.025); }
}

/* ---------- 7. Pills: sheen sweep, live dot, press ---------- */
.pill { position: relative; overflow: hidden; }
.pill .dot { position: relative; }
@media (prefers-reduced-motion: no-preference) {
  .pill::after {
    content: "";
    position: absolute;
    inset: -40% -20%;
    pointer-events: none;
    background: linear-gradient(115deg, transparent 38%, rgba(255, 255, 255, 0.42) 50%, transparent 62%);
    transform: translateX(-130%) skewX(-12deg);
    transition: transform 0.75s var(--mo-ease);
  }
  .pill:not(.pill--solid)::after {
    background: linear-gradient(115deg, transparent 38%, rgba(var(--accent-rgb, 127, 108, 224), 0.22) 50%, transparent 62%);
  }
  .pill:hover::after, .pill:focus-visible::after { transform: translateX(130%) skewX(-12deg); }
  .pill:hover .dot, .pill:focus-visible .dot { animation: mo-ping 1.1s ease-out infinite; }
  @keyframes mo-ping {
    0%   { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.55); }
    100% { box-shadow: 0 0 0 9px rgba(255, 255, 255, 0); }
  }
  .pill:not(.pill--solid):hover .dot { animation-name: mo-ping-accent; }
  @keyframes mo-ping-accent {
    0%   { box-shadow: 0 0 0 0 rgba(var(--accent-rgb, 127, 108, 224), 0.5); }
    100% { box-shadow: 0 0 0 9px rgba(var(--accent-rgb, 127, 108, 224), 0); }
  }
  .pill { transition: transform 0.25s var(--mo-ease), background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease; }
  .pill:active { transform: scale(0.97); }
}

/* ---------- 8. FAQ: the answer slides open instead of snapping ---------- */
@media (prefers-reduced-motion: no-preference) {
  @supports (interpolate-size: allow-keywords) {
    .faq { interpolate-size: allow-keywords; }
    .faq details::details-content {
      height: 0;
      overflow: clip;
      transition: height 0.4s var(--mo-ease), content-visibility 0.4s allow-discrete;
    }
    .faq details[open]::details-content { height: auto; }
  }
}

/* ---------- 9. Page to page: a soft cross-document transition, nav stays put ---------- */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  .nav { view-transition-name: opt-site-nav; }
  ::view-transition-old(root) { animation: mo-vt-out 0.18s ease-in both; }
  ::view-transition-new(root) { animation: mo-vt-in 0.32s var(--mo-ease) both; }
  ::view-transition-old(opt-site-nav), ::view-transition-new(opt-site-nav) { animation: none; }
  @keyframes mo-vt-out { to { opacity: 0; } }
  @keyframes mo-vt-in { from { opacity: 0; transform: translateY(10px); } }
}

/* ---------- 10. Small things ---------- */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
  .navlink { position: relative; }
  .navlink::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: -0.25em;
    height: 1px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: 0 50%;
    transition: transform 0.35s var(--mo-ease);
  }
  .navlink:hover::after, .navlink:focus-visible::after, .navlink[aria-current="page"]::after { transform: scaleX(1); }
}
