/* ============================================================
   Animations — keyframes + idle-state setup for JS-driven reveals.
   GSAP handles most timed animations imperatively;
   this file holds keyframes and pre-animation states.
   ============================================================ */

/* ----------------------------------------------------------------
   Pre-animation states (set when .js class is present on <html>)
   GSAP / IntersectionObserver flips these to revealed.
   ---------------------------------------------------------------- */

/* Headline / paragraph fade-up.
   No will-change here — there can be 30+ [data-reveal] elements per
   page; promoting each to its own GPU layer permanently wastes
   memory. GSAP composites the transform+opacity transitions just
   fine without the hint. */
.js [data-reveal="fade-up"],
.js [data-reveal=""],
.js [data-reveal] {
  opacity: 0;
  transform: translateY(28px);
}

/* Side fade */
.js [data-reveal="fade-left"] {
  opacity: 0;
  transform: translateX(-28px);
}

.js [data-reveal="fade-right"] {
  opacity: 0;
  transform: translateX(28px);
}

/* Pure fade */
.js [data-reveal="fade"] {
  opacity: 0;
  transform: none;
}

/* Children of a stagger group start hidden too, so there is no flash
   of the grid before GSAP takes over. Released the same three ways:
   GSAP inline styles, reduced motion, the paint failsafe. */
.js [data-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(26px) scale(0.97);
}
.js [data-reveal-stagger].is-revealed > * { opacity: 1; transform: none; }

/* Once revealed, GSAP sets these inline; clean state */
.js [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Reduced motion — render final state immediately */
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal],
  .js [data-reveal-stagger] > * {
    opacity: 1 !important;
    transform: none !important;
    will-change: auto !important;
  }
  .hero__tagline { opacity: 1 !important; transform: none !important; }
  .hero__cue     { opacity: 1 !important; }
  .hero-logo     { opacity: 0 !important; }
  .page-home .site-header .cochin-now,
  .page-home .site-header .lang-select,
  .page-home .site-header .menu-toggle { opacity: 1 !important; }
  .site-header { background: var(--color-overlay); backdrop-filter: blur(14px); }
  body.is-locked { overflow: auto !important; height: auto !important; }
  .hero-video.is-loaded { opacity: 1 !important; }
}

/* ----------------------------------------------------------------
   Keyframes — used by CSS-only loops (scroll cue, etc.)
   Most timed motion lives in GSAP timelines.
   ---------------------------------------------------------------- */

@keyframes pulse {
  0%, 100% { opacity: 0.6; }
  50%      { opacity: 1; }
}

@keyframes drift {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}

/* ----------------------------------------------------------------
   Low-perf tier — strips the most expensive GPU effects on weak
   devices and slow connections (set via data-perf="low" by an inline
   script in <head>). Everyone with a modern device sees the full
   high-fidelity version; only the constrained users get the lighter
   pass — no design quality sacrificed at the top end.
   ---------------------------------------------------------------- */

html[data-perf="low"] .site-header.is-visible {
  /* Drop backdrop-filter — replace with opaque dark fill */
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  background: rgba(14, 22, 32, 0.94);
}

html[data-perf="low"] .menu-overlay {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  background: rgba(14, 22, 32, 0.98);
}

html[data-perf="low"] .hero-video {
  /* Single filter operation instead of three — much lighter to
     composite on weak GPUs. */
  filter: brightness(1.4);
}

html[data-perf="low"] .hero__tagline {
  /* Single shadow layer instead of three — same readability, ~3x
     cheaper to paint. */
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.85);
}

html[data-perf="low"] .principle:hover {
  /* No translateY lift on hover — eliminates a layer promotion */
  transform: none;
}

/* ----------------------------------------------------------------
   Page transition — internal pages
   Light fade-in on first paint so the static header logo doesn't
   appear to "pop" before fonts load.
   ---------------------------------------------------------------- */

body:not(.page-home) {
  animation: pageEnter 600ms var(--ease-out) both;
}

@keyframes pageEnter {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  body:not(.page-home) { animation: none; }
}

/* Failsafe — see the paintSafety timer in main.js. If GSAP and Lenis have
   not arrived within 2s (slow network, blocked CDN, offline third party),
   the reveal elements are released so the page is READABLE without them.
   Animation is a enhancement; the content is the product. */
.reveals-bypass [data-reveal],
.reveals-bypass [data-reveal-stagger] > * {
  opacity: 1 !important;
  transform: none !important;
}
