/* =====================================================================
   SECTION ANIMATIONS — CSS
   ---------------------------------------------------------------------
   HOW IT WORKS (3 steps)
   1. You add  data-animate="effect-name"  to any element.
   2. The JS file waits until that element scrolls into view, then
      adds the class  "is-visible".
   3. "is-visible" starts the matching animation in this file.

   Every animation goes FROM a starting look (hidden, moved, blurred…)
   TO the element's normal look. That means when an animation ends,
   your element looks exactly the way you styled it.

   FILE LAYOUT
   1. Settings            ← change colors, speed, distance here
   2. The on/off switch
   3. Self effects        (the element itself moves)
   4. Group effects       (the element's children move one by one)
   5. Overlay effects     (a layer on top uncovers the element)
   6. JS-helped effects   (typewriter, count-up)
   7. Reduced motion      (respects the user's accessibility setting)
   ===================================================================== */


/* =====================================================================
   1. SETTINGS — change these to restyle every animation at once
   ===================================================================== */
:root {
  --sa-duration: 700ms;   /* how long one animation lasts            */
  --sa-delay: 0ms;        /* wait before it starts                    */
  --sa-stagger: 90ms;     /* gap between children in group effects   */
  --sa-distance: 28px;    /* how far things slide                     */
  --sa-color: #3443E8;    /* color of doors, blinds, pixels, lines    */

  /* Easing = the "feel" of the movement */
  --sa-ease-smooth: cubic-bezier(.16, 1, .3, 1);    /* fast start, soft landing */
  --sa-ease-bounce: cubic-bezier(.34, 1.56, .64, 1); /* overshoots a little      */
  --sa-ease-steady: cubic-bezier(.65, 0, .35, 1);    /* slow → fast → slow       */
}

/* Some effects look better a bit slower, so they get their own default.
   (data-duration="…" on the element still overrides these.) */
[data-animate="blur-in"]        { --sa-duration: 950ms; }
[data-animate="depth-dolly"],
[data-animate="iris"],
[data-animate="tilt-settle"],
[data-animate="scanline"]       { --sa-duration: 1000ms; }
[data-animate="curtain"],
[data-animate="hinge"],
[data-animate="gravity-drop"]   { --sa-duration: 900ms; }
[data-animate="ink-spread"],
[data-animate="line-to-panel"],
[data-animate="dot-morph"]      { --sa-duration: 1100ms; }
[data-animate="magnetic"]       { --sa-duration: 800ms; }
[data-animate="split-doors"]    { --sa-duration: 750ms; }
[data-animate="glitch"]         { --sa-duration: 600ms; }
[data-animate="brochure-fold"]  { --sa-duration: 650ms; --sa-stagger: 140ms; }
[data-animate="gravity-drop"]   { --sa-stagger: 110ms; }


/* =====================================================================
   2. THE ON/OFF SWITCH
   ===================================================================== */

/* Hide animated elements until they scroll into view.
   This only happens when the JS is running (it adds .sa-ready to <html>),
   so if the JS ever fails to load, your content still shows. */
.sa-ready [data-animate]:not(.is-visible) {
  opacity: 0;
}

/* Shared timing for every effect. Each effect below only picks a name. */
[data-animate].is-visible {
  animation-duration: var(--sa-duration);
  animation-delay: var(--sa-delay);
  animation-timing-function: var(--sa-ease-smooth);
  animation-fill-mode: backwards;  /* hold the starting look during the delay */
}


/* =====================================================================
   3. SELF EFFECTS — the element itself animates
   ===================================================================== */

/* --- fade-up: rises a little while fading in. The safe default. --- */
[data-animate="fade-up"].is-visible { animation-name: sa-fade-up; }
@keyframes sa-fade-up {
  from { opacity: 0; transform: translateY(var(--sa-distance)); }
}

/* --- blur-in: sharpens out of a soft blur --- */
[data-animate="blur-in"].is-visible { animation-name: sa-blur-in; }
@keyframes sa-blur-in {
  from { opacity: 0; filter: blur(14px); transform: scale(1.05); }
}

/* --- depth-dolly: falls from "in front of" the screen into place --- */
[data-animate="depth-dolly"].is-visible { animation-name: sa-depth-dolly; }
@keyframes sa-depth-dolly {
  from { opacity: 0; transform: scale(1.4); filter: blur(6px); }
}

