@charset "UTF-8";
/* ==========================================================================
   CAPE ANIMATION LIBRARY  v1.0
   --------------------------------------------------------------------------
   A reusable, dependency-free motion library. No JavaScript, no frameworks.
   Drop this file into any project and use the hooks below.

   Entrance keyframes are a curated subset of Animate.css
   (MIT, © Daniel Eden — http://daneden.me/animate); class names match the
   original, so the full library is a drop-in upgrade if you ever need more.

   ---------------------------------------------------------------- CONTENTS
     1. Tokens
     2. Entrance animations   .animated .fadeInUp .delay-2
     3. Scroll reveals        data-reveal="up"  data-reveal-delay="2"
     4. Image reveals         data-reveal-img="scale|wipe"
     5. Parallax              data-parallax="slow|medium|fast"
     6. Ken Burns             data-kenburns="in|out"
     7. Hover / micro         .hover-lift .hover-zoom .hover-underline
     8. Reduced-motion kill switch

   -------------------------------------------------------------- HOW IT RUNS
   Scroll effects use native CSS scroll-driven animations
   (animation-timeline: view() / scroll(root)). Everything is wrapped in
   @supports, so a browser without that support simply shows the content
   normally — nothing breaks, nothing is ever stuck invisible.

   SAFE BY CONSTRUCTION: scroll effects deliberately set no animation-fill-mode.
   The element's resting state is its visible state, so if an animation never
   runs the content is still there. Never add fill-mode: both to section 3 or 4.
   ========================================================================== */

/* ==========================================================================
   1. TOKENS — retune the whole library from here
   ========================================================================== */
:root {
  --anim-duration: 0.9s;          /* entrance + reveal length */
  --anim-duration-fast: 0.6s;
  --anim-duration-slow: 1.4s;
  --anim-ease: cubic-bezier(0.22, 0.61, 0.36, 1);  /* gentle deceleration */
  --anim-step: 0.12s;             /* stagger between delay-1, -2, -3 … */
  --anim-distance: 24px;          /* travel for fadeInUp / Down */
  --anim-distance-x: 30px;        /* travel for fadeInLeft / Right */

  /* Scroll-reveal trigger window: starts as the element enters the viewport,
     finishes before it reaches the middle. Retune to taste. */
  --anim-range: entry 5% entry 75%;
}

/* ==========================================================================
   2. ENTRANCE ANIMATIONS — run once on page load
   Usage: <div class="animated fadeInUp delay-2">
   ========================================================================== */
.animated {
  animation-duration: var(--anim-duration);
  animation-timing-function: var(--anim-ease);
  animation-fill-mode: both;
}
.animated.fast { animation-duration: var(--anim-duration-fast); }
.animated.slow { animation-duration: var(--anim-duration-slow); }

.animated.delay-1 { animation-delay: calc(var(--anim-step) * 1); }
.animated.delay-2 { animation-delay: calc(var(--anim-step) * 2); }
.animated.delay-3 { animation-delay: calc(var(--anim-step) * 3); }
.animated.delay-4 { animation-delay: calc(var(--anim-step) * 4); }
.animated.delay-5 { animation-delay: calc(var(--anim-step) * 5); }
.animated.delay-6 { animation-delay: calc(var(--anim-step) * 6); }

@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.fadeIn { animation-name: fadeIn; }

