/* ==========================================================================
   ALT PLACAS — animations.css
   Pre-animation states, keyframes and the reduced-motion contract.

   Every element GSAP animates in must start from a CSS state so there is no
   flash of un-animated content before the timeline attaches. `js-on` is added
   to <html> by an inline head script, so these states only apply when
   JavaScript is actually going to run.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. PRE-ANIMATION STATES
   -------------------------------------------------------------------------- */
.js-on [data-anim="up"]     { opacity: 0; transform: translateY(38px); }
.js-on [data-anim="fade"]   { opacity: 0; }
.js-on [data-anim="scale"]  { opacity: 0; transform: scale(0.94); }
.js-on [data-anim="left"]   { opacity: 0; transform: translateX(-38px); }
.js-on [data-anim="right"]  { opacity: 0; transform: translateX(38px); }
.js-on [data-anim="clip"]   { clip-path: inset(0 0 100% 0); }
.js-on [data-anim-child]    { opacity: 0; transform: translateY(26px); }
.js-on [data-anim="rule"]   { transform: scaleX(0); transform-origin: left center; }

/* Elements already handled by their own timeline keep their own start state. */
.js-on [data-anim].is-in,
.js-on [data-anim-child].is-in { opacity: 1; transform: none; }

/* --------------------------------------------------------------------------
   2. WORD REVEAL
   Each word sits in an overflow-hidden wrap; the inner span is lifted from
   below. Applied to hero and to every large section headline.
   -------------------------------------------------------------------------- */
.word-wrap {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: 0.06em;   /* room for descenders inside the clip */
}
.word-inner { display: inline-block; will-change: transform; }
.js-on .split-ready .word-inner { transform: translateY(105%); }

/* Line-level variant used by SplitText */
.line-wrap { overflow: hidden; display: block; padding-bottom: 0.04em; }

/* --------------------------------------------------------------------------
   3. KEYFRAMES
   -------------------------------------------------------------------------- */
@keyframes cinematic {
  from { transform: scale(1.14); filter: blur(8px); opacity: 0; }
  to   { transform: scale(1);    filter: blur(0);   opacity: 1; }
}
.animate-cinematic { animation: cinematic 2.4s var(--ease) both; }

@keyframes slideUp {
  from { opacity: 0; transform: translateY(28px); }
  to   { opacity: 1; transform: translateY(0); }
}
.animate-slide-up { animation: slideUp 1s var(--ease) both; }

@keyframes shimmer {
  0%   { transform: translateX(-120%); }
  100% { transform: translateX(120%); }
}
.animate-shimmer-effect::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(105deg, transparent 35%, rgba(255,255,255,0.28) 50%, transparent 65%);
  animation: shimmer 3.4s var(--ease) infinite;
  pointer-events: none;
}

@keyframes scrollHint {
  0%, 100% { transform: translateY(0);    opacity: 0.35; }
  50%      { transform: translateY(7px);  opacity: 1; }
}
.scroll-hint { animation: scrollHint 2.2s ease-in-out infinite; }

@keyframes laserSweep {
  0%   { transform: translateY(-100%); opacity: 0; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { transform: translateY(1100%); opacity: 0; }
}
/* A single green line that sweeps a photo like a laser level being set out. */
.laser-sweep::after {
  content: '';
  position: absolute; left: 0; right: 0; top: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--laser), transparent);
  box-shadow: 0 0 12px 1px rgba(74, 222, 128, 0.55);
  animation: laserSweep 6s var(--ease) infinite;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   4. IN-VIEW HELPERS (IntersectionObserver fallback path)
   -------------------------------------------------------------------------- */
.animate-on-scroll { opacity: 0; transform: translateY(26px); transition: opacity 0.9s var(--ease), transform 0.9s var(--ease); }
.animate-on-scroll.animate { opacity: 1; transform: none; }

/* --------------------------------------------------------------------------
   5. REDUCED MOTION
   Everything resolves to its final state; nothing loops.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .js-on [data-anim],
  .js-on [data-anim-child],
  .js-on .split-ready .word-inner {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  .animate-cinematic,
  .animate-slide-up,
  .animate-shimmer-effect::before,
  .scroll-hint,
  .laser-sweep::after { animation: none !important; }
  .animate-on-scroll { opacity: 1; transform: none; }
  .media img, .media video, .card-img, .svc__media img, .method__media img { transition: none !important; }
  * { scroll-behavior: auto !important; }
}