/* --- curtain: a hard edge wipes from left to right --- */
[data-animate="curtain"].is-visible {
  animation-name: sa-curtain;
  animation-timing-function: var(--sa-ease-steady);
}
@keyframes sa-curtain {
  from { clip-path: inset(0 100% 0 0); }  /* inset(top right bottom left) */
  to   { clip-path: inset(0 0 0 0); }
}

/* --- iris: a circle opens from the center like a camera lens --- */
[data-animate="iris"].is-visible { animation-name: sa-iris; }
@keyframes sa-iris {
  from { clip-path: circle(0% at 50% 50%); }
  to   { clip-path: circle(75% at 50% 50%); }
}

/* --- ink-spread: floods in from the bottom-left corner --- */
[data-animate="ink-spread"].is-visible {
  animation-name: sa-ink-spread;
  animation-timing-function: cubic-bezier(.5, 0, .2, 1);
}
@keyframes sa-ink-spread {
  from { clip-path: circle(0% at 0% 100%); }
  to   { clip-path: circle(150% at 0% 100%); }
}

/* --- line-to-panel: a thin colored line draws across, then opens up --- */
[data-animate="line-to-panel"].is-visible {
  animation-name: sa-line-to-panel;
  animation-timing-function: var(--sa-ease-steady);
}
@keyframes sa-line-to-panel {
  0%   { clip-path: inset(calc(50% - 1px) 50% calc(50% - 1px) 50%); background-color: var(--sa-color); }
  40%  { clip-path: inset(calc(50% - 1px) 0   calc(50% - 1px) 0);   background-color: var(--sa-color); }
  100% { clip-path: inset(0 0 0 0); }
}

/* --- dot-morph: a small dot stretches into the full section --- */
[data-animate="dot-morph"].is-visible { animation-name: sa-dot-morph; }
@keyframes sa-dot-morph {
  0%, 25% { clip-path: inset(calc(50% - 10px) calc(50% - 10px) round 999px); background-color: var(--sa-color); }
  100%    { clip-path: inset(0 round 0); }
}
/* The content fades in once the shape has mostly opened */
[data-animate="dot-morph"].is-visible > * {
  animation: sa-fade-in calc(var(--sa-duration) * .4) ease calc(var(--sa-delay) + var(--sa-duration) * .6) backwards;
}
@keyframes sa-fade-in {
  from { opacity: 0; }
}

/* --- hinge: swings down from its top edge like a flap --- */
[data-animate="hinge"] { transform-origin: 50% 0; }
[data-animate="hinge"].is-visible {
  animation-name: sa-hinge;
  animation-timing-function: var(--sa-ease-bounce);
}
@keyframes sa-hinge {
  from { opacity: 0; transform: perspective(700px) rotateX(-85deg); }
}

/* --- tilt-settle: drops in crooked, wobbles, settles flat --- */
[data-animate="tilt-settle"].is-visible {
  animation-name: sa-tilt-settle;
  animation-timing-function: cubic-bezier(.3, .7, .4, 1);
}
@keyframes sa-tilt-settle {
  0%  { opacity: 0; transform: translateY(50px) rotate(-6deg); }
  55% { opacity: 1; transform: translateY(-4px) rotate(1.5deg); }
  80% { transform: translateY(1px) rotate(-.5deg); }
}

