/* ===========================================================================
   MOTION & MICRO-INTERACTIONS

   Spec §33: animation communicates state, it does not decorate. Everything
   here maps to a specific thing the user needs to understand —
   "this is loading", "your tap registered", "that saved", "this is new".

   All durations and curves come from --mk-dur-* / --mk-ease-* in
   design-tokens.css. Nothing in this file hardcodes a timing.

   REDUCED MOTION: the whole file is disabled at the bottom for anyone who
   asked their OS for less movement. Vestibular disorders are real and a
   finance app is not the place to be clever about it — the entrances become
   instant, and the skeleton keeps a static shimmer-free background so it is
   still visibly a placeholder.
   =========================================================================== */

/* ── Skeleton loading ─────────────────────────────────────────────────────
   Shown in place of content while it loads, shaped like the content it will
   become. Better than a spinner because it says *what* is coming, and it
   stops the layout jumping when the real thing lands. */
.mk-skel {
    background: linear-gradient(
        90deg,
        var(--mk-bg-app) 25%,
        var(--mk-bg-subtle) 37%,
        var(--mk-bg-app) 63%
    );
    background-size: 400% 100%;
    animation: mk-shimmer 1.4s ease-in-out infinite;
    border-radius: var(--mk-r-sm);
}

.mk-skel-text   { height: 12px; margin-bottom: 8px; }
.mk-skel-title  { height: 18px; width: 45%; margin-bottom: 12px; }
.mk-skel-amount { height: 28px; width: 60%; margin-bottom: 10px; }
.mk-skel-line   { height: 12px; width: 100%; }
.mk-skel-line.short { width: 65%; }

.mk-skel-card {
    background: var(--mk-bg-surface);
    border: 1px solid var(--mk-border);
    border-radius: var(--mk-r-md);
    padding: var(--mk-s5);
    margin-bottom: var(--mk-s3);
}

@keyframes mk-shimmer {
    0%   { background-position: 100% 50%; }
    100% { background-position: 0 50%; }
}


/* Announced to screen readers, invisible on screen. A skeleton is a purely
   visual signal; without this, an assistive-tech user gets silence while the
   page loads. */
.mk-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ── Entrance ─────────────────────────────────────────────────────────────
   For content that arrives after load. Deliberately small: an 8px rise, not
   a slide across the screen. The job is to say "this is new", not to put on
   a show every time a list refreshes. */
.mk-enter {
    animation: mk-rise var(--mk-dur) var(--mk-ease) both;
}

/* Staggering makes a list read as a sequence rather than a single block
   appearing. Capped at six — beyond that the last item waits long enough to
   feel like lag rather than choreography. */
.mk-enter-stagger > * { animation: mk-rise var(--mk-dur) var(--mk-ease) both; }
.mk-enter-stagger > *:nth-child(1) { animation-delay: 0ms; }
.mk-enter-stagger > *:nth-child(2) { animation-delay: 40ms; }
.mk-enter-stagger > *:nth-child(3) { animation-delay: 80ms; }
.mk-enter-stagger > *:nth-child(4) { animation-delay: 120ms; }
.mk-enter-stagger > *:nth-child(5) { animation-delay: 160ms; }
.mk-enter-stagger > *:nth-child(n+6) { animation-delay: 200ms; }

