/* marketing-motion.css — the homepage's motion layer: the Pursuit Signal Field
   behind the hero, the scroll reveals below it, and the final CTA's field.
   Loaded by index.html only; every other marketing page is untouched.

   WHY A SEPARATE FILE
   index.html is imported from the design canvas (tools/dc-import.mjs) and
   hand-maintained after. Keeping the motion system here, and the page's
   hooks to a few classes, means a future re-import has one file to relink
   and a few attributes to restore rather than 300 lines of inline CSS to
   reconstruct.

   THE PALETTE IS THE SITE'S OWN. --brand* come from brand-tokens.css.
   #072826 is the dark ink the page already uses for every heading and
   primary button; the hero ground is that ink, deepened with color-mix so
   no new hue enters. The RGB triplets below are those same colours split
   into channels for rgba(), nothing else. Easings mirror the app's tokens
   (app/paavya-design-tokens.css: --ease-out, --ease-standard).

   THE FIELD IS ONE 16s CLOCK. Every animation in the hero runs 16s infinite
   on the same timeline, with 0% and 100% identical, so the loop is seamless
   by construction: fragments enter (0–50%), converge and settle (50–72%),
   the decision beacon blooms (56–68%), the feedback loop draws itself and a
   single signal makes one lap (64–92%), everything dissolves (84–100%).
   Transform and opacity only, ~16 animated nodes, blur on four small far
   tiles — nothing that forces layout. */

:root {
  --psf-ink: #072826;
  --psf-ink-rgb: 7, 40, 38;
  --psf-brand-rgb: 0, 100, 93;      /* --brand      #00645D */
  --psf-mid-rgb: 10, 122, 114;      /* --brand-mid  #0A7A72 */
  --psf-light-rgb: 198, 245, 244;   /* --brand-light #C6F5F4 */
  --psf-ease-out: cubic-bezier(.23, 1, .32, 1);
  --psf-ease-standard: cubic-bezier(.4, 0, .2, 1);
  --psf-loop: 16s;
  /* Small on purpose: the card straddles the seam, but must not cover the
     focal point the field resolves to just above it. */
  --proof-overlap: clamp(40px, 5vw, 64px);
}

/* ── Hero ─────────────────────────────────────────────────────────────── */

.psf-hero {
  position: relative;
  overflow: hidden;
  /* border-box so the min-height IS the viewport: the page's default
     content-box sizing would add both paddings on top of 100svh. */
  box-sizing: border-box;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  align-items: center;
  /* Sized so eyebrow-to-trust-line plus both paddings fits inside 100svh on
     a 900px-tall desktop: the hero IS the first viewport, and the band under
     the CTAs (the bottom padding) is where the field converges. */
  padding: clamp(112px, 12vw, 140px) 24px clamp(150px, 18vh, 190px);
  background: var(--psf-ink);
  color: #FFFFFF;
  isolation: isolate;
}

.psf-field {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  contain: layout paint;
  opacity: calc(1 - var(--hero-p, 0) * .55);
  transform: translate3d(0, calc(var(--hero-p, 0) * -22px), 0);
}

.psf-ground {
  position: absolute;
  inset: 0;
  background: var(--psf-ink);
  background:
    radial-gradient(ellipse 60% 50% at 18% 12%, rgba(var(--psf-mid-rgb), .16), transparent 70%),
    radial-gradient(ellipse 50% 45% at 84% 8%, rgba(var(--psf-brand-rgb), .14), transparent 70%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--psf-ink) 78%, #000) 0%,
      var(--psf-ink) 48%,
      color-mix(in srgb, var(--psf-ink) 90%, #000) 100%);
}

/* The perspective grid: a floor receding to a vanishing point above the
   focal area. Masked so it fades in from the horizon and out before the
   hero's bottom edge, and it breathes very slowly rather than moving. */
.psf-grid {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: max(100%, 1600px);
  height: 100%;
  transform: translate3d(calc(-50% + var(--px, 0px) * .4), calc(var(--py, 0px) * .4), 0);
  -webkit-mask-image: linear-gradient(to bottom, transparent 34%, #000 58%, #000 84%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 34%, #000 58%, #000 84%, transparent 100%);
  animation: psf-breathe var(--psf-loop) ease-in-out infinite;
}
.psf-grid line { stroke: rgba(var(--psf-light-rgb), .085); stroke-width: 1; vector-effect: non-scaling-stroke; }
.psf-grid .psf-grid-radial { stroke: rgba(var(--psf-light-rgb), .06); }

/* The stage: everything positioned about the focal point, so one transform
   (pointer offset on desktop, a scale on phones) moves the whole ensemble
   without the tiles, beacon and loop ever drifting apart. */
.psf-stage {
  position: absolute;
  left: 50%;
  bottom: 13%;
  width: 0;
  height: 0;
  transform: translate3d(var(--px, 0px), var(--py, 0px), 0) scale(var(--stage-scale, 1));
  transform-origin: 0 0;
}

.psf-layer { position: absolute; left: 0; top: 0; width: 0; height: 0; }

/* A signal tile: a rounded document-like fragment with two faint lines and,
   on some, a small teal tag — evidence, requirements, buyer signals,
   outcomes — with no literal label to read. */
.psf-tile {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--w);
  height: var(--h);
  margin: calc(var(--h) / -2) 0 0 calc(var(--w) / -2);
  border-radius: 6px;
  border: 1px solid rgba(var(--psf-light-rgb), .34);
  background: rgba(255, 255, 255, .035);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .28);
  opacity: 0;
  transform: translate(var(--sx), var(--sy)) scale(.86);
  will-change: transform, opacity;
  animation: psf-tile var(--psf-loop) var(--psf-ease-out) infinite;
  animation-delay: var(--d, 0s);
}
.psf-tile::before,
.psf-tile::after {
  content: '';
  position: absolute;
  left: 8px;
  height: 2px;
  border-radius: 2px;
  background: rgba(var(--psf-light-rgb), .3);
}
.psf-tile::before { top: 8px; right: 26%; }
.psf-tile::after { top: 15px; right: 46%; }
.psf-tile b {
  position: absolute;
  right: 6px;
  bottom: 6px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--brand-mid);
  box-shadow: 0 0 8px 1px rgba(var(--psf-mid-rgb), .7);
}
.psf-far .psf-tile { filter: blur(1.2px); border-color: rgba(var(--psf-light-rgb), .22); }