/* --- glitch: a burst of digital jitter, then snaps into place --- */
[data-animate="glitch"].is-visible {
  animation-name: sa-glitch;
  animation-timing-function: steps(1, end);  /* jump between frames, no smoothing */
}
@keyframes sa-glitch {
  0%   { opacity: 0; transform: translate(-10px, 3px) skewX(8deg);  clip-path: inset(12% 0 60% 0); }
  15%  { opacity: 1; transform: translate(8px, -3px) skewX(-6deg);  clip-path: inset(45% 0 18% 0); text-shadow: -3px 0 #ff2a6d, 3px 0 #05d9e8; }
  30%  { transform: translate(-6px, 1px);           clip-path: inset(0 0 72% 0);   text-shadow: 3px 0 #ff2a6d, -3px 0 #05d9e8; }
  45%  { transform: translate(6px, 0) skewX(4deg);  clip-path: inset(58% 0 4% 0);  text-shadow: -2px 0 #ff2a6d, 2px 0 #05d9e8; }
  60%  { transform: translate(-3px, 2px);           clip-path: inset(20% 0 28% 0); }
  80%  { transform: translate(2px, 0);              clip-path: inset(0 0 0 0); }
}

/* --- accordion: the first child (a heading) shows, then the rest unfolds.
   NEEDS exactly two children: a header and a body wrapper.             --- */
[data-animate="accordion"] {
  display: grid;
  grid-template-rows: auto 0fr;  /* body row starts at zero height */
  transition: grid-template-rows var(--sa-duration) var(--sa-ease-smooth) calc(var(--sa-delay) + 250ms);
}
[data-animate="accordion"] > :last-child {
  overflow: hidden;
  min-height: 0;
}
[data-animate="accordion"].is-visible {
  grid-template-rows: auto 1fr;  /* body row grows to full height */
}
[data-animate="accordion"].is-visible > :first-child {
  animation: sa-fade-up 450ms var(--sa-ease-smooth) var(--sa-delay) backwards;
}


/* =====================================================================
   4. GROUP EFFECTS — the element's direct children animate one by one.
   The JS gives each child a number called --i (0, 1, 2…).
   Delay for each child = data-delay + (its number × --sa-stagger).
   ===================================================================== */
.is-visible:is(
  [data-animate="stagger"],
  [data-animate="zigzag"],
  [data-animate="bloom"],
  [data-animate="brochure-fold"],
  [data-animate="gravity-drop"],
  [data-animate="magnetic"]
) > * {
  animation-duration: var(--sa-duration);
  animation-delay: calc(var(--sa-delay) + var(--i, 0) * var(--sa-stagger));
  animation-timing-function: var(--sa-ease-smooth);
  animation-fill-mode: backwards;
}

/* --- stagger: children fade up one after another, top to bottom --- */
[data-animate="stagger"].is-visible > * { animation-name: sa-fade-up; }

/* --- zigzag: children slide in from alternating sides --- */
[data-animate="zigzag"].is-visible > :nth-child(odd)  { animation-name: sa-from-left; }
[data-animate="zigzag"].is-visible > :nth-child(even) { animation-name: sa-from-right; }
@keyframes sa-from-left  { from { opacity: 0; transform: translateX(-60px); } }
@keyframes sa-from-right { from { opacity: 0; transform: translateX(60px); } }

/* --- bloom: the middle child pops first, neighbors follow outward --- */
[data-animate="bloom"].is-visible > * {
  animation-name: sa-bloom;
  animation-timing-function: var(--sa-ease-bounce);
}
@keyframes sa-bloom {
  from { opacity: 0; transform: scale(.5); }
}

/* --- brochure-fold: children unfold like panels hinged on the left --- */
[data-animate="brochure-fold"] > * { transform-origin: 0 50%; }
[data-animate="brochure-fold"].is-visible > * { animation-name: sa-fold; }
@keyframes sa-fold {
  from { opacity: 0; transform: perspective(600px) rotateY(-95deg); }
}

/* --- gravity-drop: children fall from above and bounce to rest --- */
[data-animate="gravity-drop"].is-visible > * {
  animation-name: sa-gravity;
  animation-timing-function: linear;  /* each step below sets its own easing */
}
@keyframes sa-gravity {
  0%   { opacity: 0; transform: translateY(-160px); animation-timing-function: cubic-bezier(.55, 0, 1, .45); } /* falling   */
  50%  { opacity: 1; transform: translateY(0);      animation-timing-function: cubic-bezier(0, .55, .45, 1); } /* 1st hit   */
  68%  {             transform: translateY(-20px);  animation-timing-function: cubic-bezier(.55, 0, 1, .45); } /* bounce up */
  82%  {             transform: translateY(0);      animation-timing-function: cubic-bezier(0, .55, .45, 1); } /* 2nd hit   */
  91%  {             transform: translateY(-6px);   animation-timing-function: cubic-bezier(.55, 0, 1, .45); } /* tiny hop  */
  100% {             transform: translateY(0); }
}

/* --- magnetic: children fly in from random spots and snap into place.
   The JS picks a random --sa-x, --sa-y, --sa-r and --d for each child. --- */
[data-animate="magnetic"].is-visible > * {
  animation-name: sa-magnetic;
  animation-timing-function: var(--sa-ease-bounce);
  animation-delay: calc(var(--sa-delay) + var(--d, 0ms));
}
@keyframes sa-magnetic {
  from { opacity: 0; transform: translate(var(--sa-x), var(--sa-y)) rotate(var(--sa-r)) scale(.6); }
}


/* =====================================================================
   5. OVERLAY EFFECTS — the JS adds a decorative layer on top of the
   element, and that layer moves out of the way to uncover it.
   ===================================================================== */
.sa-has-overlay {
  position: relative;  /* so the overlay can sit exactly on top */
  overflow: hidden;    /* so the overlay is hidden once it moves away */
}
.sa-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;  /* never blocks clicks */
}

/* --- split-doors: two colored panels slide apart --- */
.sa-doors span {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 50.5%;  /* the extra .5% hides the seam in the middle */
  background: var(--sa-color);
}
.sa-doors span:first-child { left: 0;  transform: translateX(-101%); }  /* resting place: off to the left  */
.sa-doors span:last-child  { right: 0; transform: translateX(101%); }   /* resting place: off to the right */

[data-animate="split-doors"].is-visible .sa-doors span {
  animation: var(--sa-duration) var(--sa-ease-steady) calc(var(--sa-delay) + 300ms) backwards;
}
[data-animate="split-doors"].is-visible .sa-doors span:first-child { animation-name: sa-door-left; }
[data-animate="split-doors"].is-visible .sa-doors span:last-child  { animation-name: sa-door-right; }
@keyframes sa-door-left  { from { transform: translateX(0); } }
@keyframes sa-door-right { from { transform: translateX(0); } }

/* The section underneath settles slightly as the doors open */
[data-animate="split-doors"].is-visible {
  animation-name: sa-settle;
  animation-delay: calc(var(--sa-delay) + 300ms);
}
@keyframes sa-settle {
  from { transform: scale(.94); }
}

/* --- blinds: horizontal slats pull up one after another --- */
.sa-blinds {
  display: flex;
  flex-direction: column;
}
.sa-blinds span {
  flex: 1;
  background: var(--sa-color);
  transform: scaleY(0);  /* resting place: flattened to nothing */
  transform-origin: top;
}
[data-animate="blinds"].is-visible .sa-blinds span {
  animation: sa-blind calc(var(--sa-duration) * .7) var(--sa-ease-steady)
             calc(var(--sa-delay) + var(--i) * 75ms) backwards;
}
@keyframes sa-blind {
  from { transform: scaleY(1.02); }  /* 1.02 avoids thin gaps between slats */
}

/* --- scanline: a cover slides down with a glowing line on its edge.
   The cover copies the element's own background, so give the element
   a background color for this one to look right. --- */
.sa-scanline {
  background: inherit;          /* same background as the section */
  transform: translateY(calc(100% + 24px));  /* resting place: below the section, glow included */
}
.sa-scanline::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 2px;
  background: var(--sa-color);
  box-shadow: 0 0 12px 2px var(--sa-color);
}
[data-animate="scanline"].is-visible .sa-scanline {
  animation: sa-scan var(--sa-duration) linear var(--sa-delay) backwards;
}
@keyframes sa-scan {
  from { transform: translateY(0); }
}

/* --- pixel-dissolve: a grid of tiles blinks away in random order --- */
.sa-pixels {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  grid-template-rows: repeat(6, 1fr);
}
.sa-pixels span {
  background: var(--sa-color);
  opacity: 0;  /* resting place: invisible */
}
[data-animate="pixel-dissolve"].is-visible .sa-pixels span {
  animation: sa-pixel 200ms steps(1, end) calc(var(--sa-delay) + var(--d)) backwards;
}
@keyframes sa-pixel {
  from { opacity: 1; }
}


/* =====================================================================
   6. JS-HELPED EFFECTS — the JS changes the text; CSS adds polish
   ===================================================================== */

/* --- typewriter: blinking cursor while the JS types the text --- */
.sa-typing::after {
  content: "";
  display: inline-block;
  width: .08em;
  height: 1em;
  margin-left: .06em;
  vertical-align: -.12em;
  background: currentColor;
  animation: sa-blink .8s steps(1) infinite;
}
@keyframes sa-blink {
  50% { opacity: 0; }
}

/* --- count-up: the box fades up while the JS counts the numbers.
   Any element inside marked  data-bar  fills from left to right. --- */
[data-animate="count-up"].is-visible { animation-name: sa-fade-up; }
[data-animate="count-up"] [data-bar] { transform-origin: left; }
[data-animate="count-up"].is-visible [data-bar] {
  animation: sa-bar calc(var(--sa-duration) * 1.8) var(--sa-ease-smooth) calc(var(--sa-delay) + 150ms) backwards;
}
@keyframes sa-bar {
  from { transform: scaleX(0); }
}


/* =====================================================================
   7. REDUCED MOTION — if someone has turned on "reduce motion" in
   their device settings, skip all movement and just show the content.
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
  [data-animate],
  [data-animate] > *,
  [data-animate] [data-bar],
  .sa-overlay,
  .sa-overlay * {
    animation: none !important;
    transition: none !important;
  }
}