@keyframes mk-rise {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

/* ── Press & hover ────────────────────────────────────────────────────────
   Touch has no hover, so the press state is the only feedback a phone user
   gets that their tap landed. Scale rather than colour: it survives every
   theme and every background colour underneath. */
.mk-press {
    transition: transform var(--mk-dur-fast) var(--mk-ease),
                box-shadow var(--mk-dur-fast) var(--mk-ease),
                background-color var(--mk-dur-fast) var(--mk-ease);
}
.mk-press:active { transform: scale(.97); }

.mk-lift {
    transition: transform var(--mk-dur-fast) var(--mk-ease),
                box-shadow var(--mk-dur-fast) var(--mk-ease);
}
.mk-lift:hover { transform: translateY(-2px); box-shadow: var(--mk-sh-md); }
.mk-lift:active { transform: translateY(0); }

/* ── Success ──────────────────────────────────────────────────────────────
   The tick that confirms a save. Draws itself rather than appearing, because
   the drawing is what reads as "done" — a static tick fading in looks like
   part of the layout. */
.mk-check {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--mk-fin-positive-lt);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    animation: mk-pop var(--mk-dur-slow) var(--mk-ease) both;
}
.mk-check svg { width: 28px; height: 28px; }
.mk-check path {
    stroke: var(--mk-fin-positive);
    stroke-width: 3;
    stroke-linecap: round;
    stroke-linejoin: round;
    fill: none;
    stroke-dasharray: 32;
    stroke-dashoffset: 32;
    animation: mk-draw var(--mk-dur-slow) var(--mk-ease) 80ms both;
}

@keyframes mk-pop {
    0%   { transform: scale(.7); opacity: 0; }
    60%  { transform: scale(1.05); opacity: 1; }
    100% { transform: scale(1); opacity: 1; }
}
@keyframes mk-draw { to { stroke-dashoffset: 0; } }

/* ── Value change ─────────────────────────────────────────────────────────
   A brief tint when a figure updates in place, so a balance that changed
   while the user was looking elsewhere does not change silently. */
.mk-flash-up   { animation: mk-flash-up var(--mk-dur-slow) var(--mk-ease-out) both; }
.mk-flash-down { animation: mk-flash-down var(--mk-dur-slow) var(--mk-ease-out) both; }

@keyframes mk-flash-up {
    0%   { color: var(--mk-fin-positive); }
    100% { color: inherit; }
}
@keyframes mk-flash-down {
    0%   { color: var(--mk-fin-negative); }
    100% { color: inherit; }
}

/* ── Progress fills ───────────────────────────────────────────────────────
   Budget bars, goal rings, the score arc. Linear, because a progress bar that
   eases is lying about the rate. */
.mk-fill { transition: width var(--mk-dur-slow) linear; }


/* ── Pull to refresh ──────────────────────────────────────────────────────
   The indicator js/motion.js inserts at the top of a scroll container. Height
   is driven from JS (it tracks the finger); everything else is here. */
.mk-ptr {
    height: 0;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    flex-shrink: 0;
}

.mk-ptr-spinner {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 2px solid var(--mk-border);
    border-top-color: var(--mk-primary);
    /* Static until the pull passes the threshold: a spinner that spins while
       you are still deciding says "loading" when nothing is loading yet. */
    transform: rotate(0deg);
    transition: border-top-color var(--mk-dur-fast) var(--mk-ease);
}

.mk-ptr-ready .mk-ptr-spinner { border-top-color: var(--mk-fin-positive); }

.mk-ptr-active .mk-ptr-spinner {
    animation: mk-spin 700ms linear infinite;
    border-top-color: var(--mk-primary);
}

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

@media (prefers-reduced-motion: reduce) {
    .mk-ptr-active .mk-ptr-spinner { animation: none; opacity: .7; }
    .mk-ptr { transition: none !important; }
}

/* ── Reduced motion ───────────────────────────────────────────────────────
   Everything above becomes instant. The skeleton keeps a flat background so
   it still reads as a placeholder rather than as empty content. */
@media (prefers-reduced-motion: reduce) {
    .mk-skel {
        animation: none;
        background: var(--mk-bg-app);
    }

    .mk-enter,
    .mk-enter-stagger > *,
    .mk-check,
    .mk-check path,
    .mk-flash-up,
    .mk-flash-down {
        animation: none !important;
    }

    .mk-check path { stroke-dashoffset: 0; }

    .mk-press,
    .mk-lift,
    .mk-fill { transition: none; }

    .mk-press:active,
    .mk-lift:hover,
    .mk-lift:active { transform: none; }
}
