/* =============================================================================
   IzeChat Motion Design System — Layer 0 (tokens) + Layer 1 (primitives)
   -----------------------------------------------------------------------------
   THE single source of truth for how anything in IzeChat moves. Every duration,
   every curve, every press/enter/exit gesture in the product resolves to one of
   the tokens below. Components must never invent a duration or a cubic-bezier
   again; they compose these.

   WHY A SYSTEM AND NOT MORE ANIMATION
   The audit (MOTION-DESIGN-SYSTEM.md) found 22 distinct easing curves, 4
   independent ripple implementations and 15 spinner keyframes across the theme.
   Nothing was wrong individually; together they read as "many small websites"
   rather than one app. Motion carries meaning only when it is consistent: the
   same gesture must always take the same time on the same curve, or the user
   stops reading it as language and starts reading it as noise.

   NAMESPACE
   Every custom property is `--ize-mo-*` and every class/keyframe is `ize-mo-*`.
   Deliberate: `--ize-ink`, `--ize-ease`, `--ize-surface` are ALREADY defined
   with conflicting meanings by ize-actionbar.css, ize-premium.css, ize-auth.css
   and ize-comment-sheet.css. A generic name here would silently repaint those
   components. `--ize-mo-` collides with nothing.

   BACKWARD COMPATIBILITY
   Purely additive. This file defines tokens and opt-in classes; it does not
   restyle, reset or !important any existing selector, and it contains no
   universal (`*`) rule. A component animates through the system only once it
   has been migrated to it. Nothing breaks by loading this file.

   PERFORMANCE CONTRACT
   Only `transform`, `opacity` and `filter` are animated by anything in here —
   the three properties the compositor can run off the main thread. No width,
   height, top/left, margin or box-shadow transitions. `will-change` is applied
   ONLY for the duration of a gesture (see .ize-mo-lift), never as a resting
   state, because a permanent will-change costs a compositor layer per element
   and — critically for this app — makes the element a containing block for its
   position:fixed descendants (which is what would break the nav bar's panels).

   MOTION POLICY (the one dial)
   All durations are `calc(<base> * var(--ize-mo-scale))`. Anything that needs to
   slow down, speed up or effectively stop motion moves that ONE number:
     • prefers-reduced-motion: reduce   -> .01  (imperceptible, but non-zero so
                                                 transitionend/animationend still
                                                 fire and no JS waits forever)
     • html.ize-lean (IzeXM low-power / low-bandwidth / offline) -> .75
     • html.ize-mo-off (kill switch, JS or debugging)            -> .01
   Looping "ambient" animations are gated separately by
   `--ize-mo-ambient-play` (running|paused), because the right answer for a
   shimmer on a battery-saver device is to STOP, not to run fast.
   ========================================================================== */