@keyframes psf-tile {
  0%        { opacity: 0;               transform: translate(var(--sx), var(--sy)) scale(.86); }
  9%        { opacity: var(--op);       }
  50%       { opacity: var(--op);       transform: translate(var(--mx), var(--my)) scale(.96); }
  62%, 72%  { opacity: var(--op);       transform: translate(var(--ex), var(--ey)) scale(1); }
  84%       { opacity: 0;               transform: translate(var(--ex), var(--ey)) scale(.72); }
  100%      { opacity: 0;               transform: translate(var(--sx), var(--sy)) scale(.86); }
}

/* The decision beacon: a restrained teal bloom at the moment of convergence,
   and a small bright core. It supports the hierarchy; it is not the brand. */
.psf-beacon {
  position: absolute;
  left: -260px;
  top: -260px;
  width: 520px;
  height: 520px;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(var(--psf-mid-rgb), .52) 0%,
    rgba(var(--psf-brand-rgb), .26) 22%,
    rgba(var(--psf-brand-rgb), .08) 46%,
    transparent 68%);
  opacity: 0;
  transform: scale(.8);
  will-change: transform, opacity;
  animation: psf-beacon var(--psf-loop) var(--psf-ease-standard) infinite;
}
.psf-core {
  position: absolute;
  left: -5px;
  top: -5px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--brand-light);
  box-shadow: 0 0 22px 6px rgba(var(--psf-light-rgb), .38);
  opacity: 0;
  transform: scale(0);
  animation: psf-core var(--psf-loop) var(--psf-ease-out) infinite;
}
@keyframes psf-beacon {
  0%, 56%   { opacity: 0;   transform: scale(.8); }
  68%       { opacity: 1;   transform: scale(1); }
  82%       { opacity: .88; transform: scale(1.03); }
  94%, 100% { opacity: 0;   transform: scale(1.1); }
}
@keyframes psf-core {
  0%, 60%   { opacity: 0;  transform: scale(0); }
  66%       { opacity: 1;  transform: scale(1.25); }
  70%       { opacity: 1;  transform: scale(1); }
  92%       { opacity: 1;  transform: scale(1); }
  100%      { opacity: 0;  transform: scale(.6); }
}

/* The feedback loop: a fine ring in perspective around the converged
   fragments, drawn on once the beacon holds, with one signal making a
   single lap — an outcome coming back around to the next decision. */
.psf-loop {
  position: absolute;
  left: -210px;
  top: -210px;
  width: 420px;
  height: 420px;
  overflow: visible;
}
.psf-ring {
  fill: none;
  stroke: rgba(var(--psf-light-rgb), .55);
  stroke-width: 1;
  stroke-dasharray: 943;
  stroke-dashoffset: 943;
  opacity: 0;
  animation: psf-ring var(--psf-loop) var(--psf-ease-standard) infinite;
}
.psf-orbit {
  transform-origin: 0 0;
  opacity: 0;
  animation: psf-orbit var(--psf-loop) var(--psf-ease-standard) infinite;
}
.psf-orbit circle { fill: var(--brand-light); }
@keyframes psf-ring {
  0%, 64%   { stroke-dashoffset: 943; opacity: 0; }
  67%       { opacity: .9; }
  80%       { stroke-dashoffset: 0;   opacity: .9; }
  93%       { stroke-dashoffset: 0;   opacity: .9; }
  100%      { stroke-dashoffset: 0;   opacity: 0; }
}
@keyframes psf-orbit {
  0%, 68%   { transform: rotate(0deg);   opacity: 0; }
  71%       { opacity: 1; }
  91%       { transform: rotate(360deg); opacity: 1; }
  95%, 100% { transform: rotate(360deg); opacity: 0; }
}
@keyframes psf-breathe {
  0%, 100% { opacity: .78; }
  50%      { opacity: 1; }
}