@keyframes fadeInUp {
  from { opacity: 0; transform: translate3d(0, var(--anim-distance), 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
.fadeInUp { animation-name: fadeInUp; }

@keyframes fadeInDown {
  from { opacity: 0; transform: translate3d(0, calc(var(--anim-distance) * -1), 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
.fadeInDown { animation-name: fadeInDown; }

@keyframes fadeInLeft {
  from { opacity: 0; transform: translate3d(calc(var(--anim-distance-x) * -1), 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
.fadeInLeft { animation-name: fadeInLeft; }

@keyframes fadeInRight {
  from { opacity: 0; transform: translate3d(var(--anim-distance-x), 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
.fadeInRight { animation-name: fadeInRight; }

@keyframes zoomIn {
  from { opacity: 0; transform: scale3d(0.94, 0.94, 0.94); }
  to   { opacity: 1; transform: scale3d(1, 1, 1); }
}
.zoomIn { animation-name: zoomIn; }

@keyframes pulse {
  0%   { transform: scale3d(1, 1, 1); }
  50%  { transform: scale3d(1.05, 1.05, 1.05); }
  100% { transform: scale3d(1, 1, 1); }
}
.pulse { animation-name: pulse; }

/* ==========================================================================
   3. SCROLL REVEALS — animate as the element scrolls into view
   Usage: <div data-reveal="up" data-reveal-delay="2">
   Values: up (default) | down | left | right | zoom | fade
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {

    [data-reveal] {
      animation-name: fadeInUp;              /* "up" is the default */
      animation-duration: var(--anim-duration);
      animation-timing-function: var(--anim-ease);
      animation-timeline: view();
      animation-range: var(--anim-range);
      /* NO animation-fill-mode — see SAFE BY CONSTRUCTION above. */
    }

    [data-reveal="down"]  { animation-name: fadeInDown; }
    [data-reveal="left"]  { animation-name: fadeInLeft; }
    [data-reveal="right"] { animation-name: fadeInRight; }
    [data-reveal="zoom"]  { animation-name: zoomIn; }
    [data-reveal="fade"]  { animation-name: fadeIn; }

    /* Stagger. Because a view() timeline is driven by scroll position rather
       than time, "delay" shifts the trigger window later instead of pausing —
       which is what produces the cascade on a row of cards. */
    [data-reveal-delay="1"] { animation-range: entry 10% entry 80%; }
    [data-reveal-delay="2"] { animation-range: entry 15% entry 85%; }
    [data-reveal-delay="3"] { animation-range: entry 20% entry 90%; }
    [data-reveal-delay="4"] { animation-range: entry 25% entry 95%; }
    [data-reveal-delay="5"] { animation-range: entry 30% entry 100%; }
    [data-reveal-delay="6"] { animation-range: entry 35% entry 105%; }
  }
}

/* ==========================================================================
   4. IMAGE REVEALS — for photos inside a wrapper
   Usage: <figure data-reveal-img="scale"><img src="…" alt="…"></figure>
   Values: scale (settle) | wipe (uncover upward)
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {

    [data-reveal-img] { overflow: hidden; }

    [data-reveal-img] img {
      animation-duration: var(--anim-duration);
      animation-timing-function: var(--anim-ease);
      animation-timeline: view();
      animation-range: var(--anim-range);
    }

    [data-reveal-img="scale"] img { animation-name: imgScale; }
    [data-reveal-img="wipe"]  img { animation-name: imgWipe; }
  }
}

@keyframes imgScale {
  from { opacity: 0; transform: scale(1.12); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes imgWipe {
  from { clip-path: inset(100% 0 0 0); transform: scale(1.08); }
  to   { clip-path: inset(0 0 0 0);    transform: scale(1); }
}

/* ==========================================================================
   5. PARALLAX — element drifts as the page scrolls
   Usage: <img data-parallax="slow" …>  (parent needs overflow: hidden)
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: scroll(root)) {

    [data-parallax] {
      animation-name: parallaxDrift;
      animation-timing-function: linear;
      animation-timeline: scroll(root);
      will-change: transform;
    }
    [data-parallax="slow"]   { --parallax-shift: -20px; }
    [data-parallax="medium"],
    [data-parallax=""]       { --parallax-shift: -48px; }
    [data-parallax="fast"]   { --parallax-shift: -90px; }
  }
}

@keyframes parallaxDrift {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, var(--parallax-shift, -48px), 0); }
}

/* ==========================================================================
   6. KEN BURNS — slow continuous zoom, for hero / background images
   Usage: <img data-kenburns="in" …>  (parent needs overflow: hidden)
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  [data-kenburns] {
    animation: kenBurnsIn 20s var(--anim-ease) infinite alternate;
    will-change: transform;
  }
  [data-kenburns="out"] { animation-name: kenBurnsOut; }
}

@keyframes kenBurnsIn {
  from { transform: scale(1); }
  to   { transform: scale(1.12); }
}
@keyframes kenBurnsOut {
  from { transform: scale(1.12); }
  to   { transform: scale(1); }
}

/* ==========================================================================
   7. HOVER / MICRO-INTERACTIONS
   These are transitions, not animations — they work in every browser and are
   only disabled by reduced-motion.
   ========================================================================== */
.hover-lift {
  transition: transform 250ms var(--anim-ease), box-shadow 250ms var(--anim-ease);
}
.hover-lift:hover,
.hover-lift:focus-within { transform: translateY(-6px); }

.hover-zoom { overflow: hidden; }
.hover-zoom img { transition: transform 500ms var(--anim-ease); }
.hover-zoom:hover img,
.hover-zoom:focus-within img { transform: scale(1.06); }

/* Underline that grows from the left on hover. */
.hover-underline { position: relative; }
.hover-underline::after {
  content: "";
  position: absolute; left: 0; bottom: -2px;
  width: 100%; height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 250ms var(--anim-ease);
}
.hover-underline:hover::after,
.hover-underline:focus-visible::after { transform: scaleX(1); }

/* ==========================================================================
   8. REDUCED MOTION — global kill switch
   Anything above that still slips through lands here. Content stays visible.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .animated,
  [data-reveal],
  [data-reveal-img] img,
  [data-parallax],
  [data-kenburns] {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  .hover-lift,
  .hover-zoom img,
  .hover-underline::after { transition: none !important; }
}