:root {
	/* ---- The dial ---------------------------------------------------------- */
	--ize-mo-scale: 1;
	--ize-mo-ambient-play: running;

	/* ---- Durations --------------------------------------------------------- *
	 * instant : state tint under a finger — must beat the perception threshold
	 * fast    : icon / colour / opacity swaps
	 * quick   : THE default UI transition (nav, chips, toggles) — 200ms is the
	 *           "responsive but not abrupt" band every reference app lives in
	 * normal  : cards, menus, dialogs entering
	 * slow    : bottom sheets, large surfaces entering
	 * slower  : shared-element / full-screen morphs
	 * page    : in-app content swap
	 * ripple  : touch ripple expansion (long by design; it outlives the press)
	 *
	 * Each one is declared TWICE: once as a bare number (--ize-mo-b-*) and once
	 * as the usable time token (--ize-mo-t-*). That is not redundancy — it is
	 * what keeps CSS and JS on one source of truth. A custom property holding
	 * `calc(200ms * 1)` is returned to getComputedStyle verbatim (custom props
	 * are untyped, so calc is never evaluated for them), which would force
	 * ize-motion.js to keep its own private copy of every duration and drift
	 * away from this file. The bare numbers resolve cleanly, so JS reads them. */
	--ize-mo-b-instant:  90;
	--ize-mo-b-fast:    140;
	--ize-mo-b-quick:   200;
	--ize-mo-b-normal:  260;
	--ize-mo-b-slow:    320;
	--ize-mo-b-slower:  400;
	--ize-mo-b-page:    240;
	--ize-mo-b-ripple:  480;

	--ize-mo-t-instant: calc(var(--ize-mo-b-instant) * 1ms * var(--ize-mo-scale));
	--ize-mo-t-fast:    calc(var(--ize-mo-b-fast)    * 1ms * var(--ize-mo-scale));
	--ize-mo-t-quick:   calc(var(--ize-mo-b-quick)   * 1ms * var(--ize-mo-scale));
	--ize-mo-t-normal:  calc(var(--ize-mo-b-normal)  * 1ms * var(--ize-mo-scale));
	--ize-mo-t-slow:    calc(var(--ize-mo-b-slow)    * 1ms * var(--ize-mo-scale));
	--ize-mo-t-slower:  calc(var(--ize-mo-b-slower)  * 1ms * var(--ize-mo-scale));
	--ize-mo-t-page:    calc(var(--ize-mo-b-page)    * 1ms * var(--ize-mo-scale));
	--ize-mo-t-ripple:  calc(var(--ize-mo-b-ripple)  * 1ms * var(--ize-mo-scale));

	/* Loop durations are NOT scaled: a shimmer at 0.01x is a strobe. They are
	   switched off wholesale by --ize-mo-ambient-play instead. */
	--ize-mo-t-shimmer: 1150ms;   /* matches the existing skeleton cadence */
	--ize-mo-t-breathe: 3200ms;
	--ize-mo-t-spin:     900ms;
	--ize-mo-t-pulse:   1800ms;

	/* ---- Easing ------------------------------------------------------------ *
	 * Four curves carry 95% of the product. They are Material 3's, chosen
	 * because the shell is an Android WebView and the motion must agree with
	 * the OS transitions happening around it.
	 *   standard : anything moving within the screen, both directions
	 *   enter    : anything ARRIVING (emphasized decelerate) — fast off the
	 *              mark, long soft landing. Nothing should land hard.
	 *   exit     : anything LEAVING (emphasized accelerate) — no lingering
	 *   glide    : long positional travel (indicators, bars auto-hiding)
	 * Springs are for acknowledgement only (a like, a success), never travel. */
	--ize-mo-e-standard:  cubic-bezier(.2, 0, 0, 1);
	--ize-mo-e-enter:     cubic-bezier(.05, .7, .1, 1);
	--ize-mo-e-exit:      cubic-bezier(.3, 0, .8, .15);
	--ize-mo-e-glide:     cubic-bezier(.22, .61, .36, 1);
	--ize-mo-e-spring:    cubic-bezier(.34, 1.4, .64, 1);
	--ize-mo-e-spring-lg: cubic-bezier(.34, 1.56, .64, 1);
	--ize-mo-e-linear:    linear;
	/* Migration alias only: the M2 curve the legacy theme uses in ~20 places.
	   Lets a file adopt the token vocabulary in one commit and re-time in the
	   next, without a visual jump in between. Do not use in new work. */
	--ize-mo-e-legacy:    cubic-bezier(.4, 0, .2, 1);

	/* ---- Transforms -------------------------------------------------------- */
	--ize-mo-press:     .96;    /* buttons, icons                              */
	--ize-mo-press-sm:  .90;    /* small icon-only targets, needs more travel  */
	--ize-mo-press-lg:  .985;   /* cards — a big surface moving 4% looks broken */
	--ize-mo-pop:       1.08;   /* acknowledgement overshoot                    */
	--ize-mo-rise:      8px;    /* enter offset                                 */
	--ize-mo-rise-lg:   16px;

	/* ---- Opacity ----------------------------------------------------------- */
	--ize-mo-dim:       .68;    /* pressed non-tinted surfaces (images, chips) */
	--ize-mo-ghost:     .38;    /* disabled / pending                          */

	/* ---- Surfaces (light) -------------------------------------------------- */
	--ize-mo-ink-ripple: rgba(0, 0, 0, .10);
	--ize-mo-ink-press:  rgba(0, 0, 0, .06);
	--ize-mo-scrim:      rgba(0, 0, 0, .40);
	--ize-mo-elev-1: 0 1px 2px rgba(17, 24, 39, .08);
	--ize-mo-elev-2: 0 4px 12px rgba(17, 24, 39, .12);
	--ize-mo-elev-3: 0 12px 28px rgba(17, 24, 39, .18);
}

