/* Drawer motion, the flavours (0.18, docs/VFX-NOTES.md 3.1-3.4). admin/fx.js
   labels each card, row, tab, toast and modal with data-fx (hashed, never
   the same as its neighbour), --i and --jit; this file picks the move. Every
   distance and angle is multiplied by --fx-amp (ui.admin_motion: none 0,
   subtle .55, lively 1), durations and easings come from theme.css, and each
   system owns one property (arrivals translate / scale / opacity, idle life
   rotate, presses scale) so they compose. Every animation here can go and
   nothing is lost; theme.css's reduced-motion rule does exactly that. */

/* Arrival delay: a stagger with a hashed jitter, so a column of cards reads
   as dealt by hand rather than by a machine. */
#admin .panel > [data-fx], #admin fieldset > .row[data-fx] {
  animation-delay: calc(var(--i, 0) * 55ms + var(--jit, 0) * 1ms);
  animation-fill-mode: both;
}
#admin .panel { animation: none; }

/* Cards: six flavours. */
#admin .panel > [data-fx="0"] { animation-name: fx-slam; animation-duration: var(--t-4); animation-timing-function: var(--e-over); }
#admin .panel > [data-fx="1"] { animation-name: fx-rise; animation-duration: var(--t-4); animation-timing-function: var(--e-anticipate); }
#admin .panel > [data-fx="2"] { animation-name: fx-from-left; animation-duration: var(--t-3); animation-timing-function: var(--e-out); }
#admin .panel > [data-fx="3"] { animation-name: fx-drop; animation-duration: var(--t-5); animation-timing-function: var(--e-bounce); }
#admin .panel > [data-fx="4"] { animation-name: fx-wipe; animation-duration: var(--t-4); animation-timing-function: var(--e-out); }
#admin .panel > [data-fx="5"] { animation-name: fx-from-right; animation-duration: var(--t-4); animation-timing-function: var(--e-hitstop); }

@keyframes fx-slam { from { opacity: 0; scale: calc(1 + .06 * var(--fx-amp)); } }
@keyframes fx-rise { from { opacity: 0; translate: 0 calc(18px * var(--fx-amp)); } 30% { opacity: 1; } }
@keyframes fx-from-left { from { opacity: 0; translate: calc(-28px * var(--fx-amp)) 0; } }
@keyframes fx-drop { from { opacity: 0; translate: 0 calc(-22px * var(--fx-amp)); } 25% { opacity: 1; } }
@keyframes fx-from-right { from { opacity: 0; translate: calc(24px * var(--fx-amp)) 0; } }
/* A hard diagonal ink wipe (A6): the card is printed onto the page. The
   mask lives only in the keyframes and the fill is backwards, so a card at
   rest carries no mask pass. */
