/* =============================================================================
   ANIMATIONS.CSS
   -----------------------------------------------------------------------------
   Reverse-engineered motion system. The source's signature effects:
     1. Blur-reveal      — elements fade up while un-blurring on scroll-in.
     2. Split-text word  — headings reveal word-by-word, staggered, with blur.
     3. Gradient slide   — a light sweep animates across gradient text.
     4. Shimmer / sheen  — swept highlight on buttons & cards.
     5. Spin             — loaders.
     6. Float / parallax — gentle idle motion on hero art.

   Scroll triggering is handled in script.js via IntersectionObserver, which
   toggles the `.is-inview` class. These rules define the before/after states.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   KEYFRAMES
   --------------------------------------------------------------------------- */
@keyframes ds-reset-opacity { from { opacity: 0; } to { opacity: 1; } }
@keyframes ds-reset-blur    { from { filter: blur(6px); } to { filter: blur(0); } }

@keyframes ds-spin { to { transform: rotate(360deg); } }

@keyframes ds-gradient-slide {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

@keyframes ds-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-12px); }
}

@keyframes ds-pulse-glow {
  0%, 100% { box-shadow: 0 0 0 0 rgb(207 123 79 / 0.4); }
  50%      { box-shadow: 0 0 0 12px rgb(207 123 79 / 0); }
}

/* Cada .ds-marquee-inner desliza 100% da própria largura: a cópia sai pela
   esquerda exatamente quando a seguinte assume seu lugar — loop sem emenda. */
@keyframes ds-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}

/* ---------------------------------------------------------------------------
   1. BLUR-REVEAL  (scroll-in)
   Apply .ds-reveal to any element. It starts hidden+blurred+shifted; when
   script.js adds .is-inview it animates to its resting state.
   --------------------------------------------------------------------------- */
.ds-reveal {
  opacity: 0;
  filter: blur(6px);
  transform: translateY(24px);
  transition:
    opacity var(--dur-reveal) var(--ease-out),
    filter var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out);
  will-change: opacity, filter, transform;
}
.ds-reveal.is-inview {
  opacity: 1;
  filter: blur(0);
  transform: none;
}
/* Direction + distance modifiers */
.ds-reveal[data-from="left"]  { transform: translateX(-32px); }
.ds-reveal[data-from="right"] { transform: translateX(32px); }
.ds-reveal[data-from="scale"] { transform: scale(0.94); }
.ds-reveal.is-inview[data-from] { transform: none; }

/* Staggered children — set --i on each child (script.js can auto-index) */
.ds-reveal-group > * {
  opacity: 0;
  filter: blur(6px);
  transform: translateY(24px);
  transition:
    opacity 0.8s var(--ease-out),
    filter 0.8s var(--ease-out),
    transform 0.8s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 80ms);
}
.ds-reveal-group.is-inview > * { opacity: 1; filter: blur(0); transform: none; }

/* ---------------------------------------------------------------------------
   2. SPLIT-TEXT (word reveal)
   Wrap words in <span class="ds-word"><span>word</span></span>. script.js
   splits text automatically for elements with .ds-split.
   --------------------------------------------------------------------------- */
.ds-split { --stagger: 45ms; }
.ds-word { display: inline-block; overflow: hidden; vertical-align: top; }
.ds-word > span {
  display: inline-block;
  opacity: 0;
  filter: blur(4px);
  transform: translateY(0.9em);
  transition:
    opacity 0.6s var(--ease-out),
    filter 0.6s var(--ease-out),
    transform 0.6s var(--ease-out);
  transition-delay: calc(var(--wi, 0) * var(--stagger));
}
.ds-split.is-inview .ds-word > span { opacity: 1; filter: blur(0); transform: none; }

/* ---------------------------------------------------------------------------
   3. GRADIENT SLIDE  (animated text sweep)
   --------------------------------------------------------------------------- */
.ds-text-gradient.is-animated {
  animation: ds-gradient-slide 6s var(--ease-linear) infinite;
}

