/* apliteni-ui — motion library. Reusable entrance, micro-interaction, attention
 * and scroll-reveal effects as plain classes, every timing reading the brand
 * motion vocabulary.
 *
 * Per-effect overrides via custom properties on the element:
 *   --m-dur  duration   --m-ease  timing function
 *   --m-delay  start delay   --m-dist  slide travel (default 16px)
 *
 * Scroll reveals need `initReveal()` from apliteni-ui/motion. Without JS,
 * [data-reveal] content stays fully visible.
 *
 * The global prefers-reduced-motion net lives in reduced-motion.css and is NOT
 * @imported from here — the icon gates read each stylesheet on its own and
 * refuse a sheet that pulls in another.
 *
 * why: docs/foundations.md#motion */

/* -- Entrances -------------------------------------------------------------
 * `both` fill so the element starts at the "from" frame (hidden) and holds
 * the "to" frame. Compose with a delay for staggered groups. */
.m-fade-in,
.m-slide-up,
.m-slide-down,
.m-slide-left,
.m-slide-right,
.m-scale-in,
.m-blur-in {
  animation-duration: var(--m-dur, var(--dur-slow));
  animation-timing-function: var(--m-ease, var(--ease-out));
  animation-delay: var(--m-delay, 0s);
  animation-fill-mode: both;
}
.m-fade-in    { animation-name: m-fade; }
.m-slide-up   { animation-name: m-slide-up; }
.m-slide-down { animation-name: m-slide-down; }
.m-slide-left { animation-name: m-slide-left; }
.m-slide-right{ animation-name: m-slide-right; }
.m-scale-in   { animation-name: m-scale-in; }
.m-blur-in    { animation-name: m-blur-in; }

@keyframes m-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes m-slide-up {
  from { opacity: 0; transform: translateY(var(--m-dist, 16px)); }
  to   { opacity: 1; transform: none; }
}
@keyframes m-slide-down {
  from { opacity: 0; transform: translateY(calc(-1 * var(--m-dist, 16px))); }
  to   { opacity: 1; transform: none; }
}
@keyframes m-slide-left {
  from { opacity: 0; transform: translateX(var(--m-dist, 16px)); }
  to   { opacity: 1; transform: none; }
}
@keyframes m-slide-right {
  from { opacity: 0; transform: translateX(calc(-1 * var(--m-dist, 16px))); }
  to   { opacity: 1; transform: none; }
}
@keyframes m-scale-in {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: none; }
}
@keyframes m-blur-in {
  from { opacity: 0; filter: blur(8px); }
  to   { opacity: 1; filter: blur(0); }
}

/* -- Micro-interactions ----------------------------------------------------
 * .m-lift is the travel only; it cast --shadow-md until #295. */
.m-lift {
  transition: transform var(--dur-fast) var(--ease);
}
.m-lift:hover {
  transform: translateY(-3px);
}
.m-press {
  transition: transform var(--dur-instant) var(--ease-sharp);
}
.m-press:active { transform: scale(0.97); }

/* Shimmer / skeleton — a loading placeholder that reads the accent-neutral. */
.m-skeleton {
  position: relative;
  overflow: hidden;
  background: color-mix(in srgb, var(--text) 8%, transparent); /* code-bg: inherit — loading placeholder has no nested focus target. */
  border-radius: var(--radius-sm, 8px);
}
.m-skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in srgb, var(--text) 12%, transparent),
    transparent
  );
  animation: m-shimmer var(--duration-crawl, 1s) linear infinite; /* motion: ambient — a skeleton sweeps while the data is away */
}
@keyframes m-shimmer { to { transform: translateX(100%); } }

/* -- Attention ------------------------------------------------------------- */
.m-pulse { animation: m-pulse 2s var(--ease) infinite; } /* motion: ambient — attention loop with no interaction origin */
@keyframes m-pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50%      { transform: scale(1.04); opacity: 0.86; }
}

.m-shake { animation: m-shake var(--dur-slow) var(--ease) both; }
@keyframes m-shake {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-6px); }
  40%      { transform: translateX(5px); }
  60%      { transform: translateX(-3px); }
  80%      { transform: translateX(2px); }
}

/* Success draw-in — put on an SVG; strokes draw themselves. Set --m-len to the
 * path length (getTotalLength) for an exact draw; 48 is a sane default. */
.m-draw path,
.m-draw [data-draw] {
  stroke-dasharray: var(--m-len, 48);
  stroke-dashoffset: var(--m-len, 48);
  animation: m-draw var(--dur-slow) var(--ease-out) forwards;
  animation-delay: var(--m-delay, 0s);
}
@keyframes m-draw { to { stroke-dashoffset: 0; } }

/* -- Scroll reveals --------------------------------------------------------
 * Progressive enhancement: [data-reveal] is only hidden once JS marks the
 * document (<html class="js-reveal">). initReveal() then adds .is-revealed as
 * each element enters the viewport. Stagger a group with --reveal-i (0,1,2…).
 * If JS never runs, content shows normally — nothing is trapped hidden. */
.js-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
  transition-delay: calc(var(--reveal-i, 0) * var(--delay-2));
}
.js-reveal [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

/* The global reduced-motion net lives in reduced-motion.css, imported beside this
 * file from src/index.css — it has to reach the React bundle as well. */
