/* ============================================================
   animations.css — Text & Element Animation Utility Classes
   Usage: add class to any element, e.g. <p class="anim fade-right">
   To replay: remove and re-add the class via JS
   ============================================================ */

/* ------------------------------------------------------------
   1. DEFAULT SETTINGS (override with utility classes below)
   ------------------------------------------------------------ */
.anim,
.anim-scroll {
    animation-duration: 0.6s;
    animation-timing-function: ease-out;
    animation-fill-mode: both;
    animation-play-state: running;
    animation-name: var(--anim-name);
}

/* Scroll-triggered: keep at frame 0 until JS adds .is-visible */
.anim-scroll:not(.is-visible) {
    animation-play-state: paused;
}



/* ============================================================
   2. KEYFRAMES
   ============================================================ */

/* Fade directions */
@keyframes fadeRight {
    from { opacity: 0; transform: translateX(40px); }
    to   { opacity: 1; transform: translateX(0); }
}

@keyframes fadeLeft {
    from { opacity: 0; transform: translateX(-40px); }
    to   { opacity: 1; transform: translateX(0); }
}

@keyframes fadeUp {
    from { opacity: 0; transform: translateY(30px); }
    to   { opacity: 1; transform: translateY(0); }
}

@keyframes fadeDown {
    from { opacity: 0; transform: translateY(-30px); }
    to   { opacity: 1; transform: translateY(0); }
}

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

/* Zoom */
@keyframes zoomIn {
    from { opacity: 0; transform: scale(0.7); }
    to   { opacity: 1; transform: scale(1); }
}

@keyframes zoomOut {
    from { opacity: 0; transform: scale(1.3); }
    to   { opacity: 1; transform: scale(1); }
}

/* Flip */
@keyframes flipX {
    from { opacity: 0; transform: perspective(400px) rotateX(90deg); }
    to   { opacity: 1; transform: perspective(400px) rotateX(0deg); }
}

@keyframes flipY {
    from { opacity: 0; transform: perspective(400px) rotateY(90deg); }
    to   { opacity: 1; transform: perspective(400px) rotateY(0deg); }
}

/* Slide (no fade) */
@keyframes slideRight {
    from { transform: translateX(60px); }
    to   { transform: translateX(0); }
}

@keyframes slideLeft {
    from { transform: translateX(-60px); }
    to   { transform: translateX(0); }
}

@keyframes slideUp {
    from { transform: translateY(40px); }
    to   { transform: translateY(0); }
}

@keyframes slideDown {
    from { transform: translateY(-40px); }
    to   { transform: translateY(0); }
}

/* Blur */
@keyframes blurIn {
    from { opacity: 0; filter: blur(12px); }
    to   { opacity: 1; filter: blur(0); }
}

@keyframes slideBlurUp {
    from { opacity: 0; transform: translateY(20px); filter: blur(6px); }
    to   { opacity: 1; transform: translateY(0);    filter: blur(0); }
}

@keyframes slideBlurRight {
    from { opacity: 0; transform: translateX(20px); filter: blur(6px); }
    to   { opacity: 1; transform: translateX(0);    filter: blur(0); }
}

/* Bounce */
@keyframes bounceIn {
    0%   { opacity: 0; transform: scale(0.4); }
    55%  { opacity: 1; transform: scale(1.1); }
    75%  { transform: scale(0.95); }
    100% { transform: scale(1); }
}

@keyframes bounceUp {
    0%   { opacity: 0; transform: translateY(40px); }
    55%  { opacity: 1; transform: translateY(-10px); }
    75%  { transform: translateY(4px); }
    100% { transform: translateY(0); }
}

/* Elastic */
@keyframes elasticLeft {
    0%   { opacity: 0; transform: translateX(-60px) scaleX(1.15); }
    60%  { opacity: 1; transform: translateX(6px) scaleX(0.97); }
    80%  { transform: translateX(-3px) scaleX(1.01); }
    100% { transform: translateX(0) scaleX(1); }
}

@keyframes elasticRight {
    0%   { opacity: 0; transform: translateX(60px) scaleX(1.15); }
    60%  { opacity: 1; transform: translateX(-6px) scaleX(0.97); }
    80%  { transform: translateX(3px) scaleX(1.01); }
    100% { transform: translateX(0) scaleX(1); }
}

/* Rotate */
@keyframes rotateIn {
    from { opacity: 0; transform: rotate(-180deg) scale(0.6); }
    to   { opacity: 1; transform: rotate(0deg) scale(1); }
}

@keyframes rotateFadeIn {
    from { opacity: 0; transform: rotate(-15deg); }
    to   { opacity: 1; transform: rotate(0deg); }
}

/* Typewriter effect — works best on monospace text */
@keyframes typewriter {
    from { clip-path: inset(0 100% 0 0); }
    to   { clip-path: inset(0 0% 0 0); }
}

/* Shimmer / highlight sweep */
@keyframes shimmer {
    0%   { background-position: -200% center; }
    100% { background-position: 200% center; }
}

/* Pulse glow (for attention) */
@keyframes pulseGlow {
    0%, 100% { opacity: 1; }
    50%       { opacity: 0.5; }
}


/* ============================================================
   3. ANIMATION CLASSES
   ============================================================ */

/* Animation-name is delivered via --anim-name so both .anim and .anim-scroll work */