/* ---------------------------------------------------------------------------
   4. SHIMMER / SHEEN  (idle highlight sweep on a surface)
   --------------------------------------------------------------------------- */
.ds-shimmer { position: relative; overflow: hidden; }
.ds-shimmer::after {
  content: "";
  position: absolute; inset: 0;
  background: var(--gradient-sheen);
  background-size: 250% 100%;
  transform: translateX(-100%);
  animation: ds-shimmer-move 3.5s var(--ease-out) infinite;
  pointer-events: none;
}
@keyframes ds-shimmer-move {
  0%   { transform: translateX(-100%); }
  60%, 100% { transform: translateX(100%); }
}

/* ---------------------------------------------------------------------------
   5. SPINNER
   --------------------------------------------------------------------------- */
.ds-spinner {
  width: 1.5rem; height: 1.5rem;
  border-radius: 50%;
  border: 2.5px solid var(--ink-a20);
  border-top-color: var(--brand-accent);
  animation: ds-spin 0.7s linear infinite;
}

/* ---------------------------------------------------------------------------
   6. FLOAT / PARALLAX
   .ds-float = gentle idle bob. Parallax offset is driven by script.js via the
   --parallax custom property on [data-parallax].
   --------------------------------------------------------------------------- */
.ds-float { animation: ds-float 6s var(--ease-in-out) infinite; }
.ds-float--slow { animation-duration: 9s; }
[data-parallax] { transform: translate3d(0, var(--parallax, 0), 0); will-change: transform; }

/* ---------------------------------------------------------------------------
   7. AURA DRIFT — the ambient orbs (layout.css) breathe very slowly, so the
   light behind the glass is never perfectly static. Long duration + tiny
   amplitude on purpose: it should be felt, not watched.
   --------------------------------------------------------------------------- */
@keyframes ds-aura-drift {
  0%, 100% { translate: -50% -50%;             scale: 1; }
  50%      { translate: calc(-50% + 4%) -46%;  scale: 1.08; }
}
@media (prefers-reduced-motion: no-preference) {
  .ds-aura { animation: ds-aura-drift 24s var(--ease-in-out) infinite; }
  .ds-aura:nth-of-type(2) { animation-duration: 31s; animation-delay: -8s; }
}

/* ---------------------------------------------------------------------------
   MARQUEE  (infinite logo / word strip). Duplicate the content twice inside.
   --------------------------------------------------------------------------- */
.ds-marquee { display: flex; overflow: hidden; width: 100%; }
.ds-marquee-inner {
  display: flex;
  align-items: center;
  justify-content: space-around;
  gap: var(--space-6);
  flex: 0 0 auto;
  /* Nunca menor que a faixa visível: com poucos itens as cópias continuam
     encostadas uma na outra, sem buraco entre elas. */
  min-width: 100%;
  padding-right: var(--space-6);
  animation: ds-marquee 24s linear infinite;
  will-change: transform;
}
.ds-marquee:hover .ds-marquee-inner { animation-play-state: paused; }

/* ---------------------------------------------------------------------------
   HOVER / MICRO-INTERACTION UTILITIES
   --------------------------------------------------------------------------- */
.ds-hover-lift   { transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base); }
.ds-hover-lift:hover { transform: translateY(-4px); box-shadow: var(--shadow-elevated); }
.ds-hover-grow   { transition: transform var(--dur-base) var(--ease-out); }
.ds-hover-grow:hover { transform: scale(1.03); }
.ds-pulse        { animation: ds-pulse-glow 2s var(--ease-out) infinite; }

/* Sticky / pinned helper.
   The offset is a token because the right value depends on what floats above
   the page: with a sticky navbar, a column pinned at the default --space-8
   comes to rest UNDER it. Pages with a fixed/sticky header should set
   --sticky-top to the header height plus breathing room.
   Turned off in the single-column layout — see responsive.css. */
.ds-sticky { position: sticky; top: var(--sticky-top, var(--space-8)); }