/* The scrim sits between the field and the copy so the fragments passing
   behind the headline never compete with it. */
.psf-scrim {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 58% 52% at 50% 40%, rgba(var(--psf-ink-rgb), .78), rgba(var(--psf-ink-rgb), .35) 55%, transparent 78%);
}

/* ── Hero content ─────────────────────────────────────────────────────── */

.psf-content {
  position: relative;
  z-index: 2;
  max-width: 1040px;
  margin: 0 auto;
  text-align: center;
  transform: translate3d(0, calc(var(--hero-p, 0) * -10px), 0);
}
.psf-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 28px;
  padding: 9px 18px 9px 14px;
  border: 1px solid rgba(var(--psf-light-rgb), .22);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--brand-light);
  background: rgba(var(--psf-light-rgb), .05);
}
.psf-eyebrow::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--brand-light);
  box-shadow: 0 0 10px 2px rgba(var(--psf-light-rgb), .45);
  animation: psf-pulse 3.2s ease-in-out infinite;
}
@keyframes psf-pulse {
  0%, 100% { opacity: .55; transform: scale(.9); }
  50%      { opacity: 1;   transform: scale(1); }
}
.psf-title {
  margin: 0 0 24px;
  font-size: clamp(40px, 4.6vw, 64px);
  font-weight: 600;
  letter-spacing: -.03em;
  line-height: 1.04;
  color: #FFFFFF;
  text-wrap: balance;
}
.psf-title span {
  display: block;
  font-weight: 400;
  color: var(--brand-light);
}
.psf-lede {
  margin: 0 auto 38px;
  max-width: 640px;
  font-size: clamp(17px, 1.8vw, 20px);
  line-height: 1.55;
  color: rgba(255, 255, 255, .8);
  text-wrap: pretty;
}
.psf-ctas {
  display: flex;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
}
/* The site's monochrome pill CTA, inverted for the dark ground: same
   shape, weight, padding and press choreography as .dch3k on the white
   page, so the button reads as the same control in a different light. */
.psf-cta-primary {
  display: inline-block;
  padding: 18px 38px;
  border-radius: 999px;
  background: #FFFFFF;
  color: var(--psf-ink);
  font-size: 17px;
  font-weight: 600;
  box-shadow: 0 12px 30px rgba(0, 0, 0, .28);
}
.psf-cta-primary:hover { background: var(--brand-light); color: var(--psf-ink); transform: translateY(-2px); }
.psf-cta-primary:active, .psf-cta-primary:hover:active { transform: translateY(-2px) scale(.97); }
.psf-cta-secondary {
  display: inline-block;
  padding: 18px 34px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .24);
  background: transparent;
  color: #FFFFFF;
  font-size: 17px;
  font-weight: 700;
}
.psf-cta-secondary:hover { background: rgba(255, 255, 255, .08); color: #FFFFFF; }
.psf-cta-secondary:active, .psf-cta-secondary:hover:active { transform: scale(.97); }
.psf-trust {
  margin: 20px 0 0;
  font-size: 14.5px;
  font-weight: 600;
  color: rgba(255, 255, 255, .6);
}

/* ── The bridge: the product proof straddling the seam, then the loop ── */

.psf-bridge {
  position: relative;
  z-index: 1;
  padding: 0 24px 24px;
  background: #FFFFFF;
}
.psf-proof {
  max-width: 1180px;
  margin: calc(var(--proof-overlap) * -1) auto 0;
}
.psf-proof-card {
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid #EDF0F4;
  background: #FFFFFF;
  box-shadow: 0 40px 90px rgba(var(--psf-ink-rgb), .22), 0 6px 18px rgba(var(--psf-ink-rgb), .08);
}
.psf-proof-card img { display: block; width: 100%; height: auto; }

.psf-stages {
  max-width: 1180px;
  margin: clamp(56px, 7vw, 92px) auto 0;
  text-align: center;
}
.psf-stages-eyebrow {
  margin: 0 0 26px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--brand);
}
.psf-stage-list {
  position: relative;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
}
.psf-stage-list li {
  position: relative;
  flex: 1 1 0;
  padding: 26px 6px 0;
  font-size: 15.5px;
  font-weight: 600;
  color: var(--psf-ink);
}
.psf-stage-list li::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  width: 11px;
  height: 11px;
  margin-left: -5.5px;
  border-radius: 50%;
  background: #FFFFFF;
  border: 1.5px solid var(--brand-mid);
  box-sizing: border-box;
}
.psf-stage-list li:last-child::before { background: var(--brand-mid); box-shadow: 0 0 0 4px var(--brand-tint); }
/* The line through the nodes, and the return arc beneath them: the loop. */
.psf-stage-list::before {
  content: '';
  position: absolute;
  top: 5px;
  left: calc(100% / 14);
  right: calc(100% / 14);
  height: 1px;
  background: #E1E6EC;
}
.psf-stage-list::after {
  content: '';
  position: absolute;
  top: 5px;
  left: calc(100% / 14);
  right: calc(100% / 14);
  height: 30px;
  border: 1px solid rgba(var(--psf-brand-rgb), .32);
  border-top: none;
  border-radius: 0 0 30px 30px;
  clip-path: inset(24px 0 0 0);
  transition: clip-path 1.1s var(--psf-ease-out) .5s;
}
.is-in .psf-stage-list::after,
.psf-stage-list.is-in::after { clip-path: inset(0 0 0 0); }
.psf-stages-note {
  margin: 44px auto 0;
  max-width: 520px;
  font-size: 16px;
  line-height: 1.6;
  color: #5A6474;
  text-wrap: pretty;
}

