/* The framer-motion vocabulary, in CSS.
 *
 * src/motion.js on the React side collapsed 177 motion props into five
 * primitives: rise, fade, slide, delay(i), loop(v). Those five are what this
 * file reimplements - which is why that refactor, done for the prerender, is
 * what makes this migration small.
 *
 * Honest difference: framer-motion uses spring physics, this uses easing
 * curves. The cubic-bezier below is a close visual match for its default
 * spring, but it is a match, not the same maths.
 */

:root {
  --rv-dur: 0.6s;
  --rv-ease: cubic-bezier(0.22, 1, 0.36, 1);   /* ~= framer's default spring */
}

/* Base: hidden until observed. `will-change` only while animating, so we do not
   pin a compositor layer for every element on the page forever. */
[data-rv] {
  opacity: 0;
  transition:
    opacity   var(--rv-dur) var(--rv-ease),
    transform var(--rv-dur) var(--rv-ease);
  transition-delay: calc(var(--rv-d, 0) * 80ms);
}

[data-rv="rise"]  { transform: translateY(30px); }
[data-rv="up"]    { transform: translateY(60px); }
[data-rv="left"]  { transform: translateX(-50px); }
[data-rv="right"] { transform: translateX(50px); }
[data-rv="fade"]  { transform: none; }
[data-rv="scale"] { transform: scale(0.9); }

[data-rv].rv-in {
  opacity: 1;
  transform: none;
}

/* --- the eight always-running loops -------------------------------------- */
@keyframes rv-float  { 0%,100% { transform: translateY(0);      } 50% { transform: translateY(-12px); } }
@keyframes rv-pulse  { 0%,100% { transform: scale(1); opacity:.85 } 50% { transform: scale(1.15); opacity:1 } }
@keyframes rv-bounce { 0%,100% { transform: translateY(0);      } 50% { transform: translateY(8px);  } }

/* The two hero blobs drift on different periods and directions, as they do in
   the React version - identical timing would read as one shape, not two. */
@keyframes rv-blob  { 0%,100% { transform: scale(1) translate(0,0);   } 50% { transform: scale(1.2) translate(30px,-30px); } }
@keyframes rv-blob2 { 0%,100% { transform: scale(1) translate(0,0);   } 50% { transform: scale(1.3) translate(-30px,30px); } }
@keyframes rv-nudge { 0%,100% { transform: translateX(0);             } 50% { transform: translateX(5px); } }
/* Map radar ring: expands and fades, matching the real site's pulse. */
@keyframes rv-radar { 0% { transform: scale(1); opacity: .5; } 100% { transform: scale(2); opacity: 0; } }
.rv-radar { animation: rv-radar 2s ease-out infinite; }

.rv-blob2 { animation: rv-blob2 10s ease-in-out infinite; }
.rv-nudge { display: inline-block; animation: rv-nudge 1.5s ease-in-out infinite; }

.rv-float  { animation: rv-float  4s ease-in-out infinite; }
.rv-pulse  { animation: rv-pulse  2.5s ease-in-out infinite; }
.rv-blob   { animation: rv-blob   5s ease-in-out infinite; }
.rv-bounce { animation: rv-bounce 2s ease-in-out infinite; }

/* Scroll progress bar. scaleX driven from JS, one transform write per frame. */
#rv-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 4px;
  background: #FFD700; z-index: 50;
  transform: scaleX(0); transform-origin: left;
}

/* --- accessibility ------------------------------------------------------- *
 * On the React side this was a JS branch that had to be evaluated before any
 * motion prop was built. Here it is one media query, and it also stops the
 * infinite loops - which are real battery drain on a mid-range Android. */
@media (prefers-reduced-motion: reduce) {
  [data-rv] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .rv-float, .rv-pulse, .rv-blob, .rv-bounce { animation: none !important; }
  html { scroll-behavior: auto !important; }
}

/* No-JS: never leave the page invisible because a script failed to run.
   The React version had the same hazard and solved it in the prerender. */
.no-js [data-rv] { opacity: 1 !important; transform: none !important; }