/* --- Fade --- */
.fade-right   { --anim-name: fadeRight; }
.fade-left    { --anim-name: fadeLeft; }
.fade-up      { --anim-name: fadeUp; }
.fade-down    { --anim-name: fadeDown; }
.fade-in      { --anim-name: fadeIn; }

/* --- Zoom --- */
.zoom-in      { --anim-name: zoomIn; }
.zoom-out     { --anim-name: zoomOut; }

/* --- Flip --- */
.flip-x       { --anim-name: flipX; }
.flip-y       { --anim-name: flipY; }

/* --- Slide (no opacity change) --- */
.slide-right  { --anim-name: slideRight; }
.slide-left   { --anim-name: slideLeft; }
.slide-up     { --anim-name: slideUp; }
.slide-down   { --anim-name: slideDown; }

/* --- Blur --- */
.blur-in         { --anim-name: blurIn; }
.slide-blur-up   { --anim-name: slideBlurUp; }
.slide-blur-right{ --anim-name: slideBlurRight; }

/* --- Bounce --- */
.bounce-in    { --anim-name: bounceIn; }
.bounce-up    { --anim-name: bounceUp; }

/* --- Elastic --- */
.elastic-left  { --anim-name: elasticLeft; }
.elastic-right { --anim-name: elasticRight; }

/* --- Rotate --- */
.rotate-in     { --anim-name: rotateIn; }
.rotate-fade   { --anim-name: rotateFadeIn; }

/* --- Special --- */
.anim.typewriter,
.anim-scroll.typewriter {
    --anim-name: typewriter;
    display: inline-block;
    white-space: nowrap;
    overflow: hidden;
}

.anim.shimmer,
.anim-scroll.shimmer {
    --anim-name: shimmer;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
    background: linear-gradient(90deg, currentColor 25%, rgba(255,255,255,0.6) 50%, currentColor 75%);
    background-size: 200% auto;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.anim.pulse,
.anim-scroll.pulse {
    --anim-name: pulseGlow;
    animation-iteration-count: infinite;
    animation-timing-function: ease-in-out;
}


/* ============================================================
   4. DURATION MODIFIERS
   ============================================================ */
.dur-300  { animation-duration: 0.3s; }
.dur-500  { animation-duration: 0.5s; }
.dur-700  { animation-duration: 0.7s; }
.dur-1000 { animation-duration: 1s; }
.dur-1500 { animation-duration: 1.5s; }
.dur-2000 { animation-duration: 2s; }


/* ============================================================
   5. DELAY MODIFIERS
   ============================================================ */
.delay-100  { animation-delay: 0.1s; }
.delay-200  { animation-delay: 0.2s; }
.delay-300  { animation-delay: 0.3s; }
.delay-400  { animation-delay: 0.4s; }
.delay-500  { animation-delay: 0.5s; }
.delay-700  { animation-delay: 0.7s; }
.delay-1000 { animation-delay: 1s; }
.delay-1500 { animation-delay: 1.5s; }


/* ============================================================
   6. EASING MODIFIERS
   ============================================================ */
.ease-in     { animation-timing-function: ease-in; }
.ease-out    { animation-timing-function: ease-out; }
.ease-in-out { animation-timing-function: ease-in-out; }
.ease-linear { animation-timing-function: linear; }
.ease-spring { animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); }
.ease-smooth { animation-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1); }
.ease-snappy { animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); }


/* ============================================================
   7. REPEAT MODIFIERS
   ============================================================ */
.repeat-2       { animation-iteration-count: 2; }
.repeat-3       { animation-iteration-count: 3; }
.repeat-forever { animation-iteration-count: infinite; }


/* ============================================================
   8. SCROLL-TRIGGERED (Intersection Observer)
   .anim-scroll elements are paused at frame 0 until JS adds
   the .is-visible class (see animation-observer.js).
   ============================================================ */


/* ============================================================
   README — HOW TO USE
   ============================================================

   BASIC USAGE
   -----------
   <p class="anim fade-right">Hello world</p>

   WITH DURATION + DELAY
   ---------------------
   <p class="anim fade-up dur-1000 delay-300">Hello world</p>

   WITH EASING
   -----------
   <p class="anim zoom-in ease-spring">Hello world</p>

   STAGGER CHILDREN (add increasing delays)
   -----------------------------------------
   <h1 class="anim fade-up delay-100">Title</h1>
   <p  class="anim fade-up delay-300">Subtitle</p>
   <a  class="anim fade-up delay-500">Button</a>

   SCROLL TRIGGER (Intersection Observer)
   ----------------------------------------
   Add class "anim-scroll" + your animation class:
   <p class="anim fade-right anim-scroll">Appears on scroll</p>

   Then add this JS once on the page:

   const observer = new IntersectionObserver((entries) => {
     entries.forEach(entry => {
       if (entry.isIntersecting) {
         entry.target.classList.add('visible');
         observer.unobserve(entry.target); // animate once
       }
     });
   }, { threshold: 0.15 });

   document.querySelectorAll('.anim-scroll').forEach(el => {
     observer.observe(el);
   });

   REPLAY VIA JS
   -------------
   function replay(el) {
     el.classList.remove('anim');
     void el.offsetWidth; // force reflow
     el.classList.add('anim');
   }

   ============================================================ */