#admin .panel > [data-fx="4"] { animation-fill-mode: backwards; }
@keyframes fx-wipe {
  from {
    -webkit-mask-image: linear-gradient(105deg, #000 40%, transparent 42%); mask-image: linear-gradient(105deg, #000 40%, transparent 42%);
    -webkit-mask-size: 260% 100%; mask-size: 260% 100%; -webkit-mask-position: 100% 0; mask-position: 100% 0;
  }
  to {
    -webkit-mask-image: linear-gradient(105deg, #000 40%, transparent 42%); mask-image: linear-gradient(105deg, #000 40%, transparent 42%);
    -webkit-mask-size: 260% 100%; mask-size: 260% 100%; -webkit-mask-position: 0 0; mask-position: 0 0;
  }
}

/* Rows follow their card, a beat behind, in three small flavours. */
#admin fieldset > .row[data-fx] { animation-duration: var(--t-3); animation-timing-function: var(--e-out); }
#admin fieldset > .row[data-fx] { animation-delay: calc(120ms + var(--i, 0) * 32ms + var(--jit, 0) * 1ms); }
#admin fieldset > .row[data-fx="0"] { animation-name: fx-row-up; }
#admin fieldset > .row[data-fx="1"] { animation-name: fx-row-left; }
#admin fieldset > .row[data-fx="2"] { animation-name: fx-row-fade; }
@keyframes fx-row-up { from { opacity: 0; translate: 0 calc(8px * var(--fx-amp)); } }
@keyframes fx-row-left { from { opacity: 0; translate: calc(-10px * var(--fx-amp)) 0; } }
@keyframes fx-row-fade { from { opacity: 0; } }

/* The title card: the plate is printed, then the banner slams onto it and
   settles; after that it sways like a hanging sign, never in step with the
   tab stickers. */
#admin .panel[data-arrive] .title-card { animation: fx-plate var(--t-4) var(--e-out) both; }
@keyframes fx-plate { from { opacity: 0; translate: 0 calc(-10px * var(--fx-amp)); } }
#admin .panel-banner { transform-origin: 70% 100%; animation: fx-sway 7.3s var(--e-out) -2s infinite alternate; }
#admin .panel[data-arrive] .panel-banner {
  animation: fx-banner-in var(--t-5) var(--e-over) 90ms both, fx-sway 7.3s var(--e-out) calc(var(--t-5) + 90ms) infinite alternate;
}
@keyframes fx-banner-in { from { opacity: 0; scale: calc(1 - .25 * var(--fx-amp)); translate: calc(30px * var(--fx-amp)) calc(-12px * var(--fx-amp)); } }
@keyframes fx-sway { from { rotate: calc(-.9deg * var(--fx-amp)); } to { rotate: calc(.9deg * var(--fx-amp)); } }
/* A layered banner instead: each piece lands a beat after the one behind it
   and then keeps a life of its own - a sway, a bob, a lean - on three
   periods that do not divide into each other, so the group never falls into
   step with itself or with the tab stickers. Nothing follows the pointer. */
#admin .banner-layer[data-n="1"] { transform-origin: 70% 100%; animation: fx-sway 7.3s var(--e-out) -2s infinite alternate; }
#admin .banner-layer[data-n="2"] { transform-origin: 50% 100%; animation: fx-bob 5.2s ease-in-out -1.1s infinite alternate; }
#admin .banner-layer[data-n="3"] { transform-origin: 30% 100%; animation: fx-lean 6.1s var(--e-out) -3.4s infinite alternate; }
@keyframes fx-bob { from { translate: 0 calc(3px * var(--fx-amp)); } to { translate: 0 calc(-4px * var(--fx-amp)); } }
@keyframes fx-lean { from { rotate: calc(1.1deg * var(--fx-amp)); } to { rotate: calc(-.5deg * var(--fx-amp)); } }
#admin .panel[data-arrive] .banner-layer[data-n="1"] { animation: fx-banner-in var(--t-5) var(--e-over) 90ms both, fx-sway 7.3s var(--e-out) calc(var(--t-5) + 90ms) infinite alternate; }
#admin .panel[data-arrive] .banner-layer[data-n="2"] { animation: fx-banner-in var(--t-5) var(--e-over) 180ms both, fx-bob 5.2s ease-in-out calc(var(--t-5) + 180ms) infinite alternate; }
#admin .panel[data-arrive] .banner-layer[data-n="3"] { animation: fx-banner-in var(--t-5) var(--e-over) 260ms both, fx-lean 6.1s var(--e-out) calc(var(--t-5) + 260ms) infinite alternate; }

#admin .panel[data-arrive] .title-card h2 { animation: fx-words var(--t-4) var(--e-hitstop) 40ms both; }
@keyframes fx-words { from { opacity: 0; scale: calc(1 + .3 * var(--fx-amp)); } }

/* Tab stickers breathe out of step (I1): a period and a phase per tab. The
   chosen one hops once when it is chosen. */
#admin-tabs .tab-art { animation: fx-breathe calc(4s + var(--i, 0) * 370ms) ease-in-out calc(var(--i, 0) * -1.7s) infinite alternate; }
@keyframes fx-breathe { to { scale: calc(1 + .05 * var(--fx-amp)); } }
#admin-tabs[data-arrive] button[aria-selected="true"] .tab-art { animation: fx-hop var(--t-5) var(--e-bounce) both; }
@keyframes fx-hop { from { translate: 0 calc(-7px * var(--fx-amp)); } }
#admin-tabs button .tab-art { transition: translate var(--t-2) var(--e-out), filter var(--t-2) var(--e-out); }
#admin-tabs button:hover .tab-art { translate: 0 calc(-3px * var(--fx-amp)); filter: drop-shadow(2.5px 3.5px 0 var(--ink-line)); }

/* Presses squash and stretch a little (R1) on top of the push into the
   shadow that admin-motion.css already does. */
#admin .btn:not(:disabled):active, #modal-root .btn:not(:disabled):active { scale: calc(1 + .04 * var(--fx-amp)) calc(1 - .04 * var(--fx-amp)); }
#admin .btn { transition: transform var(--t-1) ease-out, box-shadow var(--t-1) ease-out, scale var(--t-2) var(--e-over), background-color var(--t-2) ease-out, color var(--t-2) ease-out; }

/* none: nothing moves in the drawer, the toasts or the modal. */
[data-fx-level="none"] *, [data-fx-level="none"] { animation: none !important; transition: none !important; }

/* An empty state's picture hangs and sways slowly, like the banners. */
#admin .empty-art { transform-origin: 50% 100%; animation: fx-sway 5.9s var(--e-out) -1s infinite alternate; }