/* Dark. WoWonder signals dark ONLY by injecting <link id="night-mode-css">
   (there is no body class), so key off that — same idiom as ize-post-sheet.css,
   correct on first paint with no JS. */
html:has(#night-mode-css),
html.ize-dark {
	--ize-mo-ink-ripple: rgba(255, 255, 255, .13);
	--ize-mo-ink-press:  rgba(255, 255, 255, .08);
	--ize-mo-scrim:      rgba(0, 0, 0, .60);
	--ize-mo-elev-1: 0 1px 2px rgba(0, 0, 0, .40);
	--ize-mo-elev-2: 0 4px 12px rgba(0, 0, 0, .48);
	--ize-mo-elev-3: 0 12px 28px rgba(0, 0, 0, .58);
}

/* ---- Policy: device / network (IzeXM sets .ize-lean on <html>) ------------ */
/* Not "no motion": a cheap phone still needs the feedback, it just cannot
   afford long ones. Ambient decoration is the part that stops. */
html.ize-lean {
	--ize-mo-scale: .75;
	--ize-mo-ambient-play: paused;
}

/* ---- Policy: accessibility ------------------------------------------------ */
/* .01 rather than 0: a zero-duration transition fires no transitionend in most
   engines, which would strand any JS awaiting one. 320ms * .01 = 3.2ms — below
   perception, still a real animation. Ambient loops stop outright.
   MUST come after the .ize-lean block and MUST repeat its selector: a bare
   `:root` here (0,1,0) would lose to `html.ize-lean` (0,1,1), so a lean device
   whose owner asked for Reduce Motion would still get full-length animations.
   Same selector, later in the file — the user's accessibility choice wins. */
@media (prefers-reduced-motion: reduce) {
	:root,
	html.ize-lean {
		--ize-mo-scale: .01;
		--ize-mo-ambient-play: paused;
	}
}

/* ---- Policy: kill switch -------------------------------------------------- */
/* Last, and matches the other policy selectors, so it always wins. Set by
   IzeMotion.setEnabled(false), by a future user preference, or by hand while
   debugging a rendering problem. */
html.ize-mo-off,
html.ize-mo-off.ize-lean {
	--ize-mo-scale: .01;
	--ize-mo-ambient-play: paused;
}

/* =============================================================================
   LAYER 1 — PRIMITIVES
   Opt-in classes. Each one is a complete, named piece of the motion language.
   ========================================================================== */

/* ---------- Press: "the surface acknowledged my finger" --------------------- */
/* Two ways in, same result:
     .ize-mo-press            — pure CSS, uses :active. Zero JS.
     .ize-mo-press + JS       — ize-motion.js adds .ize-mo-pressed on pointerdown
                                and clears it on scroll/cancel. Preferred on
                                touch, where :active is sticky and can survive a
                                scroll, leaving a button visibly stuck.
   Release is deliberately slower than press and uses the spring: a finger
   lifting should feel like something rebounding, not like a value snapping. */
.ize-mo-press {
	transition: transform var(--ize-mo-t-quick) var(--ize-mo-e-spring),
	            opacity   var(--ize-mo-t-fast)  var(--ize-mo-e-standard);
	-webkit-tap-highlight-color: transparent;
}

.ize-mo-press:active,
.ize-mo-press.ize-mo-pressed {
	transform: scale(var(--ize-mo-press));
	transition-duration: var(--ize-mo-t-instant), var(--ize-mo-t-instant);
	transition-timing-function: var(--ize-mo-e-standard), var(--ize-mo-e-standard);
}

.ize-mo-press-sm:active,
.ize-mo-press-sm.ize-mo-pressed { transform: scale(var(--ize-mo-press-sm)); }

.ize-mo-press-lg:active,
.ize-mo-press-lg.ize-mo-pressed { transform: scale(var(--ize-mo-press-lg)); }

/* Media / imagery cannot scale (it would reveal the edge of the layout), so it
   dims instead. Same message, different vocabulary. `transform: none` is load
   bearing: this variant is applied ALONGSIDE the base class, which would
   otherwise still scale the element at equal specificity. */
.ize-mo-press-dim:active,
.ize-mo-press-dim.ize-mo-pressed {
	transform: none;
	opacity: var(--ize-mo-dim);
}

/* ---------- Ripple: "the touch happened HERE" ------------------------------ */
/* One implementation for the whole product, replacing izeRipple / ize-ps-ripple
   / ize-sc-ripple / ize-ncall-ripple. The ink node is created and positioned by
   ize-motion.js (one reused node per host, never a node per press) and animated
   with the Web Animations API, so this file only owns its look. */
.ize-mo-ink {
	position: absolute;
	border-radius: 50%;
	background: var(--ize-mo-ink-ripple);
	pointer-events: none;
	/* Resting state. The animation uses fill:none, so the ink returns here and
	   sits invisible until the next press — which is why one node per host can
	   be reused instead of created and destroyed per touch. */
	opacity: 0;
	transform: scale(0);
	/* Isolate the ink's paint from the host's; it is decoration and must never
	   drag its parent into a larger invalidation. NOT `strict` — that would add
	   size containment, and the ink's size is set per press. */
	contain: layout style paint;
	/* Deliberately NO will-change: this node is permanent (one per rippling
	   button), and a permanent will-change would mean a permanent compositor
	   layer per button. The WAAPI transform/opacity animation gets promoted
	   for its duration on its own. */
}

/* Hosts must clip and position their ink. Applied by the component, not here,
   so we never change the box model of an element we do not own. */
.ize-mo-ripple-host {
	position: relative;
	overflow: hidden;
	-webkit-tap-highlight-color: transparent;
}

/* ---------- Enter / exit ---------------------------------------------------- */
/* Nothing appears; things arrive. Nothing vanishes; things leave.
   `both` fill on exits only — an entrance must leave the element in its natural
   resting state so a cancelled animation can never strand it invisible. */
.ize-mo-in-fade  { animation: ize-mo-fade-in  var(--ize-mo-t-quick)  var(--ize-mo-e-enter); }
.ize-mo-in-rise  { animation: ize-mo-rise-in  var(--ize-mo-t-normal) var(--ize-mo-e-enter); }
.ize-mo-in-scale { animation: ize-mo-scale-in var(--ize-mo-t-normal) var(--ize-mo-e-enter); }
.ize-mo-in-drop  { animation: ize-mo-drop-in  var(--ize-mo-t-normal) var(--ize-mo-e-enter); }
.ize-mo-in-page  { animation: ize-mo-page-in  var(--ize-mo-t-page)   var(--ize-mo-e-enter); }

.ize-mo-out-fade  { animation: ize-mo-fade-out  var(--ize-mo-t-fast)  var(--ize-mo-e-exit) both; }
.ize-mo-out-sink  { animation: ize-mo-sink-out  var(--ize-mo-t-quick) var(--ize-mo-e-exit) both; }
.ize-mo-out-scale { animation: ize-mo-scale-out var(--ize-mo-t-quick) var(--ize-mo-e-exit) both; }

/* Stagger: set --ize-mo-i to the item index. 34ms is short enough that a list
   still reads as one gesture rather than a queue; capped by the caller. */
.ize-mo-stagger { animation-delay: calc(var(--ize-mo-i, 0) * 34ms * var(--ize-mo-scale)); }

/* ---------- Acknowledgement ------------------------------------------------ */
.ize-mo-pop   { animation: ize-mo-pop   var(--ize-mo-t-normal) var(--ize-mo-e-spring); }
.ize-mo-shake { animation: ize-mo-shake var(--ize-mo-t-slower) var(--ize-mo-e-standard); }
.ize-mo-bump  { animation: ize-mo-bump  var(--ize-mo-t-quick)  var(--ize-mo-e-spring-lg); }

/* ---------- Ambient: idle life, never attention ---------------------------- */
/* Every loop below obeys --ize-mo-ambient-play. That is the whole reason these
   are here rather than in the components: one property stops all idle motion on
   a battery-saver phone, in a background tab, or under Reduce Motion. */
.ize-mo-breathe {
	animation: ize-mo-breathe var(--ize-mo-t-breathe) var(--ize-mo-e-standard) infinite;
	animation-play-state: var(--ize-mo-ambient-play);
}

.ize-mo-pulse {
	animation: ize-mo-pulse var(--ize-mo-t-pulse) var(--ize-mo-e-standard) infinite;
	animation-play-state: var(--ize-mo-ambient-play);
}

/* The one documented exception to "transform and opacity only": a skeleton
   shimmer has to travel across a background, and the alternative (a sliding
   pseudo-element) needs an extra node on every placeholder in a list. The
   repaint is confined to the placeholder's own small box, and it is paused
   wholesale on lean devices — which is the case that would have paid for it. */
.ize-mo-shimmer {
	background-image: linear-gradient(90deg,
	                  rgba(255, 255, 255, 0) 0,
	                  rgba(255, 255, 255, .45) 45%,
	                  rgba(255, 255, 255, 0) 90%);
	background-size: 300% 100%;
	animation: ize-mo-shimmer var(--ize-mo-t-shimmer) linear infinite;
	animation-play-state: var(--ize-mo-ambient-play);
}

html:has(#night-mode-css) .ize-mo-shimmer,
html.ize-dark .ize-mo-shimmer {
	background-image: linear-gradient(90deg,
	                  rgba(255, 255, 255, 0) 0,
	                  rgba(255, 255, 255, .09) 45%,
	                  rgba(255, 255, 255, 0) 90%);
}

/* THE spinner. One definition to replace fifteen. Linear is correct here and
   nowhere else: a rotating loader must not appear to hesitate each turn. */
.ize-mo-spin {
	animation: ize-mo-spin var(--ize-mo-t-spin) linear infinite;
	animation-play-state: var(--ize-mo-ambient-play);
}

/* ---------- Loading -> content --------------------------------------------- */
/* Content never snaps in over a placeholder; it crossfades. Applied by
   IzeMotion.crossfade() so the swap itself stays the component's business. */
.ize-mo-crossfade { animation: ize-mo-fade-in var(--ize-mo-t-quick) var(--ize-mo-e-standard); }

/* Images: fade in once decoded instead of painting top-down. The .ize-mo-img
   class is set on the element and removed by JS on load, so a cached image that
   is already complete never animates at all (no flash on a warm page). */
.ize-mo-img { opacity: 0; }
.ize-mo-img.ize-mo-img-in {
	opacity: 1;
	transition: opacity var(--ize-mo-t-normal) var(--ize-mo-e-standard);
}

/* ---------- Surfaces: the shared sheet / dialog motion contract ------------- */
/* IzeMotion.sheet() drives these classes. ize-post-sheet.css already implements
   exactly this timing by hand; when it migrates it deletes its copy and keeps
   its looks. Corner radius, colour and padding stay with the component — this
   is motion only. */
/* Mount contract: the root is out of the layout entirely until opened, so a
   closed sheet costs nothing and can never intercept a tap. IzeMotion.sheet()
   adds/removes .ize-mo-mounted; the component owns position, z-index and size. */
.ize-mo-sheet-root { display: none; }
.ize-mo-sheet-root.ize-mo-mounted { display: block; }

.ize-mo-scrim-el {
	opacity: 0;
	transition: opacity var(--ize-mo-t-quick) var(--ize-mo-e-linear);
}
.ize-mo-open  > .ize-mo-scrim-el { opacity: 1; }
.ize-mo-close > .ize-mo-scrim-el { opacity: 0; transition-duration: var(--ize-mo-t-fast); }

.ize-mo-surface-sheet {
	transform: translate3d(0, 100%, 0);
	opacity: 0;
}
.ize-mo-open > .ize-mo-surface-sheet {
	transform: translate3d(0, 0, 0);
	opacity: 1;
	transition: transform var(--ize-mo-t-slow) var(--ize-mo-e-enter),
	            opacity   var(--ize-mo-t-fast) var(--ize-mo-e-linear);
}
.ize-mo-close > .ize-mo-surface-sheet {
	transform: translate3d(0, 100%, 0);
	opacity: 0;
	transition: transform var(--ize-mo-t-normal) var(--ize-mo-e-exit),
	            opacity   var(--ize-mo-t-quick)  var(--ize-mo-e-linear);
}
/* Finger down: the surface tracks 1:1, so no transition may interfere. */
.ize-mo-drag > .ize-mo-surface-sheet { transition: none; }
/* Released above the dismiss threshold: springs back, faster than a cold open
   or it feels like it is being dragged home by hand. */
.ize-mo-snap > .ize-mo-surface-sheet {
	transition: transform var(--ize-mo-t-normal) var(--ize-mo-e-enter);
}

.ize-mo-surface-dialog {
	transform: scale(.92);
	opacity: 0;
}
.ize-mo-open > .ize-mo-surface-dialog {
	transform: scale(1);
	opacity: 1;
	transition: transform var(--ize-mo-t-normal) var(--ize-mo-e-enter),
	            opacity   var(--ize-mo-t-fast)   var(--ize-mo-e-linear);
}
.ize-mo-close > .ize-mo-surface-dialog {
	transform: scale(.96);
	opacity: 0;
	transition: transform var(--ize-mo-t-quick) var(--ize-mo-e-exit),
	            opacity   var(--ize-mo-t-fast)  var(--ize-mo-e-linear);
}

/* Page scroll lock used by every modal surface. Never moves the page, so
   dismissing lands the reader exactly where they were. */
html.ize-mo-lock,
body.ize-mo-lock { overflow: hidden; }

/* ---------- Gesture helper -------------------------------------------------- */
/* Promote to its own layer for the DURATION of a drag only. Applied and removed
   by JS. Never leave this on an element: a permanent compositor layer costs
   memory, and — the reason it matters here — an element with will-change:
   transform becomes the containing block for its position:fixed children. */
.ize-mo-lift { will-change: transform; }

/* =============================================================================
   KEYFRAMES  (canonical — components must not define their own equivalents)
   ========================================================================== */
@keyframes ize-mo-fade-in   { from { opacity: 0; } to { opacity: 1; } }
@keyframes ize-mo-fade-out  { from { opacity: 1; } to { opacity: 0; } }

@keyframes ize-mo-rise-in {
	from { opacity: 0; transform: translate3d(0, var(--ize-mo-rise), 0); }
	to   { opacity: 1; transform: none; }
}

@keyframes ize-mo-drop-in {
	from { opacity: 0; transform: translate3d(0, calc(var(--ize-mo-rise) * -1), 0); }
	to   { opacity: 1; transform: none; }
}

@keyframes ize-mo-sink-out {
	from { opacity: 1; transform: none; }
	to   { opacity: 0; transform: translate3d(0, var(--ize-mo-rise), 0); }
}

@keyframes ize-mo-scale-in {
	from { opacity: 0; transform: scale(.94); }
	to   { opacity: 1; transform: none; }
}

@keyframes ize-mo-scale-out {
	from { opacity: 1; transform: none; }
	to   { opacity: 0; transform: scale(.96); }
}

/* Page enter: smaller travel than a card. A whole screen sliding 8px reads as
   the app being sure of itself; 16px reads as a website. */
@keyframes ize-mo-page-in {
	from { opacity: 0; transform: translate3d(0, 6px, 0); }
	to   { opacity: 1; transform: none; }
}

@keyframes ize-mo-pop {
	0%   { transform: scale(1); }
	42%  { transform: scale(var(--ize-mo-pop)); }
	100% { transform: scale(1); }
}

@keyframes ize-mo-bump {
	0%   { transform: scale(1); }
	50%  { transform: scale(1.22); }
	100% { transform: scale(1); }
}

/* Error. Horizontal only, decaying, and short — a shake that overstays reads as
   the app being upset rather than the field being wrong. */
@keyframes ize-mo-shake {
	0%, 100% { transform: translate3d(0, 0, 0); }
	18%      { transform: translate3d(-7px, 0, 0); }
	38%      { transform: translate3d( 6px, 0, 0); }
	58%      { transform: translate3d(-4px, 0, 0); }
	78%      { transform: translate3d( 2px, 0, 0); }
}

@keyframes ize-mo-breathe {
	0%, 100% { transform: scale(1);    opacity: 1;   }
	50%      { transform: scale(1.03); opacity: .92; }
}

@keyframes ize-mo-pulse {
	0%, 100% { transform: scale(1);    }
	50%      { transform: scale(1.06); }
}

@keyframes ize-mo-shimmer {
	from { background-position: 150% 0; }
	to   { background-position: -150% 0; }
}

@keyframes ize-mo-spin {
	from { transform: rotate(0deg);   }
	to   { transform: rotate(360deg); }
}

/* The ripple's shape lives here even though JS drives it, so a component can
   fall back to a class-only ripple where a listener would be wasteful. */
@keyframes ize-mo-ripple {
	0%   { opacity: 1; transform: scale(0);  }
	100% { opacity: 0; transform: scale(1);  }
}
