/* ============================================================================
   Keyframes, scroll-reveal rest/end states, CSS 3D and ambient backdrops.

   Reveal contract: every [data-reveal] element sits in its "out" state here and
   is moved to its "in" state by adding .is-in — added by ScrollTrigger, or (if
   GSAP never loads) by the IntersectionObserver fallback in js/main.js. Either
   way, no JS = base.css's reduced-motion block is not enough, so main.js also
   force-reveals on failure. Content is never permanently hidden by CSS alone.
   ========================================================================== */

/* -------------------------------------------------------------- keyframes */

@keyframes marquee {
  from {
    translate: 0 0;
  }
  to {
    translate: -50% 0;
  }
}

@keyframes pulse-dot {
  0% {
    box-shadow: 0 0 0 0 rgb(22 163 74 / 0.55);
  }
  70% {
    box-shadow: 0 0 0 8px rgb(22 163 74 / 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgb(22 163 74 / 0);
  }
}

@keyframes float-y {
  0%,
  100% {
    translate: 0 0;
  }
  50% {
    translate: 0 -14px;
  }
}

@keyframes drift {
  0% {
    translate: 0 0;
    scale: 1;
  }
  33% {
    translate: 4% -6%;
    scale: 1.08;
  }
  66% {
    translate: -5% 4%;
    scale: 0.96;
  }
  100% {
    translate: 0 0;
    scale: 1;
  }
}

@keyframes scan {
  0% {
    translate: 0 -110%;
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  88% {
    opacity: 1;
  }
  100% {
    translate: 0 110%;
    opacity: 0;
  }
}

@keyframes radar-sweep {
  to {
    rotate: 360deg;
  }
}

@keyframes ring-out {
  0% {
    scale: 0.25;
    opacity: 0.65;
  }
  100% {
    scale: 1;
    opacity: 0;
  }
}

@keyframes caret {
  0%,
  49% {
    opacity: 1;
  }
  50%,
  100% {
    opacity: 0;
  }
}

@keyframes bob {
  0%,
  100% {
    translate: 0 0;
  }
  50% {
    translate: 0 8px;
  }
}

/* ----------------------------------------------------------- reveal states */

[data-reveal] {
  opacity: 0;
  translate: 0 28px;
  transition:
    opacity calc(var(--dur-slow) * var(--motion)) var(--ease-out),
    translate calc(var(--dur-slow) * var(--motion)) var(--ease-out),
    scale calc(var(--dur-slow) * var(--motion)) var(--ease-out),
    clip-path calc(var(--dur-slow) * var(--motion)) var(--ease-out);
  will-change: opacity, translate;
}

[data-reveal='fade'] {
  translate: none;
}

[data-reveal='left'] {
  translate: -36px 0;
}

[data-reveal='right'] {
  translate: 36px 0;
}

[data-reveal='scale'] {
  translate: none;
  scale: 0.94;
}

/* Wipe — for headline blocks and images. */
[data-reveal='wipe'] {
  translate: none;
  clip-path: inset(0 0 100% 0);
}

[data-reveal].is-in {
  opacity: 1;
  translate: 0 0;
  scale: 1;
  clip-path: inset(0 0 0 0);
  will-change: auto;
}

/* Staggered children. --i is set inline (or by JS) per child. */
[data-reveal-group] > * {
  opacity: 0;
  translate: 0 24px;
  transition:
    opacity calc(var(--dur-slow) * var(--motion)) var(--ease-out) calc(var(--i, 0) * 70ms),
    translate calc(var(--dur-slow) * var(--motion)) var(--ease-out) calc(var(--i, 0) * 70ms);
}

[data-reveal-group].is-in > * {
  opacity: 1;
  translate: 0 0;
}

/* Hero headline — each word masked, revealed line by line. */
.reveal-line {
  display: block;
  overflow: hidden;
  padding-block-end: 0.08em; /* descenders must not be clipped by the mask */
  margin-block-end: -0.08em;
}

.reveal-line > span {
  display: block;
  translate: 0 108%;
  transition: translate 1s var(--ease-out) calc(var(--i, 0) * 90ms);
}

.is-in .reveal-line > span,
.reveal-line.is-in > span {
  translate: 0 0;
}

/* -------------------------------------------------------------- ambience */

/* Soft color fields behind sections. Purely decorative and inert. */
.glow {
  position: absolute;
  z-index: 0;
  border-radius: 50%;
  filter: blur(90px);
  opacity: 0.5;
  pointer-events: none;
  animation: drift 22s var(--ease-in-out) infinite;
}

.glow--hire {
  background: radial-gradient(circle, rgb(24 169 87 / 0.55), transparent 68%);
}

.glow--earn {
  background: radial-gradient(circle, rgb(109 93 243 / 0.5), transparent 68%);
}

.glow--money {
  background: radial-gradient(circle, rgb(249 115 22 / 0.4), transparent 68%);
}

.glow--blue {
  background: radial-gradient(circle, rgb(42 140 251 / 0.45), transparent 68%);
}

/* The glows are tuned for the dark canvas; on light they only need to tint. */
:root[data-theme='light'] .glow {
  opacity: 0.3;
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme='dark']) .glow {
    opacity: 0.3;
  }
}

/* Fine grain over the dark canvas so the big gradients never band.
   A 4×4 SVG noise tile, inlined — no network request. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.035;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Dot grid — the structural backdrop for the "how it runs" and services scenes. */
.dotgrid {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: radial-gradient(currentColor 1px, transparent 1px);
  background-size: 34px 34px;
  color: var(--line-2);
  opacity: 0.35;
  mask-image: radial-gradient(70% 60% at 50% 45%, #000, transparent 75%);
  -webkit-mask-image: radial-gradient(70% 60% at 50% 45%, #000, transparent 75%);
}

/* --------------------------------------------------------------- CSS 3D */

.scene-3d {
  perspective: 1400px;
  perspective-origin: 50% 45%;
}

.tilt {
  transform-style: preserve-3d;
  transition: transform calc(var(--dur) * var(--motion)) var(--ease-out);
  /* js/tilt.js writes --rx / --ry from pointer position. */
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
}

.tilt__layer {
  transform: translateZ(var(--z, 0px));
}

.float {
  animation: float-y 7s var(--ease-in-out) infinite;
}

/* Flip card — the START ⇄ END QR scene. --flip is scrubbed by ScrollTrigger. */
.flip {
  position: relative;
  transform-style: preserve-3d;
  transform: rotateY(var(--flip, 0deg));
}

.flip__face {
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.flip__face--back {
  position: absolute;
  inset: 0;
  transform: rotateY(180deg);
}

/* --------------------------------------------------------- misc effects */

.scanline {
  position: absolute;
  inset-inline: 8%;
  block-size: 2px;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, transparent, var(--accent-lt), transparent);
  box-shadow: 0 0 18px 2px rgb(var(--accent-rgb) / 0.6);
  animation: scan 2.8s var(--ease-in-out) infinite;
}

.caret {
  display: inline-block;
  inline-size: 2px;
  block-size: 0.95em;
  translate: 0 0.12em;
  background: var(--accent-lt);
  animation: caret 1.05s steps(1) infinite;
}
