/* orb-hero-rise: a hero that assembles on load. Pill, lockup and buttons each scale up out of nothing on their
   OWN cubic-bezier (all late-starting, 100 ms apart), the looping background fades in behind them, the nav drops in
   on a spring. CSS does the whole entrance; part.js only draws the stand-in ripple canvas, adds replay() and turns a
   data-ohr-spring="<duration> <bounce>" knob into a linear() curve.

   Mark-up hooks (any element, any layout):
     [data-ohr-rise="pill" | "lockup" | "cta"]   scale up from --ohr-from + fade from .001
     [data-ohr-fade]                             the background layer: opacity .001 -> 1
     [data-ohr-drop]                             the nav: y -70 -> 0 + fade on a spring
   Every number is a custom property; set it on the element (or any ancestor) to retune one piece. */

:root {
  /* motion's duration spring {duration: 1.4, bounce: .2} sampled every 50 ms (part.js OrbHeroRise.spring(1.4, .2));
     1.5% overshoot at 816 ms, matches the live page's WAAPI curve within .004 */
  --ohr-spring: linear(0, 0.0437, 0.1463, 0.2761, 0.4116, 0.5397, 0.6531, 0.7487, 0.826, 0.8861, 0.9311, 0.9636,
    0.9859, 1.0003, 1.009, 1.0134, 1.015, 1.0147, 1.0134, 1.0115, 1.0095, 1.0075, 1.0057, 1.0042, 1.0029, 1.002,
    1.0012, 1.0008, 1);
  --ohr-start-opacity: .001;
}
@supports not (animation-timing-function: linear(0, 1)) {
  :root { --ohr-spring: cubic-bezier(.3, 1.12, .5, 1); }
}

/* ---------- the three scale-ups: measured from the Framer appear config ---------- */
[data-ohr-rise] {
  transform-origin: 50% 50%;
  animation: ohr-rise var(--ohr-dur, 1.2s) var(--ohr-ease, ease) var(--ohr-delay, 0s) both;
}
[data-ohr-rise="pill"]   { --ohr-from: .5; --ohr-dur: 1.2s; --ohr-ease: cubic-bezier(.72, .21, .36, 1.01); --ohr-delay: .1s; }
[data-ohr-rise="cta"]    { --ohr-from: .5; --ohr-dur: 1.4s; --ohr-ease: cubic-bezier(.53, .27, .4, 1);    --ohr-delay: .2s; }
[data-ohr-rise="lockup"] { --ohr-from: .7; --ohr-dur: 1.2s; --ohr-ease: cubic-bezier(.67, .33, .23, 1.02); --ohr-delay: .3s; }
@keyframes ohr-rise {
  from { opacity: var(--ohr-start-opacity); scale: var(--ohr-from, .5); }
}

/* ---------- background: 1 s linear fade at .6 s ---------- */
[data-ohr-fade] {
  animation: ohr-fade var(--ohr-fade-dur, 1s) linear var(--ohr-fade-delay, .6s) both;
}
@keyframes ohr-fade {
  from { opacity: var(--ohr-start-opacity); }
}

/* ---------- nav: y -70 -> 0 on the spring, 1.4 s at .6 s (opacity rides the same curve) ---------- */
[data-ohr-drop] {
  animation: ohr-drop var(--ohr-drop-dur, 1.4s) var(--ohr-spring) var(--ohr-drop-delay, .6s) both;
}
@keyframes ohr-drop {
  from { opacity: var(--ohr-start-opacity); translate: 0 var(--ohr-drop-y, -70px); }
}

/* ---------- the stage: a dark looping picture turned to pale chrome ----------
   The source plays a DARK purple orb-in-water video and makes it white with one filter chain, then a white radial
   vignette eats the edges. Put any dark <video>, <canvas> or image inside .ohr__bg and it gets the same treatment. */
.ohr {
  --ohr-page: #f5f5f5;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--ohr-page);
}
.ohr__bg {
  position: absolute;
  inset: var(--ohr-bg-inset, -238px -176px -47px);   /* the source's oversized video box (1793 x 1185 at 1440 x 900) */
  z-index: 0;
  filter: var(--ohr-bg-filter, brightness(.69) grayscale(1) invert(1));
  pointer-events: none;
}
.ohr__bg > canvas, .ohr__bg > video, .ohr__bg > img {
  display: block; width: 100%; height: 100%; object-fit: cover;
}
.ohr__bg > canvas { filter: blur(var(--ohr-ripple-soft, 2.5px)); }
.ohr__vignette {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(50% 50% at 50% 50%, rgba(255, 255, 255, 0) 0%, var(--ohr-vignette, #fff) 100%);
}
.ohr__content { position: relative; z-index: 2; }

@media (prefers-reduced-motion: reduce) {
  [data-ohr-rise], [data-ohr-fade], [data-ohr-drop] { animation: none; }
}