/* ── Scroll reveals ───────────────────────────────────────────────────── */
/* Only under .js-motion, which marketing-motion.js adds, so a page without
   the script (or with it failing) shows every section at full opacity. The
   class is applied per section by the script right before it is observed. */
.js-motion .rv-section > * {
  opacity: 0;
  transform: translate3d(0, 18px, 0);
  transition: opacity .85s var(--psf-ease-out), transform .85s var(--psf-ease-out);
}
.js-motion .rv-section > :nth-child(2) { transition-delay: .09s; }
.js-motion .rv-section > :nth-child(3) { transition-delay: .18s; }
.js-motion .rv-section > :nth-child(n + 4) { transition-delay: .27s; }
.js-motion .rv-section.is-in > * { opacity: 1; transform: none; }

/* ── The final CTA's field: a calm payoff, not a second hero ──────────── */

.psf-final-field {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 52% 62% at 50% 46%, rgba(var(--psf-light-rgb), .5), rgba(233, 255, 254, .3) 42%, transparent 72%);
}
.psf-final-ring {
  position: absolute;
  left: 50%;
  top: 57%;
  width: 980px;
  height: 300px;
  transform: translate(-50%, -50%);
  fill: none;
  stroke: rgba(var(--psf-brand-rgb), .14);
  stroke-width: 1;
  overflow: visible;
}

/* ── Phones and touch: the field stays, the expensive parts go ────────── */

@media (max-width: 760px) {
  .psf-hero { min-height: 0; padding: 118px 20px 150px; }
  .psf-stage { --stage-scale: .58; bottom: 7%; }
  .psf-far { display: none; }
  .psf-near .psf-tile:nth-child(n + 7) { display: none; }
  .psf-tile { filter: none; box-shadow: none; }
  .psf-scrim { background: radial-gradient(ellipse 80% 60% at 50% 40%, rgba(var(--psf-ink-rgb), .82), transparent 80%); }
  .psf-content { transform: none; }
  .psf-field { opacity: 1; transform: none; }
  .psf-proof-card { border-radius: 10px; }
  .psf-stage-list { flex-wrap: wrap; gap: 10px 0; }
  .psf-stage-list li { flex: 1 1 33%; font-size: 14px; }
  .psf-stage-list::before, .psf-stage-list::after { display: none; }
  .psf-final-ring { width: 130vw; }
}

/* ── Reduced motion: the composed, resolved state — nothing lost ──────── */

@media (prefers-reduced-motion: reduce) {
  .psf-tile, .psf-beacon, .psf-core, .psf-ring, .psf-orbit, .psf-grid, .psf-eyebrow::before {
    animation: none !important;
  }
  .psf-tile { opacity: var(--op); transform: translate(var(--ex), var(--ey)) scale(1); }
  .psf-beacon { opacity: .75; transform: scale(1); }
  .psf-core { opacity: 1; transform: scale(1); }
  .psf-ring { stroke-dashoffset: 0; opacity: .7; }
  .psf-orbit { display: none; }
  .psf-grid { opacity: .9; }
  .psf-field, .psf-content { transform: none; opacity: 1; }
  .js-motion .rv-section > * { opacity: 1; transform: none; transition: none; }
  .psf-stage-list::after { clip-path: none; transition: none; }
}
