/* TailMotion v0.8.0 — tailmotion.css | Generated 2026-08-24T13:00:26.616Z */
/* Entry point for TailMotion.

   base.css pulls in the shared token layer and the motion profiles, so it must
   stay first: everything below reads those tokens. */

/* --- src/animations/base.css --- */
/* --------------------------------------------------------------------------
   TailMotion base layer

   Tailwind owns the interface design. TailMotion owns only the movement.

   The token layer lives in ../shared/tokens.css and is shared with every
   optional module, so a module can be imported on its own. This file adds the
   element-level utilities that override those tokens.

   Timing tokens (--tm-duration, --tm-delay, --tm-easing,
   --tm-iteration-count) are deliberately NOT given root values: every motion
   class carries its own tuned default, written as

     var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1)))

   so an explicit --tm-duration replaces the class default outright, while an
   inherited motion profile only scales it. A root --tm-duration value would
   shadow every one of those defaults, which is why there is none. Set the
   tokens per element with the tm-duration, tm-delay, tm-ease and tm-repeat
   utilities, the Tailwind plugin, or an inline style.
   -------------------------------------------------------------------------- */


/* --- src/shared/tokens.css --- */
/* --------------------------------------------------------------------------
   TailMotion token layer.

   Everything TailMotion animates reads from these four groups:

     1. Explicit overrides  --tm-duration, --tm-delay, --tm-easing,
                            --tm-iteration-count. Deliberately unset, so each
                            motion class keeps its own tuned default. Set them
                            per element with tm-duration-*, tm-delay-*,
                            tm-ease-*, tm-repeat-*, the Tailwind plugin, or an
                            inline style. An explicit value always wins.

     2. Profile factors     --tm-duration-scale, --tm-emphasis, --tm-overshoot.
                            Inherited multipliers. A motion personality
                            (tm-motion-calm / -productive / -expressive)
                            retunes a whole subtree by changing these, and each
                            animation keeps its relative character because it
                            multiplies its own default rather than being
                            replaced by a global one.

     3. Shared scalars      --tm-distance, --tm-stagger-step. One value each,
                            already shared by every class that uses them, so a
                            profile sets them outright.

     4. Role easings        --tm-ease-entrance, --tm-ease-exit,
                            --tm-ease-interaction, --tm-ease-emphasis. Classes
                            opt into a role; a profile retunes the role.
                            Animations with a character of their own (linear
                            spins, ambient drifts) stay out of this and keep
                            their literal curve.

   This file carries no selectors of its own beyond :root, so a module can
   import it and stand alone.
   -------------------------------------------------------------------------- */

@layer base {
  :root,
  :host {
    /* --- Profile factors ------------------------------------------------ */

    /* Multiplies every animation's own default duration. */
    --tm-duration-scale: 1;

    /* Multiplies how far a keyframe departs from its resting value: the 0.85
       start scale of tm-pop, the blur of tm-blur-in. 0 removes the departure
       entirely, so keep it above 0 unless the motion should become a pure
       fade. */
    --tm-emphasis: 1;

    /* Multiplies only the frames that travel *past* the resting value: the
       1.05 peak of tm-pop, the settle of tm-drop. 0 removes overshoot without
       touching the entrance itself. */
    --tm-overshoot: 1;

    /* --- Shared scalars ------------------------------------------------- */

    /* Choreography */
    --tm-stagger-step: 100ms;

    /* Travel distance. Exits travel 70% of an entrance, resolved at the point
       of use so tm-distance-* retunes entrances and exits together. */
    --tm-distance: 12px;

    /* Sign of inline-axis motion: 1 in LTR, -1 in RTL. */
    --tm-inline-flip: 1;

    /* --- Role easings --------------------------------------------------- */

    /* Arriving: decelerate into place. Anything that enters or leaves the
       screen wants an ease-out, entrances and exits alike -- an ease-in exit
       delays the visual feedback and reads as sluggish. */
    --tm-ease-entrance: cubic-bezier(0.22, 1, 0.36, 1);

    /* Leaving: the same family, weaker, because the exit should not perform. */
    --tm-ease-exit: cubic-bezier(0.25, 0.46, 0.45, 0.94);

    /* Responding to a pointer or key, where the target can change mid-flight. */
    --tm-ease-interaction: cubic-bezier(0.25, 0.46, 0.45, 0.94);

    /* Moving or reshaping something that is already on screen: accelerate out
       of the old position, brake into the new one. */
    --tm-ease-morph: cubic-bezier(0.2, 0, 0, 1);

    /* Celebrating: the only curve that is allowed to overshoot. */
    --tm-ease-emphasis: cubic-bezier(0.34, 1.56, 0.64, 1);

    /* --- Effect colors --------------------------------------------------
       TailMotion ships no palette: every effect inherits the consumer's color
       and every token can be replaced with an exact value, alpha included. */
    --tm-color: currentColor;
    --tm-shadow-color: color-mix(in oklab, var(--tm-color) 25%, transparent);
    --tm-glow-color: color-mix(in oklab, var(--tm-color) 45%, transparent);
    --tm-outline-color: color-mix(in oklab, var(--tm-color) 40%, transparent);

    /* The shimmer highlight keeps its color and its strength apart: browsers
       drop gradient interpolation hints from any gradient holding a
       color-mix() stop, so strength lives in --tm-shimmer-opacity instead. */
    --tm-shimmer-color: var(--tm-color);
    --tm-shimmer-opacity: 0.35;
  }

  /* Safe fallback where color-mix() is unavailable. */
  @supports not (color: color-mix(in oklab, currentColor, transparent)) {
    :root,
    :host {
      --tm-shadow-color: var(--tm-color);
      --tm-glow-color: var(--tm-color);
      --tm-outline-color: var(--tm-color);
    }
  }

  /* Mirror inline-axis motion in right-to-left contexts. */
  [dir="ltr"] {
    --tm-inline-flip: 1;
  }

  [dir="rtl"] {
    --tm-inline-flip: -1;
  }

  @supports selector(:dir(rtl)) {
    [dir="auto"]:dir(ltr) {
      --tm-inline-flip: 1;
    }

    [dir="auto"]:dir(rtl) {
      --tm-inline-flip: -1;
    }
  }

  /* Motion is supplementary feedback. When it is not wanted, every animation
     lands on its final state immediately instead of being skipped, so the
     state a class communicates stays visible. Container classes that animate
     unclassed children are listed explicitly.

     Scroll-driven classes are progress-linked rather than time-linked, so a
     1ms duration would not stop them. They are switched off in
     src/scroll/scroll.css instead, which leaves their subject at its natural,
     visible state. */
  @media (prefers-reduced-motion: reduce) {
    [class*="tm-"],
    [class*="tm-"]::before,
    [class*="tm-"]::after,
    .tm-stagger > *,
    .tm-count-reveal > *,
    .tm-icon-swap > *,
    .tm-view-morph > [data-tm-panel],
    .tm-text-flip-chars > span {
      animation-duration: 1ms !important;
      animation-delay: 0ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 1ms !important;
      transition-delay: 0ms !important;
    }

    /* Kept apart: a selector list is discarded whole if a browser cannot parse
       one of its parts, and ::backdrop is younger than the rule above. */
    [class*="tm-"]::backdrop {
      animation-duration: 1ms !important;
      animation-delay: 0ms !important;
      transition-duration: 1ms !important;
      transition-delay: 0ms !important;
    }
  }
}


/* --- src/profiles/profiles.css --- */
/* --------------------------------------------------------------------------
   Motion personalities.

   One class on an ancestor retunes every TailMotion descendant. The animation
   classes themselves never change:

     <main class="tm-motion-calm">
       <button class="tm-press">Save</button>
       <div class="tm-slide-block-start">Saved</div>
     </main>

   How the override order works, from weakest to strongest:

     1. Each animation's own tuned default, multiplied by the inherited
        --tm-duration-scale and shaped by the inherited role easing.
     2. A nearer profile scope, because these are plain inherited custom
        properties: the closest ancestor that sets them wins.
     3. An element-level utility -- tm-duration-*, tm-delay-*, tm-ease-*,
        tm-repeat-*, tm-distance-*, tm-stagger-step-* -- because it sets
        --tm-duration, --tm-easing or --tm-distance directly on the element,
        and those are read *before* the profile factors, not multiplied by
        them.

   A profile changes feel, not vocabulary. tm-pop stays livelier than
   tm-fade-in in all three, because each keeps its own base timing and only
   the multiplier moves.
   -------------------------------------------------------------------------- */

@layer utilities {
  /* Settings, dashboards, finance, long-form content. Short travel, no
     overshoot, curves that only decelerate. Motion here confirms a change
     without asking to be watched. */
  .tm-motion-calm {
    --tm-duration-scale: 1.1;
    --tm-emphasis: 0.55;
    --tm-overshoot: 0;
    --tm-distance: 8px;
    --tm-stagger-step: 70ms;

    --tm-ease-entrance: cubic-bezier(0.25, 0.9, 0.35, 1);
    --tm-ease-exit: cubic-bezier(0.33, 0.6, 0.5, 1);
    --tm-ease-interaction: cubic-bezier(0.33, 0.6, 0.5, 1);
    --tm-ease-morph: cubic-bezier(0.35, 0, 0.15, 1);
    /* Emphasis still exists here, it simply stops overshooting. */
    --tm-ease-emphasis: cubic-bezier(0.22, 1, 0.36, 1);
  }

  /* The recommended default for product UI. Feedback arrives fast, movement
     stays small, and the state change is the loudest thing on screen. */
  .tm-motion-productive {
    --tm-duration-scale: 0.85;
    --tm-emphasis: 0.85;
    --tm-overshoot: 0.6;
    --tm-distance: 10px;
    --tm-stagger-step: 55ms;

    --tm-ease-entrance: cubic-bezier(0.22, 1, 0.36, 1);
    --tm-ease-exit: cubic-bezier(0.25, 0.46, 0.45, 0.94);
    --tm-ease-interaction: cubic-bezier(0.25, 0.46, 0.45, 0.94);
    --tm-ease-morph: cubic-bezier(0.2, 0, 0, 1);
    --tm-ease-emphasis: cubic-bezier(0.3, 1.35, 0.5, 1);
  }

  /* Onboarding, marketing, milestones, celebration. Travel is larger and the
     curves are allowed to spring, but the motion still settles rather than
     oscillating. */
  .tm-motion-expressive {
    --tm-duration-scale: 1.2;
    --tm-emphasis: 1.35;
    --tm-overshoot: 1.3;
    --tm-distance: 22px;
    --tm-stagger-step: 110ms;

    --tm-ease-entrance: cubic-bezier(0.16, 1.16, 0.3, 1);
    --tm-ease-exit: cubic-bezier(0.2, 0.7, 0.4, 1);
    --tm-ease-interaction: cubic-bezier(0.2, 1.2, 0.4, 1);
    --tm-ease-morph: cubic-bezier(0.16, 0.2, 0, 1);
    --tm-ease-emphasis: cubic-bezier(0.34, 1.7, 0.5, 1);
  }

  /* Return a subtree to the library defaults, for a region that should not
     inherit a surrounding personality. */
  .tm-motion-default {
    --tm-duration-scale: 1;
    --tm-emphasis: 1;
    --tm-overshoot: 1;
    --tm-distance: 12px;
    --tm-stagger-step: 100ms;

    --tm-ease-entrance: cubic-bezier(0.22, 1, 0.36, 1);
    --tm-ease-exit: cubic-bezier(0.25, 0.46, 0.45, 0.94);
    --tm-ease-interaction: cubic-bezier(0.25, 0.46, 0.45, 0.94);
    --tm-ease-morph: cubic-bezier(0.2, 0, 0, 1);
    --tm-ease-emphasis: cubic-bezier(0.34, 1.56, 0.64, 1);
  }

  /* Profile factors as standalone utilities, for the case where a subtree
     needs one axis of a personality and not the rest. */
  .tm-emphasis-0 {
    --tm-emphasis: 0;
    --tm-overshoot: 0;
  }

  .tm-emphasis-50 {
    --tm-emphasis: 0.5;
    --tm-overshoot: 0.5;
  }

  .tm-emphasis-100 {
    --tm-emphasis: 1;
    --tm-overshoot: 1;
  }

  .tm-emphasis-150 {
    --tm-emphasis: 1.5;
    --tm-overshoot: 1.5;
  }

  .tm-no-overshoot {
    --tm-overshoot: 0;
  }

  .tm-speed-75 {
    --tm-duration-scale: 0.75;
  }

  .tm-speed-100 {
    --tm-duration-scale: 1;
  }

  .tm-speed-125 {
    --tm-duration-scale: 1.25;
  }

  .tm-speed-150 {
    --tm-duration-scale: 1.5;
  }
}


@layer utilities {
  .tm-perspective {
    perspective: 1200px;
  }

  .tm-3d {
    transform-style: preserve-3d;
    backface-visibility: hidden;
  }

  /* Opt-in GPU promotion. TailMotion does not promote elements permanently on
     its own: add this only where you have measured first-frame stutter. */
  .tm-gpu {
    will-change: transform, opacity, filter;
  }

  .tm-motion-paused {
    animation-play-state: paused !important;
  }

  .tm-motion-running {
    animation-play-state: running !important;
  }

  .tm-motion-reset {
    --tm-delay: 0ms;
    --tm-iteration-count: 1;
  }

  /* Duration tokens */
  .tm-duration-150 {
    --tm-duration: 150ms;
  }

  .tm-duration-200 {
    --tm-duration: 200ms;
  }

  .tm-duration-300 {
    --tm-duration: 300ms;
  }

  .tm-duration-400 {
    --tm-duration: 400ms;
  }

  .tm-duration-500 {
    --tm-duration: 500ms;
  }

  .tm-duration-700 {
    --tm-duration: 700ms;
  }

  .tm-duration-900 {
    --tm-duration: 900ms;
  }

  .tm-duration-1000 {
    --tm-duration: 1000ms;
  }

  .tm-duration-1200 {
    --tm-duration: 1200ms;
  }

  .tm-duration-1400 {
    --tm-duration: 1400ms;
  }

  .tm-duration-1600 {
    --tm-duration: 1600ms;
  }

  .tm-duration-2000 {
    --tm-duration: 2000ms;
  }

  .tm-duration-3000 {
    --tm-duration: 3000ms;
  }

  /* Delay tokens */
  .tm-delay-0 {
    --tm-delay: 0ms;
  }

  .tm-delay-75 {
    --tm-delay: 75ms;
  }

  .tm-delay-150 {
    --tm-delay: 150ms;
  }

  .tm-delay-200 {
    --tm-delay: 200ms;
  }

  .tm-delay-300 {
    --tm-delay: 300ms;
  }

  .tm-delay-400 {
    --tm-delay: 400ms;
  }

  .tm-delay-500 {
    --tm-delay: 500ms;
  }

  .tm-delay-700 {
    --tm-delay: 700ms;
  }

  .tm-delay-1000 {
    --tm-delay: 1000ms;
  }

  /* Easing tokens */
  .tm-ease-linear {
    --tm-easing: linear;
  }

  .tm-ease-in {
    --tm-easing: cubic-bezier(0.55, 0.085, 0.68, 0.53);
  }

  .tm-ease-out {
    --tm-easing: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  }

  .tm-ease-in-out {
    --tm-easing: cubic-bezier(0.645, 0.045, 0.355, 1);
  }

  .tm-ease-soft {
    --tm-easing: cubic-bezier(0.4, 0, 0.2, 1);
  }

  .tm-ease-snappy {
    --tm-easing: cubic-bezier(0.34, 1.56, 0.64, 1);
  }

  .tm-ease-bouncy {
    --tm-easing: cubic-bezier(0.68, -0.55, 0.265, 1.55);
  }

  /* Repeat helpers */
  .tm-repeat-1 {
    --tm-iteration-count: 1;
  }

  .tm-repeat-2 {
    --tm-iteration-count: 2;
  }

  .tm-repeat-3 {
    --tm-iteration-count: 3;
  }

  .tm-repeat-infinite {
    --tm-iteration-count: infinite;
  }

  /* Stagger step tokens, for .tm-stagger containers. A motion profile also
     sets --tm-stagger-step; these are declared after the profiles, so putting
     both on one element leaves the explicit step in charge. */
  .tm-stagger-step-50 {
    --tm-stagger-step: 50ms;
  }

  .tm-stagger-step-75 {
    --tm-stagger-step: 75ms;
  }

  .tm-stagger-step-100 {
    --tm-stagger-step: 100ms;
  }

  .tm-stagger-step-150 {
    --tm-stagger-step: 150ms;
  }

  .tm-stagger-step-200 {
    --tm-stagger-step: 200ms;
  }

  /* Travel distance tokens. Every slide, exit and presence offset derives from
     --tm-distance, and --tm-exit-distance is resolved where it is used rather
     than on :root, so one utility retunes entrances and exits together. A
     motion profile sets --tm-distance too; these come later in the sheet, so
     an explicit distance wins even on the same element. */
  .tm-distance-4 {
    --tm-distance: 4px;
  }

  .tm-distance-8 {
    --tm-distance: 8px;
  }

  .tm-distance-12 {
    --tm-distance: 12px;
  }

  .tm-distance-20 {
    --tm-distance: 20px;
  }

  .tm-distance-30 {
    --tm-distance: 30px;
  }
}


/* --- src/presence/presence.css --- */
/* --------------------------------------------------------------------------
   State-driven presence.

   These classes animate between the open and closed states your application
   or headless UI library already manages. TailMotion never mounts, unmounts
   or toggles anything: it reads the state you already set.

     <div class="tm-presence-pop" data-state="open">Menu content</div>

   Recognised state contracts, on the element itself:

     data-state="open"      / "closed"
     data-state="active"    / "inactive"      (tabs)
     data-state="checked"   / "unchecked"     (checkbox, switch)
     data-state="on"        / "off"           (toggle)
     aria-expanded="true"   / "false"
     aria-pressed="true"    / "false"
     aria-checked="true"    / "false"
     class="tm-open"        / "tm-closed"

   An element with no recognised state is treated as open. That is deliberate:
   a missing or misspelled attribute leaves content visible rather than
   invisible.

   Everything here is a transition, not a keyframe, so reversing state
   mid-flight retargets from the current position instead of snapping back to
   the start. Interruptibility is the whole point of the module.

   Shape of the code: the open state is the base rule, and one closed rule
   reads two per-variant custom properties. Each variant class then only
   declares where "closed" is. That keeps the state contract written down
   once, so it cannot drift between variants.

   Mounting contract: a closed element must stay in the DOM until its closed
   transition finishes, otherwise there is nothing left to animate. React, Vue
   and Svelte examples are in the README. The closed state ends on
   `visibility: hidden`, so a closed element is neither clickable nor
   announced by a screen reader while it waits.

   Every class animates `opacity`, `translate` and `scale` -- never
   `transform` -- so a Tailwind `rotate-*`, `-translate-*` or `skew-*` on the
   same element survives.
   -------------------------------------------------------------------------- */


/* --- src/shared/tokens.css (already inlined) --- */


@layer utilities {
  /* Open. Also the resting state of an element with no state attribute. */
  .tm-presence-fade,
  .tm-presence-scale,
  .tm-presence-pop,
  .tm-presence-slide-block,
  .tm-presence-slide-inline {
    opacity: 1;
    visibility: visible;
    translate: 0 0;
    scale: 1;
    transition-property: opacity, visibility, translate, scale;
    transition-duration: var(--tm-duration, calc(var(--tm-presence-duration, 220ms) * var(--tm-duration-scale, 1)));
    transition-delay: var(--tm-delay, 0ms);
    transition-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    transform-origin: var(--tm-origin, center);
  }

  /* Closed. Softer and shorter than the entrance -- the user has already
     decided, so the exit gets out of the way rather than performing.
     --tm-presence-exit-scale (0.7) sets that ratio; --tm-exit-duration
     replaces it outright. */
  :is(
      .tm-presence-fade,
      .tm-presence-scale,
      .tm-presence-pop,
      .tm-presence-slide-block,
      .tm-presence-slide-inline
    ):is(
      [data-state="closed"],
      [data-state="inactive"],
      [data-state="unchecked"],
      [data-state="off"],
      [aria-expanded="false"],
      [aria-pressed="false"],
      [aria-checked="false"],
      .tm-closed
    ) {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    translate: var(--tm-presence-closed-translate, 0 0);
    scale: var(--tm-presence-closed-scale, 1);
    transition-duration: var(
      --tm-exit-duration,
      calc(
        var(
            --tm-duration,
            calc(var(--tm-presence-duration, 220ms) * var(--tm-duration-scale, 1))
          ) * var(--tm-presence-exit-scale, 0.7)
      )
    );
    transition-timing-function: var(--tm-easing, var(--tm-ease-exit, cubic-bezier(0.25, 0.46, 0.45, 0.94)));
  }

  /* --- Where "closed" is, per variant ---------------------------------
     Every variant sets both properties, including the ones it does not use,
     so a presence element nested inside another cannot inherit its parent's
     closed position. */

  /* Opacity only. The safest default: nothing moves, so it composes with any
     layout and never fights a positioned popper. */
  .tm-presence-fade {
    --tm-presence-closed-translate: 0 0;
    --tm-presence-closed-scale: 1;
    --tm-presence-duration: 180ms;
  }

  /* Settles up from slightly small. Never overshoots. */
  .tm-presence-scale {
    --tm-presence-closed-translate: 0 0;
    --tm-presence-closed-scale: calc(1 - 0.04 * var(--tm-emphasis, 1));
    --tm-presence-duration: 220ms;
  }

  /* Springs open. The overshoot lives in the easing rather than a keyframe, so
     it stays interruptible; a profile with --tm-overshoot: 0 flattens it back
     to a decelerating curve. */
  .tm-presence-pop {
    --tm-presence-closed-translate: 0 0;
    --tm-presence-closed-scale: calc(1 - 0.1 * var(--tm-emphasis, 1));
    --tm-presence-duration: 260ms;
    transition-timing-function: var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1)));
  }

  .tm-no-overshoot .tm-presence-pop,
  .tm-motion-calm .tm-presence-pop {
    transition-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
  }

  /* Travels on the block axis. --tm-presence-direction picks the edge it
     starts from: -1 (default) starts toward block-start and drops into place,
     the shape a menu below its trigger wants; 1 starts toward block-end and
     rises. Use tm-presence-from-start / tm-presence-from-end rather than
     remembering the sign. */
  .tm-presence-slide-block {
    --tm-presence-closed-translate: 0
      calc(var(--tm-distance, 12px) * var(--tm-presence-direction, -1));
    --tm-presence-closed-scale: 1;
    --tm-presence-duration: 240ms;
  }

  /* Travels on the inline axis, mirrored in right-to-left contexts:
     "start" is the left edge in LTR and the right edge in RTL. */
  .tm-presence-slide-inline {
    --tm-presence-closed-translate: calc(
        var(--tm-distance, 12px) * var(--tm-presence-direction, -1) *
          var(--tm-inline-flip, 1)
      )
      0;
    --tm-presence-closed-scale: 1;
    --tm-presence-duration: 240ms;
  }

  /* Which edge a slide presence starts from. */
  .tm-presence-from-start {
    --tm-presence-direction: -1;
  }

  .tm-presence-from-end {
    --tm-presence-direction: 1;
  }

  /* --- First paint ----------------------------------------------------
     A presence element mounted already open has no previous state to
     transition from, so it would simply appear. @starting-style supplies the
     missing "before" frame. Guarded on transition-behavior, which shipped in
     the same release as @starting-style in Chrome (117), Safari (17.4) and
     Firefox (129), so the query is a reliable proxy. Without support the
     element is visible immediately -- correct, just not animated. */
  @supports (transition-behavior: allow-discrete) {
    @starting-style {
      .tm-presence-fade,
      .tm-presence-scale,
      .tm-presence-pop,
      .tm-presence-slide-block,
      .tm-presence-slide-inline {
        opacity: 0;
        translate: var(--tm-presence-closed-translate, 0 0);
        scale: var(--tm-presence-closed-scale, 1);
      }
    }
  }
}

/* Reduced motion: the state still changes instantly and stays legible, the
   travel just does not happen. Repeated here so the module is safe to import
   on its own, next to a project that does not take the full stylesheet. */
@media (prefers-reduced-motion: reduce) {
  .tm-presence-fade,
  .tm-presence-scale,
  .tm-presence-pop,
  .tm-presence-slide-block,
  .tm-presence-slide-inline {
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }
}


/* --- src/native/native.css --- */
/* --------------------------------------------------------------------------
   Native HTML motion.

   Recipes for elements the browser already owns: [popover], <dialog> and
   <details>. TailMotion adds movement and nothing else -- no colors, no
   dimensions, no padding, no radius, no shadow, and no JavaScript. Opening,
   closing, focus handling, the top layer, light dismiss and the Escape key
   all stay with the browser.

   Support, and what happens without it
   ------------------------------------
   Every modern-CSS rule here sits behind an @supports guard, and the
   unsupported path always leaves content visible and usable:

     :popover-open            Chrome 114, Safari 17, Firefox 125.
                              Without it the popover still opens and closes,
                              with no transition.

     transition-behavior:     Chrome 117, Safari 17.4, Firefox 129. This is
     allow-discrete           what lets an element in `display: none` or the
                              top layer animate *out*. Without it entrances
                              still animate and exits are instant.

     @starting-style          Ships with the property above in every engine, so
                              the same guard covers both.

     ::details-content        Chrome 131. Not in Safari or Firefox at the time
                              of writing. Without it <details> gets the content
                              entrance below and no height interpolation --
                              which is exactly what those browsers do today,
                              only smoother.

     interpolate-size:        Chrome 129. Required to interpolate to `auto`
     allow-keywords           height. Without it the disclosure opens at full
                              height immediately.

   None of these guards can leave an element permanently transparent: the
   hidden base state is only ever declared inside the guard that also declares
   how it becomes visible again.
   -------------------------------------------------------------------------- */


/* --- src/shared/tokens.css (already inlined) --- */


@layer utilities {
  /* --- Popover ---------------------------------------------------------

       <button popovertarget="account-menu">Account</button>
       <div id="account-menu" popover class="tm-native-popover">…</div>

     Set --tm-origin to the corner the popover grows from -- for an anchored
     menu that is the trigger's edge, which stops the panel from appearing to
     inflate out of its own middle. */
  @supports selector(:popover-open) {
    .tm-native-popover[popover] {
      opacity: 0;
      scale: calc(1 - 0.04 * var(--tm-emphasis, 1));
      transform-origin: var(--tm-origin, center);
      /* `display` and `overlay` are discrete properties. Naming them here is
         harmless in browsers that do not know them -- transition-property
         accepts unknown names and simply never matches them. */
      transition-property: opacity, scale, display, overlay;
      transition-duration: var(--tm-duration, calc(200ms * var(--tm-duration-scale, 1)));
      transition-timing-function: var(--tm-easing, var(--tm-ease-exit, cubic-bezier(0.25, 0.46, 0.45, 0.94)));
    }

    .tm-native-popover[popover]:popover-open {
      opacity: 1;
      scale: 1;
      transition-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    }

    /* The close is shorter than the open, as everywhere else in TailMotion. */
    .tm-native-popover[popover]:not(:popover-open) {
      transition-duration: var(
        --tm-exit-duration,
        calc(
          var(--tm-duration, calc(200ms * var(--tm-duration-scale, 1))) * 0.7
        )
      );
    }

    @supports (transition-behavior: allow-discrete) {
      .tm-native-popover[popover] {
        transition-behavior: allow-discrete;
      }

      @starting-style {
        .tm-native-popover[popover]:popover-open {
          opacity: 0;
          scale: calc(1 - 0.04 * var(--tm-emphasis, 1));
        }
      }
    }
  }

  /* --- Dialog ----------------------------------------------------------

       <dialog class="tm-native-dialog">…</dialog>

     The dialog and its backdrop move as one unit, so they share a duration
     and an easing. A closed <dialog> is `display: none` in the UA stylesheet,
     so the transparent base state below can never strand visible content. */
  @supports selector(dialog:modal) {
    .tm-native-dialog {
      opacity: 0;
      scale: calc(1 - 0.04 * var(--tm-emphasis, 1));
      translate: 0 calc(var(--tm-distance, 12px) * -0.5);
      transform-origin: var(--tm-origin, center);
      transition-property: opacity, scale, translate, display, overlay;
      transition-duration: var(--tm-duration, calc(240ms * var(--tm-duration-scale, 1)));
      transition-timing-function: var(--tm-easing, var(--tm-ease-exit, cubic-bezier(0.25, 0.46, 0.45, 0.94)));
    }

    .tm-native-dialog[open] {
      opacity: 1;
      scale: 1;
      translate: 0 0;
      transition-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    }

    .tm-native-dialog:not([open]) {
      transition-duration: var(
        --tm-exit-duration,
        calc(
          var(--tm-duration, calc(240ms * var(--tm-duration-scale, 1))) * 0.7
        )
      );
    }

    /* Backdrop opacity only: the color is the browser's, or yours.

       ::backdrop only started inheriting from its originating element
       recently (Chrome 122, Firefox 123, Safari 17.4). Older engines resolve
       these vars against nothing, so every fallback here is a literal that
       matches the dialog's own unscaled default -- the pair stays in step
       either way. Set --tm-backdrop-duration to pin it explicitly. */
    .tm-native-dialog::backdrop {
      opacity: 0;
      transition-property: opacity, display, overlay;
      transition-duration: var(--tm-backdrop-duration, 240ms);
      transition-timing-function: var(--tm-ease-exit, cubic-bezier(0.25, 0.46, 0.45, 0.94));
    }

    .tm-native-dialog[open]::backdrop {
      opacity: 1;
      transition-timing-function: var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1));
    }

    @supports (transition-behavior: allow-discrete) {
      .tm-native-dialog,
      .tm-native-dialog::backdrop {
        transition-behavior: allow-discrete;
      }

      @starting-style {
        .tm-native-dialog[open] {
          opacity: 0;
          scale: calc(1 - 0.04 * var(--tm-emphasis, 1));
          translate: 0 calc(var(--tm-distance, 12px) * -0.5);
        }

        .tm-native-dialog[open]::backdrop {
          opacity: 0;
        }
      }
    }
  }

  /* --- Disclosure ------------------------------------------------------

       <details class="tm-native-disclosure">
         <summary>Details <span data-tm-marker>›</span></summary>
         <div>Disclosure content</div>
       </details>

     Two layers, so every browser gets something:

       1. The content entrance below runs everywhere. <details> only renders
          its content while open, so a plain keyframe is enough and needs no
          measured height.
       2. Where ::details-content and interpolate-size exist, the box height
          interpolates as well, so the surrounding page reflows smoothly
          instead of jumping. */
  .tm-native-disclosure[open] > :not(summary) {
    animation-name: tm-disclosure-content;
    animation-duration: var(--tm-duration, calc(240ms * var(--tm-duration-scale, 1)));
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    animation-fill-mode: both;
  }

  /* Optional marker child. summary::marker cannot be transformed, so rotation
     needs an element you own. */
  .tm-native-disclosure summary [data-tm-marker] {
    display: inline-block;
    transition-property: rotate;
    transition-duration: var(--tm-duration, calc(200ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-ease-morph, cubic-bezier(0.2, 0, 0, 1)));
  }

  .tm-native-disclosure[open] summary [data-tm-marker] {
    rotate: var(--tm-marker-rotate, 90deg);
  }

  @supports selector(::details-content) {
    .tm-native-disclosure::details-content {
      block-size: 0;
      overflow-y: clip;
      opacity: 0;
      transition-property: block-size, content-visibility, opacity;
      transition-duration: var(--tm-duration, calc(240ms * var(--tm-duration-scale, 1)));
      transition-timing-function: var(--tm-easing, var(--tm-ease-morph, cubic-bezier(0.2, 0, 0, 1)));
      transition-behavior: allow-discrete;
    }

    .tm-native-disclosure[open]::details-content {
      block-size: auto;
      opacity: 1;
    }

    /* Without interpolate-size, `auto` is not an interpolatable length and the
       height simply snaps -- still open, still readable. */
    @supports (interpolate-size: allow-keywords) {
      .tm-native-disclosure {
        interpolate-size: allow-keywords;
      }
    }

    /* The box already animates its height; a second entrance on the child
       would double the movement. */
    .tm-native-disclosure[open] > :not(summary) {
      animation-name: none;
    }
  }
}

@keyframes tm-disclosure-content {
  from {
    opacity: 0;
    translate: 0 calc(var(--tm-distance, 12px) * -0.5);
  }

  to {
    opacity: 1;
    translate: 0 0;
  }
}

/* Reduced motion. Repeated here so the module is safe to import on its own,
   and extended to ::backdrop and ::details-content, which the token layer
   cannot name without risking the whole rule in an older parser. */
@media (prefers-reduced-motion: reduce) {
  .tm-native-popover,
  .tm-native-dialog,
  .tm-native-disclosure,
  .tm-native-disclosure > :not(summary),
  .tm-native-disclosure summary [data-tm-marker] {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }

  .tm-native-dialog::backdrop {
    transition-duration: 1ms !important;
  }

  @supports selector(::details-content) {
    .tm-native-disclosure::details-content {
      transition-duration: 1ms !important;
    }
  }
}


/* --- src/recipes/recipes.css --- */
/* --------------------------------------------------------------------------
   Product-motion recipes.

   Each recipe encodes the motion decisions a real interface pattern needs --
   which direction it comes from, what its transform origin is, how much
   shorter the exit is than the entrance -- and nothing else. No colors, no
   type, no dimensions, no spacing, no shadows, no component structure beyond
   the minimum the movement requires. Tailwind keeps all of that.

   They read the same state contract as tm-presence-*:

     data-state="open"    / "closed"
     data-state="active"  / "inactive"
     data-state="checked" / "unchecked"
     data-state="on"      / "off"
     aria-expanded        / aria-pressed / aria-checked
     .tm-open             / .tm-closed

   An element with no recognised state is treated as open, so a typo leaves
   content visible.

   Where a recipe needs specific children, the contract is written above it and
   in the README. Recipes with a child contract are opt-in: nothing here
   applies to markup that does not carry the class.
   -------------------------------------------------------------------------- */


/* --- src/shared/tokens.css (already inlined) --- */


@layer utilities {
  /* --- Shared presence engine for the panel recipes ---------------------
     Same shape as src/presence/presence.css: the base rule is the open state,
     one closed rule reads two per-recipe custom properties. */
  .tm-menu,
  .tm-tooltip,
  .tm-dialog,
  .tm-dialog-backdrop,
  .tm-toast,
  .tm-tab-panel {
    opacity: 1;
    visibility: visible;
    translate: 0 0;
    scale: 1;
    transition-property: opacity, visibility, translate, scale;
    transition-duration: var(--tm-duration, calc(var(--tm-recipe-duration, 220ms) * var(--tm-duration-scale, 1)));
    transition-delay: var(--tm-delay, 0ms);
    transition-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    transform-origin: var(--tm-origin, center);
  }

  :is(
      .tm-menu,
      .tm-tooltip,
      .tm-dialog,
      .tm-dialog-backdrop,
      .tm-toast,
      .tm-tab-panel
    ):is(
      [data-state="closed"],
      [data-state="inactive"],
      [data-state="unchecked"],
      [data-state="off"],
      [aria-expanded="false"],
      [aria-pressed="false"],
      [aria-checked="false"],
      .tm-closed
    ) {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    translate: var(--tm-recipe-closed-translate, 0 0);
    scale: var(--tm-recipe-closed-scale, 1);
    transition-duration: var(
      --tm-exit-duration,
      calc(
        var(
            --tm-duration,
            calc(var(--tm-recipe-duration, 220ms) * var(--tm-duration-scale, 1))
          ) * var(--tm-presence-exit-scale, 0.7)
      )
    );
    transition-timing-function: var(--tm-easing, var(--tm-ease-exit, cubic-bezier(0.25, 0.46, 0.45, 0.94)));
  }

  @supports (transition-behavior: allow-discrete) {
    @starting-style {
      .tm-menu,
      .tm-tooltip,
      .tm-dialog,
      .tm-dialog-backdrop,
      .tm-toast,
      .tm-tab-panel {
        opacity: 0;
        translate: var(--tm-recipe-closed-translate, 0 0);
        scale: var(--tm-recipe-closed-scale, 1);
      }
    }
  }

  /* --- 1. Menu and popover ---------------------------------------------

       <div class="tm-menu" data-state="open" data-side="bottom">…</div>

     A menu should look like it comes out of its trigger, not out of its own
     middle, so data-side sets the transform origin. The names follow the
     convention Radix UI, Base UI and Floating UI already emit, and
     --tm-origin overrides them (Radix users can pass
     --tm-origin: var(--radix-popper-transform-origin)). */
  .tm-menu {
    --tm-recipe-duration: 180ms;
    --tm-recipe-closed-translate: 0 0;
    --tm-recipe-closed-scale: calc(1 - 0.04 * var(--tm-emphasis, 1));
  }

  /* --- 2. Dialog --------------------------------------------------------

       <div class="tm-dialog-backdrop" data-state="open"></div>
       <div class="tm-dialog" role="dialog" data-state="open">…</div>

     For a <dialog> element use tm-native-dialog instead: the browser handles
     the top layer and the backdrop for you. This pair is for the div-based
     dialogs headless libraries build.

     Both halves move as one unit, so they share a duration and an easing. */
  .tm-dialog {
    --tm-recipe-duration: 240ms;
    --tm-recipe-closed-translate: 0 calc(var(--tm-distance, 12px) * -0.5);
    --tm-recipe-closed-scale: calc(1 - 0.04 * var(--tm-emphasis, 1));
  }

  .tm-dialog-backdrop {
    --tm-recipe-duration: 240ms;
    --tm-recipe-closed-translate: 0 0;
    --tm-recipe-closed-scale: 1;
  }

  /* --- 3. Toast ---------------------------------------------------------

       <div role="status" data-state="open" class="tm-toast">Changes saved</div>

     Slides in from the edge it is anchored to. The default is the inline-end
     edge, mirrored in right-to-left contexts; the modifiers below cover
     bottom- and top-anchored stacks. Toasts appear without being asked for,
     so the travel is short and the exit is quick. */
  .tm-toast {
    --tm-recipe-duration: 260ms;
    --tm-recipe-closed-translate: calc(
        var(--tm-toast-distance, calc(var(--tm-distance, 12px) * 1.6)) *
          var(--tm-inline-flip, 1)
      )
      0;
    --tm-recipe-closed-scale: 1;
  }

  .tm-toast-from-inline-start {
    --tm-recipe-closed-translate: calc(
        var(--tm-toast-distance, calc(var(--tm-distance, 12px) * 1.6)) *
          var(--tm-inline-flip, 1) * -1
      )
      0;
  }

  .tm-toast-from-block-end {
    --tm-recipe-closed-translate: 0
      var(--tm-toast-distance, calc(var(--tm-distance, 12px) * 1.6));
  }

  .tm-toast-from-block-start {
    --tm-recipe-closed-translate: 0
      calc(var(--tm-toast-distance, calc(var(--tm-distance, 12px) * 1.6)) * -1);
  }

  /* --- 4. Tooltip -------------------------------------------------------

       <div role="tooltip" data-state="open" data-side="top" class="tm-tooltip">…</div>

     The fastest thing in the library. A tooltip that takes 200ms to appear
     feels broken, because the pointer is already there. Travel is a third of
     the usual distance and the exit is nearly instant. */
  .tm-tooltip {
    --tm-recipe-duration: 120ms;
    --tm-presence-exit-scale: 0.5;
    --tm-recipe-closed-translate: 0
      calc(var(--tm-distance, 12px) * -0.33 * var(--tm-tooltip-direction, 1));
    --tm-recipe-closed-scale: calc(1 - 0.03 * var(--tm-emphasis, 1));
  }

  /* A tooltip above its trigger should retreat upward, one below it downward.
     data-side gives that for free. */
  .tm-tooltip[data-side="bottom"] {
    --tm-tooltip-direction: -1;
  }

  /* Transform origin from the side the panel is anchored on. Kept as one rule
     per side so the mapping is readable, and applied to both panel recipes. */
  :is(.tm-menu, .tm-tooltip)[data-side="top"] {
    --tm-origin: bottom center;
  }

  :is(.tm-menu, .tm-tooltip)[data-side="bottom"] {
    --tm-origin: top center;
  }

  :is(.tm-menu, .tm-tooltip)[data-side="left"] {
    --tm-origin: center right;
  }

  :is(.tm-menu, .tm-tooltip)[data-side="right"] {
    --tm-origin: center left;
  }

  /* Alignment is deliberately not mapped. transform-origin takes no logical
     keywords, so a data-align rule would hard-code left/right and break in
     right-to-left contexts. Positioning libraries already publish a resolved
     origin -- pass it straight through:

       style="--tm-origin: var(--radix-popper-transform-origin)"  */

  /* --- 5. Accordion / disclosure ---------------------------------------

       <div class="tm-accordion-panel" data-state="open">
         <div>…exactly one child…</div>
       </div>

     Child contract: exactly one element child, which TailMotion clips.
     The 0fr -> 1fr grid row is the one height animation CSS can express
     without measuring anything, so this needs no JavaScript and no fixed
     height. For a <details> element use tm-native-disclosure instead.

     Support: Chrome 107, Safari 16, Firefox 66. Older browsers show and hide
     the panel without the height tween -- open content is never hidden. */
  .tm-accordion-panel {
    display: grid;
    grid-template-rows: 1fr;
    transition-property: grid-template-rows, opacity, visibility;
    transition-duration: var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1)));
    transition-delay: var(--tm-delay, 0ms);
    transition-timing-function: var(--tm-easing, var(--tm-ease-morph, cubic-bezier(0.2, 0, 0, 1)));
    opacity: 1;
    visibility: visible;
  }

  .tm-accordion-panel > * {
    overflow: hidden;
    min-block-size: 0;
  }

  .tm-accordion-panel:is(
      [data-state="closed"],
      [data-state="inactive"],
      [data-state="off"],
      [aria-expanded="false"],
      .tm-closed
    ) {
    grid-template-rows: 0fr;
    opacity: 0;
    visibility: hidden;
    transition-duration: var(
      --tm-exit-duration,
      calc(
        var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) *
          var(--tm-presence-exit-scale, 0.7)
      )
    );
  }

  /* --- 6. Tabs ----------------------------------------------------------

     Two independent pieces.

     The panel cross-fade needs no measurement:

       <div class="tm-tab-panel" data-state="active">…</div>

     The indicator does need measurement, and that stays with your component:
     set --tm-tab-offset and --tm-tab-size from the active tab's box and
     TailMotion animates between them. TailMotion never reads the DOM. */
  .tm-tab-panel {
    --tm-recipe-duration: 160ms;
    --tm-recipe-closed-translate: 0 0;
    --tm-recipe-closed-scale: 1;
  }

  .tm-tab-indicator {
    translate: var(--tm-tab-offset, 0) 0;
    inline-size: var(--tm-tab-size, 0);
    transition-property: translate, inline-size;
    transition-duration: var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-ease-morph, cubic-bezier(0.2, 0, 0, 1)));
  }

  /* --- 7. Loading to success -------------------------------------------

       <button data-state="loading" class="tm-feedback-button">
         <span class="tm-feedback-idle">Save</span>
         <span class="tm-feedback-loading">Saving</span>
         <span class="tm-feedback-success">Saved</span>
       </button>

     Child contract: one element per state, in any order, each carrying its
     state's class. All three stay mounted and share one grid cell, so the
     button never resizes mid-transition and the outgoing label animates out
     as cleanly as the incoming one animates in. States: idle, loading,
     success, and optionally error.

     Grid stacking here is structural, not styling -- the same decision
     tm-icon-swap already makes. */
  .tm-feedback-button {
    display: inline-grid;
    grid-template-areas: "tm-feedback";
    place-items: center;
  }

  .tm-feedback-button > .tm-feedback-idle,
  .tm-feedback-button > .tm-feedback-loading,
  .tm-feedback-button > .tm-feedback-success,
  .tm-feedback-button > .tm-feedback-error {
    grid-area: tm-feedback;
    opacity: 0;
    visibility: hidden;
    translate: 0 calc(var(--tm-distance, 12px) * 0.5);
    transition-property: opacity, visibility, translate;
    transition-duration: var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
  }

  .tm-feedback-button:not([data-state]) > .tm-feedback-idle,
  .tm-feedback-button[data-state="idle"] > .tm-feedback-idle,
  .tm-feedback-button[data-state="loading"] > .tm-feedback-loading,
  .tm-feedback-button[data-state="success"] > .tm-feedback-success,
  .tm-feedback-button[data-state="error"] > .tm-feedback-error {
    opacity: 1;
    visibility: visible;
    translate: 0 0;
  }

  /* Success is the one moment in a form worth celebrating, so it is the only
     state that arrives with a spring. --tm-overshoot: 0 removes it. */
  .tm-feedback-button[data-state="success"] > .tm-feedback-success {
    transition-timing-function: var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1)));
  }

  /* --- 8. Destructive hold confirmation --------------------------------

       <button class="tm-hold-confirm">Hold to delete</button>

     A progress fill that sweeps across the button while the pointer is held,
     and retreats quickly the moment it is released. Linear easing is correct
     here and almost nowhere else: the fill is a clock, and any other curve
     would misreport how much time is left.

     Motion only. The fill inherits the button's own color through
     --tm-color; TailMotion picks no red. `overflow` and `isolation` are here
     because the fill has to be clipped to the button's box -- your radius,
     padding and color all stay yours.

     Keyboard: pair this with a key handler that sets data-state="holding" on
     keydown, otherwise the interaction is pointer-only and inaccessible. */
  .tm-hold-confirm {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    /* The press itself gets the same tactile feedback as tm-press. */
    transition-property: scale;
    transition-duration: var(--tm-duration, calc(150ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-ease-interaction, cubic-bezier(0.25, 0.46, 0.45, 0.94)));
  }

  .tm-hold-confirm:active:not(:disabled):not([aria-disabled="true"]) {
    scale: var(--tm-press-scale, 0.98);
  }

  .tm-hold-confirm::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--tm-hold-fill, var(--tm-color, currentColor));
    opacity: var(--tm-hold-fill-opacity, 0.18);
    transform-origin: left center;
    scale: 0 1;
    /* Release: snap back. */
    transition: scale var(--tm-hold-release-duration, 160ms) var(--tm-ease-exit, ease-out);
  }

  [dir="rtl"] .tm-hold-confirm::after {
    transform-origin: right center;
  }

  @supports selector(:dir(rtl)) {
    .tm-hold-confirm:dir(rtl)::after {
      transform-origin: right center;
    }
  }

  /* Hold: fill at a constant, readable rate. */
  .tm-hold-confirm:active:not(:disabled):not([aria-disabled="true"])::after,
  .tm-hold-confirm[data-state="holding"]::after {
    scale: 1 1;
    transition-duration: var(--tm-hold-duration, 1200ms);
    transition-timing-function: linear;
  }
}

/* Reduced motion. Repeated here so the module is safe to import on its own. */
@media (prefers-reduced-motion: reduce) {
  /* The hold fill keeps its full duration on purpose: it is a progress
     readout, not decoration. Collapsing it to 1ms would confirm a destructive
     action the instant the button was touched. This rule outranks the
     library-wide [class*="tm-"]::after reset by specificity. */
  .tm-hold-confirm:active:not(:disabled):not([aria-disabled="true"])::after,
  .tm-hold-confirm[data-state="holding"]::after {
    transition-duration: var(--tm-hold-duration, 1200ms) !important;
  }

  .tm-menu,
  .tm-tooltip,
  .tm-dialog,
  .tm-dialog-backdrop,
  .tm-toast,
  .tm-tab-panel,
  .tm-tab-indicator,
  .tm-accordion-panel,
  .tm-feedback-button > * {
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }
}


/* --- src/choreography/stagger.css --- */
/* --------------------------------------------------------------------------
   Stagger choreography.

   A stagger container sequences its direct children. Group siblings
   semantically -- title, description, actions -- so the sequence reads as
   hierarchy rather than as a queue.

     <ul class="tm-stagger tm-stagger-75 tm-stagger-from-start" data-state="open">
       <li>Profile</li>
       <li>Settings</li>
       <li>Sign out</li>
     </ul>

   Order
   -----
   Children run in document order by default. tm-stagger-from-end reverses the
   sequence by reading a second generated index counted from the last child, so
   nothing in the DOM moves: reading order, tab order and the accessibility
   tree are exactly what the markup says. TailMotion never reorders children --
   no row-reverse, no order property, no negative delays.

   Direction and state
   -------------------
     tm-stagger                     children enter, in document order
     tm-stagger tm-stagger-from-end children enter, last one first
     tm-stagger-exit                children leave, in document order
     tm-stagger data-state="closed" children leave, in document order
     ... plus tm-stagger-from-end   children leave, last one first

   A container with no state keeps the pre-0.8 behaviour exactly: its children
   enter once on mount.

   Limit
   -----
   Indices are generated for the first 20 children (see MAX_STAGGER_CHILDREN in
   scripts/build.mjs). Child 21 onwards reuses the last index, so a long list
   ends together rather than starting together -- with the default 100ms step a
   20-item sequence already runs for 1.9s, and past that a stagger stops
   reading as choreography.

   Nesting
   -------
   A nested tm-stagger sequences its own children from its own delay; it does
   not continue the outer count, and its step does not leak back out. Offset a
   nested group with tm-delay-* when the two should read as one sequence.
   -------------------------------------------------------------------------- */


/* --- src/shared/tokens.css (already inlined) --- */


@layer utilities {
  /* The container is a scope, not an animated item: reset the indices so a
     stagger nested inside another cannot inherit its parent's position. */
  .tm-stagger {
    --tm-stagger-index: 0;
    --tm-stagger-index-end: 0;
  }

  .tm-stagger > * {
    /* Which end the sequence counts from. tm-stagger-from-end swaps it. */
    --tm-stagger-position: var(--tm-stagger-index, 0);

    animation-name: tm-stagger-item;
    animation-duration: var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1)));
    animation-delay: calc(
      var(--tm-delay, 0ms) + var(--tm-stagger-position, 0) *
        var(--tm-stagger-step, 100ms)
    );
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  /* Count from the last child instead of the first. */
  .tm-stagger-from-end > *,
  .tm-stagger-reverse > * {
    --tm-stagger-position: var(--tm-stagger-index-end, 0);
  }

  /* Explicit forward, for markup that states its intent or overrides an
     inherited modifier. */
  .tm-stagger-from-start > * {
    --tm-stagger-position: var(--tm-stagger-index, 0);
  }

  /* Leave in sequence. Either by class, or from the state the container
     already carries -- switching animation-name is what re-triggers the
     keyframes, so toggling data-state replays the choreography in the new
     direction without any JavaScript. */
  .tm-stagger-exit > *,
  .tm-stagger:is(
      [data-state="closed"],
      [data-state="inactive"],
      [data-state="off"],
      [aria-expanded="false"],
      .tm-closed
    ) > * {
    animation-name: tm-stagger-item-exit;
    animation-duration: var(
      --tm-exit-duration,
      calc(
        var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) *
          var(--tm-presence-exit-scale, 0.7)
      )
    );
    animation-timing-function: var(--tm-easing, var(--tm-ease-exit, cubic-bezier(0.25, 0.46, 0.45, 0.94)));
  }

  /* Step tokens. tm-stagger-step-* (0.6 and earlier) and the shorter
     tm-stagger-* spelling are the same utility; the short form is preferred in
     new markup. Both are declared after the motion profiles, so an explicit
     step wins over a profile's. */
  .tm-stagger-50 {
    --tm-stagger-step: 50ms;
  }

  .tm-stagger-75 {
    --tm-stagger-step: 75ms;
  }

  .tm-stagger-100 {
    --tm-stagger-step: 100ms;
  }

  .tm-stagger-150 {
    --tm-stagger-step: 150ms;
  }

  .tm-stagger-200 {
    --tm-stagger-step: 200ms;
  }

  /* Generated child indices. Forward, then counted from the end. */
  .tm-stagger > *:nth-child(1) { --tm-stagger-index: 0; }
  .tm-stagger > *:nth-child(2) { --tm-stagger-index: 1; }
  .tm-stagger > *:nth-child(3) { --tm-stagger-index: 2; }
  .tm-stagger > *:nth-child(4) { --tm-stagger-index: 3; }
  .tm-stagger > *:nth-child(5) { --tm-stagger-index: 4; }
  .tm-stagger > *:nth-child(6) { --tm-stagger-index: 5; }
  .tm-stagger > *:nth-child(7) { --tm-stagger-index: 6; }
  .tm-stagger > *:nth-child(8) { --tm-stagger-index: 7; }
  .tm-stagger > *:nth-child(9) { --tm-stagger-index: 8; }
  .tm-stagger > *:nth-child(10) { --tm-stagger-index: 9; }
  .tm-stagger > *:nth-child(11) { --tm-stagger-index: 10; }
  .tm-stagger > *:nth-child(12) { --tm-stagger-index: 11; }
  .tm-stagger > *:nth-child(13) { --tm-stagger-index: 12; }
  .tm-stagger > *:nth-child(14) { --tm-stagger-index: 13; }
  .tm-stagger > *:nth-child(15) { --tm-stagger-index: 14; }
  .tm-stagger > *:nth-child(16) { --tm-stagger-index: 15; }
  .tm-stagger > *:nth-child(17) { --tm-stagger-index: 16; }
  .tm-stagger > *:nth-child(18) { --tm-stagger-index: 17; }
  .tm-stagger > *:nth-child(19) { --tm-stagger-index: 18; }
  .tm-stagger > *:nth-child(20) { --tm-stagger-index: 19; }
  .tm-stagger > *:nth-child(n + 21) { --tm-stagger-index: 19; }

  .tm-stagger > *:nth-last-child(1) { --tm-stagger-index-end: 0; }
  .tm-stagger > *:nth-last-child(2) { --tm-stagger-index-end: 1; }
  .tm-stagger > *:nth-last-child(3) { --tm-stagger-index-end: 2; }
  .tm-stagger > *:nth-last-child(4) { --tm-stagger-index-end: 3; }
  .tm-stagger > *:nth-last-child(5) { --tm-stagger-index-end: 4; }
  .tm-stagger > *:nth-last-child(6) { --tm-stagger-index-end: 5; }
  .tm-stagger > *:nth-last-child(7) { --tm-stagger-index-end: 6; }
  .tm-stagger > *:nth-last-child(8) { --tm-stagger-index-end: 7; }
  .tm-stagger > *:nth-last-child(9) { --tm-stagger-index-end: 8; }
  .tm-stagger > *:nth-last-child(10) { --tm-stagger-index-end: 9; }
  .tm-stagger > *:nth-last-child(11) { --tm-stagger-index-end: 10; }
  .tm-stagger > *:nth-last-child(12) { --tm-stagger-index-end: 11; }
  .tm-stagger > *:nth-last-child(13) { --tm-stagger-index-end: 12; }
  .tm-stagger > *:nth-last-child(14) { --tm-stagger-index-end: 13; }
  .tm-stagger > *:nth-last-child(15) { --tm-stagger-index-end: 14; }
  .tm-stagger > *:nth-last-child(16) { --tm-stagger-index-end: 15; }
  .tm-stagger > *:nth-last-child(17) { --tm-stagger-index-end: 16; }
  .tm-stagger > *:nth-last-child(18) { --tm-stagger-index-end: 17; }
  .tm-stagger > *:nth-last-child(19) { --tm-stagger-index-end: 18; }
  .tm-stagger > *:nth-last-child(20) { --tm-stagger-index-end: 19; }
  .tm-stagger > *:nth-last-child(n + 21) { --tm-stagger-index-end: 19; }
}

@keyframes tm-stagger-item {
  from {
    opacity: 0;
    translate: 0 var(--tm-distance, 12px);
  }

  to {
    opacity: 1;
    translate: 0 0;
  }
}

@keyframes tm-stagger-item-exit {
  from {
    opacity: 1;
    translate: 0 0;
  }

  to {
    opacity: 0;
    translate: 0
      calc(var(--tm-exit-distance, calc(var(--tm-distance, 12px) * 0.7)) * -1);
  }
}

/* Reduced motion. Repeated here so the module is safe to import on its own;
   the container animates unclassed children, so it has to be named. */
@media (prefers-reduced-motion: reduce) {
  .tm-stagger > * {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
  }
}


/* --- src/scroll/scroll.css --- */
/* --------------------------------------------------------------------------
   Scroll-driven motion.

   Reveals tied to the scroll position with CSS view timelines. No
   IntersectionObserver, no scroll listener, no JavaScript at all -- the
   browser drives these on the compositor, so they do not compete with the main
   thread the way an observer-based reveal does.

     <section class="tm-scroll-reveal">Content</section>

   Why tm-scroll-* and not tm-view-*
   ---------------------------------
   tm-view-morph and the whole --tm-view-* token family already mean something
   else in this library: the container that reshapes between two mounted
   panels. Naming a scroll module tm-view-* would put two unrelated ideas
   behind one prefix.

   Support
   -------
   Chrome 115 and Edge 115 support scroll-driven animations. Firefox ships them
   behind a flag. Safari does not support them yet.

   Everything here sits inside @supports (animation-timeline: view()). Where
   that is false not one declaration below applies, so the section renders as
   ordinary, fully visible content -- the reveal is the enhancement, never the
   thing standing between a reader and the text.

   Reduced motion
   --------------
   A progress-linked animation ignores animation-duration, so the library-wide
   1ms reset cannot stop these. They are switched off by name instead, which
   leaves each element at its natural, visible state.
   -------------------------------------------------------------------------- */


/* --- src/shared/tokens.css (already inlined) --- */


@layer utilities {
  @supports (animation-timeline: view()) {
    .tm-scroll-fade,
    .tm-scroll-reveal,
    .tm-scroll-slide-block,
    .tm-scroll-scale {
      animation-timeline: view();
      /* Default range: start once the subject is properly on screen, finish
         before it reaches the middle. Running a reveal across the full entry
         range means the reader watches text resolve while trying to read it. */
      animation-range: var(--tm-scroll-range, entry 15% entry 65%);
      animation-fill-mode: both;
      animation-timing-function: linear;
    }

    .tm-scroll-fade {
      animation-name: tm-scroll-fade;
    }

    /* Fade plus a short rise. The workhorse. */
    .tm-scroll-reveal {
      animation-name: tm-scroll-reveal;
    }

    .tm-scroll-slide-block {
      animation-name: tm-scroll-slide-block;
    }

    .tm-scroll-scale {
      animation-name: tm-scroll-scale;
    }

    /* Ranges. Named for what the reader sees, not for the timeline internals:

         entry   while the element is coming into the scrollport
         cover   the whole time any part of it is visible
         contain while it is fully visible
         exit    while it is leaving

       Set --tm-scroll-range directly for anything more specific. */
    .tm-scroll-range-entry {
      --tm-scroll-range: entry 15% entry 65%;
    }

    .tm-scroll-range-cover {
      --tm-scroll-range: cover 0% cover 40%;
    }

    .tm-scroll-range-contain {
      --tm-scroll-range: contain 0% contain 100%;
    }

    .tm-scroll-range-exit {
      --tm-scroll-range: exit 0% exit 100%;
    }

    /* Reading progress, linked to the document scroll rather than to one
       element. Put it on a bar you have sized and colored yourself:

         <div class="tm-scroll-progress fixed inset-x-0 top-0 h-1 bg-black"></div> */
    .tm-scroll-progress {
      animation-name: tm-scroll-progress;
      animation-timeline: scroll(root block);
      animation-fill-mode: both;
      animation-timing-function: linear;
      transform-origin: left center;
      scale: 0 1;
    }

    [dir="rtl"] .tm-scroll-progress {
      transform-origin: right center;
    }

    @supports selector(:dir(rtl)) {
      .tm-scroll-progress:dir(rtl) {
        transform-origin: right center;
      }
    }
  }
}

@keyframes tm-scroll-fade {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

@keyframes tm-scroll-reveal {
  from {
    opacity: 0;
    translate: 0 var(--tm-distance, 12px);
  }

  to {
    opacity: 1;
    translate: 0 0;
  }
}

@keyframes tm-scroll-slide-block {
  from {
    opacity: 0;
    /* Deliberately modest. Long parallax travel on body content makes text
       arrive at a different place than the eye expects and hurts reading. */
    translate: 0 calc(var(--tm-distance, 12px) * 2);
  }

  to {
    opacity: 1;
    translate: 0 0;
  }
}

@keyframes tm-scroll-scale {
  from {
    opacity: 0;
    scale: calc(1 - 0.06 * var(--tm-emphasis, 1));
  }

  to {
    opacity: 1;
    scale: 1;
  }
}

@keyframes tm-scroll-progress {
  from {
    scale: 0 1;
  }

  to {
    scale: 1 1;
  }
}

/* A progress-linked animation has no duration to shorten, so reduced motion
   removes the animation instead. Each element then renders at its own
   authored state: the reveals are plain visible content, and the progress bar
   shows its complete state rather than tracking the scroll. If a permanently
   full bar would misinform your readers, hide it as well with Tailwind's
   motion-reduce:hidden. */
@media (prefers-reduced-motion: reduce) {
  .tm-scroll-fade,
  .tm-scroll-reveal,
  .tm-scroll-slide-block,
  .tm-scroll-scale {
    animation-name: none !important;
    animation-timeline: auto !important;
  }

  .tm-scroll-progress {
    animation-name: none !important;
    animation-timeline: auto !important;
    scale: 1 1 !important;
  }
}


/* --- src/animations/exit.css --- */
/* --------------------------------------------------------------------------
   Exit keyframes.

   Exits are quieter than the entrances they mirror: roughly 20% faster, and
   they travel 70% of --tm-distance. That ratio is resolved here, on the
   element, rather than on :root -- a custom property declared on :root is
   substituted there, so the old `--tm-exit-distance: calc(var(--tm-distance) *
   0.7)` froze at 8.4px and never noticed a tm-distance-* utility further down
   the tree. Setting --tm-exit-distance explicitly still overrides the ratio.

   Each exit ends on its final frame (fill-mode: both), so the element stays
   hidden but still occupies layout. Remove the node, or apply `hidden`, once
   the animation has finished. For an exit driven by application state that has
   to be interruptible mid-flight, reach for tm-presence-* instead.
   -------------------------------------------------------------------------- */

@layer utilities {
  .tm-fade-out {
    animation-name: tm-fade-out;
    animation-duration: var(--tm-duration, calc(200ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-exit, ease-out));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  .tm-scale-out {
    animation-name: tm-scale-out;
    animation-duration: var(--tm-duration, calc(180ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-exit, ease-out));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  /* Leaves toward the block-start edge. */
  .tm-slide-block-out {
    animation-name: tm-slide-block-out;
    animation-duration: var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-exit, ease-out));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  /* Leaves toward the inline-end edge, mirrored in RTL. */
  .tm-slide-inline-out {
    animation-name: tm-slide-inline-out;
    animation-duration: var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-exit, ease-out));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  .tm-blur-out {
    animation-name: tm-blur-out;
    animation-duration: var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-exit, ease-out));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }
}

@keyframes tm-fade-out {
  from {
    opacity: 1;
  }

  to {
    opacity: 0;
  }
}

@keyframes tm-scale-out {
  from {
    opacity: 1;
    scale: 1;
  }

  to {
    opacity: 0;
    scale: var(--tm-exit-scale, calc(1 - 0.04 * var(--tm-emphasis, 1)));
  }
}

@keyframes tm-slide-block-out {
  from {
    opacity: 1;
    translate: 0 0;
  }

  to {
    opacity: 0;
    translate: 0
      calc(var(--tm-exit-distance, calc(var(--tm-distance, 12px) * 0.7)) * -1);
  }
}

@keyframes tm-slide-inline-out {
  from {
    opacity: 1;
    translate: 0 0;
  }

  to {
    opacity: 0;
    translate:
      calc(
        var(--tm-exit-distance, calc(var(--tm-distance, 12px) * 0.7)) *
          var(--tm-inline-flip, 1)
      )
      0;
  }
}

@keyframes tm-blur-out {
  from {
    opacity: 1;
    filter: blur(0);
  }

  to {
    opacity: 0;
    filter: blur(calc(var(--tm-exit-blur, 4px) * var(--tm-emphasis, 1)));
  }
}


/* --- src/animations/interactions.css --- */
/* --------------------------------------------------------------------------
   Interruptible interaction utilities.

   Everything here is built from transitions, not keyframes: press, hover and
   toggle states retarget mid-flight when the user changes their mind, where a
   replayed keyframe would snap or restart. Frequently triggered states stay at
   or below 150ms.

   None of these classes promote an element to its own compositing layer. Add
   tm-gpu where you have measured first-frame stutter.
   -------------------------------------------------------------------------- */

@layer utilities {
  /* Tactile press feedback. */
  .tm-press {
    transition-property: scale;
    transition-duration: var(--tm-duration, calc(150ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-ease-interaction, ease-out));
  }

  .tm-press:active:not(:disabled):not([aria-disabled="true"]) {
    scale: var(--tm-press-scale, 0.96);
  }

  /* Rise with a shadow on hover or keyboard focus. */
  .tm-hover-lift {
    transition-property: translate, box-shadow;
    transition-duration: var(--tm-duration, calc(150ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-ease-interaction, ease-out));
  }

  .tm-hover-lift:hover,
  .tm-hover-lift:focus-visible {
    translate: 0 calc(var(--tm-lift-distance, 4px) * -1);
    box-shadow: var(--tm-lift-shadow, 0 8px 24px -8px var(--tm-shadow-color));
  }

  /* Grow slightly on hover or keyboard focus. */
  .tm-hover-scale {
    transition-property: scale;
    transition-duration: var(--tm-duration, calc(150ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-ease-interaction, ease-out));
  }

  .tm-hover-scale:hover,
  .tm-hover-scale:focus-visible {
    scale: var(--tm-hover-scale, 1.04);
  }

  /* Cross-fade between two glyphs. Both children stay in the DOM, so the
     outgoing icon animates out as cleanly as the incoming one animates in.

     <button class="tm-icon-swap" aria-pressed="false">
       <svg><!-- shown when aria-pressed is false --></svg>
       <svg><!-- shown when aria-pressed is true --></svg>
     </button>

     The swapped state is read from real component state, never a parallel
     flag: .tm-swapped, [data-tm-swap="on"], aria-pressed, aria-expanded or
     aria-checked. Grid stacking is structural, not styling: the two children
     share one cell so neither affects layout. */
  .tm-icon-swap {
    display: inline-grid;
    grid-template-areas: "tm-icon-swap";
    place-items: center;
  }

  .tm-icon-swap > * {
    grid-area: tm-icon-swap;
    transition-property: opacity, scale, filter;
    transition-duration: var(--tm-duration, calc(300ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-ease-morph, cubic-bezier(0.2, 0, 0, 1)));
  }

  .tm-icon-swap > * + * {
    opacity: 0;
    scale: 0.25;
    filter: blur(4px);
  }

  .tm-icon-swap:is(
    .tm-swapped,
    [data-tm-swap="on"],
    [aria-pressed="true"],
    [aria-expanded="true"],
    [aria-checked="true"]
  ) > :first-child {
    opacity: 0;
    scale: 0.25;
    filter: blur(4px);
  }

  .tm-icon-swap:is(
    .tm-swapped,
    [data-tm-swap="on"],
    [aria-pressed="true"],
    [aria-expanded="true"],
    [aria-checked="true"]
  ) > :first-child + * {
    opacity: 1;
    scale: 1;
    filter: blur(0);
  }
}


/* --- src/animations/view-morph.css --- */
/* --------------------------------------------------------------------------
   View morph recipe.

   Keep each view mounted and mark the current one with [data-tm-active]. The
   consumer supplies the target dimensions through --tm-view-width and
   --tm-view-height. Set fixed --tm-view-stage-width and
   --tm-view-stage-height values to animate a rounded inset instead of layout.

   TailMotion owns the movement and the minimum structural positioning only.
   Dimensions, radius, colour and content styling remain with the consumer.
   -------------------------------------------------------------------------- */

@layer utilities {
  .tm-view-morph {
    position: relative;
    inline-size: var(--tm-view-stage-width, var(--tm-view-width));
    block-size: var(--tm-view-stage-height, var(--tm-view-height));
    overflow: hidden;
    overflow: clip;
    clip-path: inset(
      calc(
        (var(--tm-view-stage-height, var(--tm-view-height)) - var(--tm-view-height)) /
          2
      )
      calc(
        (var(--tm-view-stage-width, var(--tm-view-width)) - var(--tm-view-width)) /
          2
      )
      round var(--tm-view-radius, 999px)
    );
    contain: paint;
    transition-property: clip-path, inline-size, block-size;
    transition-duration: var(--tm-duration, calc(360ms * var(--tm-duration-scale, 1)));
    transition-timing-function:
      var(--tm-easing, var(--tm-ease-morph, cubic-bezier(0.2, 0, 0, 1)));
    transition-delay: var(--tm-delay, 0ms);
  }

  .tm-view-morph > [data-tm-panel] {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    inline-size: max-content;
    max-inline-size: 100%;
    translate:
      -50%
      calc(-50% + var(--tm-view-exit-y, 0px));
    scale:
      var(--tm-view-exit-scale-x, var(--tm-view-exit-scale, 0.92))
      var(--tm-view-exit-scale, 0.92);
    opacity: 0;
    filter: blur(var(--tm-view-blur, 5px));
    pointer-events: none;
    transition-property: translate, scale, opacity, filter;
    transition-duration: var(--tm-view-content-duration, 180ms);
    transition-timing-function:
      var(--tm-view-content-easing, cubic-bezier(0.2, 0, 0, 1));
    transition-delay: 0ms;
  }

  .tm-view-morph > [data-tm-panel][data-tm-active] {
    translate: -50% -50%;
    scale: 1;
    opacity: 1;
    filter: blur(0);
    pointer-events: auto;
    transition-delay: var(--tm-view-enter-delay, 50ms);
  }

  /* Blur requires an offscreen raster on mobile browsers. Keep the spatial
     cross-fade, but skip that extra paint on touch-first devices. */
  @media (hover: none) and (pointer: coarse) {
    .tm-view-morph > [data-tm-panel] {
      filter: none;
      transition-property: translate, scale, opacity;
    }
  }
}


/* --- src/animations/flip.css --- */
/* ==========================================================================
   FLIP ANIMATIONS
   Flip card/button effects with configurable directions.
   Works with TailMotion utilities: tm-duration-*, tm-delay-*, tm-ease-*
   ========================================================================== */

@layer base {
  :root,
  :host {
    /* Flip button specific defaults - can be overridden */
    --tm-flip-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275);
  }
}

@layer utilities {
  /* --------------------------------------------------------------------------
     FLIP BUTTON CONTAINER
     Apply to the button/container element
     -------------------------------------------------------------------------- */
  .tm-flip-btn,
  .tm-flip-btn-top,
  .tm-flip-btn-bottom,
  .tm-flip-btn-left,
  .tm-flip-btn-right {
    display: inline-grid;
    place-items: center;
    perspective: 1000px;
    cursor: pointer;
  }

  .tm-flip-btn:active,
  .tm-flip-btn-top:active,
  .tm-flip-btn-bottom:active,
  .tm-flip-btn-left:active,
  .tm-flip-btn-right:active {
    transform: scale(0.95);
  }

  /* --------------------------------------------------------------------------
     FLIP FACES
     Both faces stack in the same grid cell
     -------------------------------------------------------------------------- */
  .tm-flip-front,
  .tm-flip-back {
    grid-area: 1 / 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    backface-visibility: hidden;
    transition-property: transform, opacity;
    transition-duration: var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-flip-spring));
    transition-delay: var(--tm-delay, 0ms);
  }

  /* --------------------------------------------------------------------------
     FLIP FROM TOP (default)
     rotateX axis, Y translation
     -------------------------------------------------------------------------- */
  .tm-flip-btn .tm-flip-front,
  .tm-flip-btn-top .tm-flip-front {
    opacity: 1;
    transform: rotateX(0deg) translateY(0);
  }

  .tm-flip-btn .tm-flip-back,
  .tm-flip-btn-top .tm-flip-back {
    opacity: 0;
    transform: rotateX(-90deg) translateY(-50%);
  }

  .tm-flip-btn:hover .tm-flip-front,
  .tm-flip-btn-top:hover .tm-flip-front,
  .tm-flip-btn:focus-visible .tm-flip-front,
  .tm-flip-btn-top:focus-visible .tm-flip-front {
    opacity: 0;
    transform: rotateX(90deg) translateY(50%);
  }

  .tm-flip-btn:hover .tm-flip-back,
  .tm-flip-btn-top:hover .tm-flip-back,
  .tm-flip-btn:focus-visible .tm-flip-back,
  .tm-flip-btn-top:focus-visible .tm-flip-back {
    opacity: 1;
    transform: rotateX(0deg) translateY(0);
  }

  /* --------------------------------------------------------------------------
     FLIP FROM BOTTOM
     rotateX axis, Y translation (inverted)
     -------------------------------------------------------------------------- */
  .tm-flip-btn-bottom .tm-flip-front {
    opacity: 1;
    transform: rotateX(0deg) translateY(0);
  }

  .tm-flip-btn-bottom .tm-flip-back {
    opacity: 0;
    transform: rotateX(90deg) translateY(50%);
  }

  .tm-flip-btn-bottom:hover .tm-flip-front,
  .tm-flip-btn-bottom:focus-visible .tm-flip-front {
    opacity: 0;
    transform: rotateX(-90deg) translateY(-50%);
  }

  .tm-flip-btn-bottom:hover .tm-flip-back,
  .tm-flip-btn-bottom:focus-visible .tm-flip-back {
    opacity: 1;
    transform: rotateX(0deg) translateY(0);
  }

  /* --------------------------------------------------------------------------
     FLIP FROM LEFT
     rotateY axis, X translation
     -------------------------------------------------------------------------- */
  .tm-flip-btn-left .tm-flip-front {
    opacity: 1;
    transform: rotateY(0deg) translateX(0);
  }

  .tm-flip-btn-left .tm-flip-back {
    opacity: 0;
    transform: rotateY(-90deg) translateX(-50%);
  }

  .tm-flip-btn-left:hover .tm-flip-front,
  .tm-flip-btn-left:focus-visible .tm-flip-front {
    opacity: 0;
    transform: rotateY(90deg) translateX(50%);
  }

  .tm-flip-btn-left:hover .tm-flip-back,
  .tm-flip-btn-left:focus-visible .tm-flip-back {
    opacity: 1;
    transform: rotateY(0deg) translateX(0);
  }

  /* --------------------------------------------------------------------------
     FLIP FROM RIGHT
     rotateY axis, X translation (inverted)
     -------------------------------------------------------------------------- */
  .tm-flip-btn-right .tm-flip-front {
    opacity: 1;
    transform: rotateY(0deg) translateX(0);
  }

  .tm-flip-btn-right .tm-flip-back {
    opacity: 0;
    transform: rotateY(90deg) translateX(50%);
  }

  .tm-flip-btn-right:hover .tm-flip-front,
  .tm-flip-btn-right:focus-visible .tm-flip-front {
    opacity: 0;
    transform: rotateY(-90deg) translateX(-50%);
  }

  .tm-flip-btn-right:hover .tm-flip-back,
  .tm-flip-btn-right:focus-visible .tm-flip-back {
    opacity: 1;
    transform: rotateY(0deg) translateX(0);
  }

  /* --------------------------------------------------------------------------
     FLIP HOVER (simple 180° flip)
     Classic flip effect on hover
     -------------------------------------------------------------------------- */
  .tm-flip-hover {
    perspective: 1200px;
    transform-style: preserve-3d;
    backface-visibility: hidden;
  }

  .tm-flip-hover:hover,
  .tm-flip-hover:focus-visible {
    animation-name: tm-flip;
    animation-duration: var(--tm-duration, calc(320ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, ease-in-out);
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }
}

@keyframes tm-flip {
  0% {
    transform: rotateY(0deg);
  }

  50% {
    transform: rotateY(90deg);
  }

  100% {
    transform: rotateY(180deg);
  }
}

/* ==========================================================================
   STANDALONE FLIP ANIMATIONS
   Simple flip-in entrance animations
   ========================================================================== */

@layer utilities {
  /* Flip X - horizontal flip (around X axis) */
  .tm-flip-x {
    animation-name: tm-flip-x;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, ease-out);
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
    backface-visibility: visible;
  }

  /* Flip Y - vertical flip (around Y axis) */
  .tm-flip-y {
    animation-name: tm-flip-y;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, ease-out);
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
    backface-visibility: visible;
  }
}

@keyframes tm-flip-x {
  0% {
    transform: perspective(400px) rotateX(90deg);
    opacity: 0;
  }

  40% {
    transform: perspective(400px) rotateX(-20deg);
    opacity: 1;
  }

  60% {
    transform: perspective(400px) rotateX(10deg);
  }

  80% {
    transform: perspective(400px) rotateX(-5deg);
  }

  100% {
    transform: perspective(400px) rotateX(0deg);
    opacity: 1;
  }
}

@keyframes tm-flip-y {
  0% {
    transform: perspective(400px) rotateY(90deg);
    opacity: 0;
  }

  40% {
    transform: perspective(400px) rotateY(-20deg);
    opacity: 1;
  }

  60% {
    transform: perspective(400px) rotateY(10deg);
  }

  80% {
    transform: perspective(400px) rotateY(-5deg);
  }

  100% {
    transform: perspective(400px) rotateY(0deg);
    opacity: 1;
  }
}


/* --- src/animations/bounce.css --- */
@layer utilities {
  .tm-bounce {
    animation-name: tm-bounce;
    animation-duration: var(--tm-duration, calc(900ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.68, -0.55, 0.27, 1.55));
    animation-iteration-count: var(--tm-iteration-count, infinite);
    animation-fill-mode: both;
    transform-origin: center bottom;
    will-change: translate;
  }
}

@keyframes tm-bounce {
  0%,
  100% {
    translate: 0 0;
  }

  30% {
    translate: 0 calc(-18% * var(--tm-emphasis, 1));
  }

  50% {
    translate: 0 0;
  }

  70% {
    translate: 0 calc(-8% * var(--tm-emphasis, 1));
  }
}


/* --- src/animations/pulse.css --- */
@layer utilities {
  .tm-pulse {
    animation-name: tm-pulse;
    animation-duration: var(--tm-duration, calc(1400ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, ease-in-out);
    animation-iteration-count: var(--tm-iteration-count, infinite);
    animation-fill-mode: both;
    will-change: transform, opacity;
  }
}

@keyframes tm-pulse {
  0%,
  100% {
    scale: 1;
    opacity: 1;
  }

  50% {
    scale: calc(1 + 0.05 * var(--tm-emphasis, 1));
    opacity: 0.85;
  }
}


/* --- src/animations/wiggle.css --- */
@layer utilities {
  .tm-wiggle {
    animation-name: tm-wiggle;
    animation-duration: var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, ease-in-out);
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }
}

@keyframes tm-wiggle {
  0% {
    translate: 0 0;
  }

  20% {
    translate: -6px 0;
  }

  40% {
    translate: 6px 0;
  }

  60% {
    translate: -4px 0;
  }

  80% {
    translate: 4px 0;
  }

  100% {
    translate: 0 0;
  }
}


/* --- src/animations/rotate.css --- */
@layer utilities {
  /* Rotate entrance. */
  .tm-rotate-in {
    animation-name: tm-rotate-in;
    animation-duration: var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  /* Hover and press rotation, as transitions so an early release retargets
     instead of replaying. */
  .tm-rotate-hover {
    transition-property: rotate;
    transition-duration: var(--tm-duration, calc(150ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-ease-interaction, ease-out));
  }

  .tm-rotate-hover:hover,
  .tm-rotate-hover:focus-visible {
    rotate: var(--tm-rotate, 6deg);
  }

  .tm-rotate-press {
    transition-property: scale, rotate;
    transition-duration: var(--tm-duration, calc(150ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-ease-interaction, ease-out));
  }

  .tm-rotate-press:active:not(:disabled):not([aria-disabled="true"]) {
    scale: var(--tm-press-scale, 0.96);
    rotate: var(--tm-rotate, -4deg);
  }
}

@keyframes tm-rotate-in {
  from {
    opacity: 0;
    rotate: calc(var(--tm-rotate-from, -6deg) * var(--tm-emphasis, 1));
    scale: var(--tm-scale-from, calc(1 - 0.04 * var(--tm-emphasis, 1)));
  }

  to {
    opacity: 1;
    rotate: 0deg;
    scale: 1;
  }
}


/* --- src/animations/shake.css --- */
@layer utilities {
  .tm-shake {
    animation-name: tm-shake;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.36, 0.07, 0.19, 0.97));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
    transform-origin: center;
  }
}

@keyframes tm-shake {
  0%,
  100% {
    translate: 0 0;
  }

  10%,
  30%,
  50%,
  70%,
  90% {
    translate: calc(-10px * var(--tm-emphasis, 1)) 0;
  }

  20%,
  40%,
  60%,
  80% {
    translate: calc(10px * var(--tm-emphasis, 1)) 0;
  }
}


/* --- src/animations/slide.css --- */
/* --------------------------------------------------------------------------
   Slide entrances, named on the logical axes so they mirror themselves in
   right-to-left contexts. Names describe the direction of travel:
   tm-slide-block-start moves toward the block-start edge, entering from below.

   Physical names (tm-slide-up/down/left/right) are kept as compatibility
   aliases of the logical classes.

   Travel distance comes from --tm-distance (12px), so tm-distance-* retunes
   every slide at once and a motion profile can shorten or lengthen the travel
   for a whole subtree.

   These animate the `translate` property, not `transform`, so a Tailwind
   `rotate-*` or `scale-*` on the same element survives the entrance.
   -------------------------------------------------------------------------- */

@layer utilities {
  .tm-slide-block-start,
  .tm-slide-up {
    animation-name: tm-slide-block-start;
    animation-duration: var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  .tm-slide-block-end,
  .tm-slide-down {
    animation-name: tm-slide-block-end;
    animation-duration: var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  .tm-slide-inline-start,
  .tm-slide-left {
    animation-name: tm-slide-inline-start;
    animation-duration: var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  .tm-slide-inline-end,
  .tm-slide-right {
    animation-name: tm-slide-inline-end;
    animation-duration: var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }
}

@keyframes tm-slide-block-start {
  from {
    opacity: 0;
    translate: 0 var(--tm-distance, 12px);
  }

  to {
    opacity: 1;
    translate: 0 0;
  }
}

@keyframes tm-slide-block-end {
  from {
    opacity: 0;
    translate: 0 calc(var(--tm-distance, 12px) * -1);
  }

  to {
    opacity: 1;
    translate: 0 0;
  }
}

@keyframes tm-slide-inline-start {
  from {
    opacity: 0;
    translate: calc(var(--tm-distance, 12px) * var(--tm-inline-flip, 1)) 0;
  }

  to {
    opacity: 1;
    translate: 0 0;
  }
}

@keyframes tm-slide-inline-end {
  from {
    opacity: 0;
    translate: calc(var(--tm-distance, 12px) * var(--tm-inline-flip, 1) * -1) 0;
  }

  to {
    opacity: 1;
    translate: 0 0;
  }
}


/* --- src/animations/fade.css --- */
@layer utilities {
  /* Fade in. Opacity only, so it composes predictably: pair it with a Tailwind
     transform utility, or reach for tm-slide-* / tm-scale-in when the entrance
     should travel. */
  .tm-fade-in {
    animation-name: tm-fade-in;
    animation-duration: var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, ease-out));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }
}

@keyframes tm-fade-in {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}


/* --- src/animations/pop.css --- */
/* --------------------------------------------------------------------------
   tm-pop: an entrance that arrives slightly small, passes the target, and
   settles.

   The two departures from rest are separately tunable, so a motion profile can
   keep the entrance and drop the overshoot:

     --tm-emphasis   scales the 0.15 the element starts below full size
     --tm-overshoot  scales the 0.05 it passes above it

   Animates the `scale` property rather than `transform`, so a Tailwind
   `rotate-*` or `translate-*` on the same element survives the animation.
   -------------------------------------------------------------------------- */

@layer utilities {
  .tm-pop {
    animation-name: tm-pop;
    animation-duration: var(--tm-duration, calc(380ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.18, 0.89, 0.32, 1.28)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }
}

@keyframes tm-pop {
  0% {
    scale: calc(1 - 0.15 * var(--tm-emphasis, 1));
    opacity: 0;
  }

  70% {
    scale: calc(1 + 0.05 * var(--tm-overshoot, 1));
    opacity: 1;
  }

  100% {
    scale: 1;
    opacity: 1;
  }
}


/* --- src/animations/glow.css --- */
@layer utilities {
  /* Soft pulsing halo. The color comes from --tm-glow-color, which derives from
     the element's own currentColor by default; set it to any value (alpha
     included) to theme the effect. Never rely on the glow alone to signal a
     state -- pair it with a label, icon or focus ring. */
  .tm-glow {
    animation-name: tm-glow;
    animation-duration: var(--tm-duration, calc(1600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, ease-in-out);
    animation-iteration-count: var(--tm-iteration-count, infinite);
    animation-fill-mode: both;
  }
}

@keyframes tm-glow {
  0%,
  100% {
    box-shadow: 0 0 0 0 var(--tm-glow-color);
  }

  50% {
    box-shadow: 0 0 var(--tm-glow-size, 18px) var(--tm-glow-spread, 0) var(--tm-glow-color);
  }
}


/* --- src/animations/spin.css --- */
@layer utilities {
  .tm-spin {
    animation-name: tm-spin;
    animation-duration: var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, linear);
    animation-iteration-count: var(--tm-iteration-count, infinite);
    animation-fill-mode: both;
    will-change: transform;
  }
}

@keyframes tm-spin {
  0% {
    rotate: 0deg;
  }

  100% {
    rotate: 360deg;
  }
}


/* --- src/animations/float.css --- */
@layer utilities {
  .tm-float {
    animation-name: tm-float;
    animation-duration: var(--tm-duration, calc(3000ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, ease-in-out);
    animation-iteration-count: var(--tm-iteration-count, infinite);
    animation-fill-mode: both;
    will-change: transform;
  }
}

@keyframes tm-float {
  0% {
    translate: 0 0;
  }

  50% {
    translate: 0 calc(-6px * var(--tm-emphasis, 1));
  }

  100% {
    translate: 0 0;
  }
}


/* --- src/animations/zoom.css --- */
/* --------------------------------------------------------------------------
   Scale entrances.

   tm-scale-in is the short, neutral default: scale up from --tm-scale-from
   with a fade, no overshoot. tm-zoom-in / tm-zoom-out are the older, more
   expressive variants; despite its name tm-zoom-out is an *entrance* that
   settles in from a larger scale. For a real exit use tm-scale-out.

   All three animate the `scale` and `translate` properties rather than
   `transform`, so a Tailwind `rotate-*` or `-translate-*` on the same element
   is not erased. Departure from rest scales with --tm-emphasis, and the frames
   that pass the target scale with --tm-overshoot.
   -------------------------------------------------------------------------- */

@layer utilities {
  .tm-scale-in {
    animation-name: tm-scale-in;
    animation-duration: var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  .tm-zoom-in {
    animation-name: tm-zoom-in;
    animation-duration: var(--tm-duration, calc(520ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.19, 1, 0.22, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  .tm-zoom-in-slow {
    animation-name: tm-zoom-in;
    animation-duration: var(--tm-duration, calc(900ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.25, 0.8, 0.25, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  .tm-zoom-out {
    animation-name: tm-zoom-out;
    animation-duration: var(--tm-duration, calc(520ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.19, 1, 0.22, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }
}

@keyframes tm-scale-in {
  from {
    opacity: 0;
    scale: var(--tm-scale-from, calc(1 - 0.06 * var(--tm-emphasis, 1)));
  }

  to {
    opacity: 1;
    scale: 1;
  }
}

@keyframes tm-zoom-in {
  0% {
    scale: calc(1 - 0.08 * var(--tm-emphasis, 1));
    translate: 0 calc(var(--tm-distance, 12px) * 0.66);
    opacity: 0;
  }

  60% {
    scale: calc(1 + 0.02 * var(--tm-overshoot, 1));
    translate: 0 calc(var(--tm-distance, 12px) * -0.17 * var(--tm-overshoot, 1));
    opacity: 1;
  }

  100% {
    scale: 1;
    translate: 0 0;
    opacity: 1;
  }
}

@keyframes tm-zoom-out {
  0% {
    scale: calc(1 + 0.1 * var(--tm-emphasis, 1));
    opacity: 0;
  }

  60% {
    scale: calc(1 - 0.02 * var(--tm-overshoot, 1));
    opacity: 1;
  }

  100% {
    scale: 1;
    opacity: 1;
  }
}


/* --- src/animations/drop.css --- */
/* --------------------------------------------------------------------------
   tm-drop-in: falls from above, compresses slightly, settles.

   The fall derives from --tm-distance so a motion profile or tm-distance-*
   retunes it; --tm-drop-distance overrides the derived value outright. The
   squash-and-settle frames are governed by --tm-overshoot, so a calm profile
   drops the element into place without the bounce.
   -------------------------------------------------------------------------- */

@layer utilities {
  .tm-drop,
  .tm-drop-in {
    animation-name: tm-drop-in;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
    transform-origin: top center;
  }
}

@keyframes tm-drop-in {
  0% {
    opacity: 0;
    translate: 0
      calc(var(--tm-drop-distance, calc(var(--tm-distance, 12px) * 3.3)) * -1);
    scale: 1 calc(1 + 0.08 * var(--tm-emphasis, 1));
  }

  60% {
    opacity: 1;
    translate: 0 calc(var(--tm-distance, 12px) * 0.33 * var(--tm-overshoot, 1));
    scale: 1 calc(1 - 0.02 * var(--tm-overshoot, 1));
  }

  80% {
    translate: 0 calc(var(--tm-distance, 12px) * -0.17 * var(--tm-overshoot, 1));
    scale: 1 calc(1 + 0.01 * var(--tm-overshoot, 1));
  }

  100% {
    opacity: 1;
    translate: 0 0;
    scale: 1 1;
  }
}


/* --- src/animations/drift.css --- */
@layer utilities {
  .tm-drift {
    animation-name: tm-drift;
    animation-duration: var(--tm-duration, calc(2800ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, ease-in-out);
    animation-iteration-count: var(--tm-iteration-count, infinite);
    animation-fill-mode: both;
    will-change: transform;
  }
}

@keyframes tm-drift {
  0% {
    translate: 0 0;
  }

  25% {
    translate: 6px -2px;
  }

  50% {
    translate: 0 0;
  }

  75% {
    translate: -6px 2px;
  }

  100% {
    translate: 0 0;
  }
}


/* --- src/animations/lift.css --- */
/* Compatibility alias. tm-hover-lift is the canonical name and lives in
   interactions.css; tm-lift-hover is kept for pre-0.6 markup.

   Unlike the pre-0.6 version this is a transition, so releasing hover
   mid-animation reverses smoothly instead of snapping, and it no longer forces
   `display: inline-flex` on the element. */

@layer utilities {
  .tm-lift-hover {
    transition-property: translate, box-shadow;
    transition-duration: var(--tm-duration, calc(150ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-ease-interaction, ease-out));
  }

  .tm-lift-hover:hover,
  .tm-lift-hover:focus-visible {
    translate: 0 calc(var(--tm-lift-distance, 4px) * -1);
    box-shadow: var(--tm-lift-shadow, 0 8px 24px -8px var(--tm-shadow-color));
  }
}


/* --- src/animations/shimmer.css --- */
/* --------------------------------------------------------------------------
   Sweeping highlight.

   tm-shimmer runs continuously, for loading and skeleton states.
   tm-shimmer-hover sweeps once per hover.

   The highlight is --tm-shimmer-color (the element's own currentColor by
   default, never a hardcoded white) at --tm-shimmer-opacity strength. Color
   and strength are separate knobs because a gradient holding a color-mix()
   stop loses its interpolation hint; keeping them apart lets the gradient
   interpolate in oklab, so the fade to transparent stays even instead of
   dipping toward gray.
   -------------------------------------------------------------------------- */

@layer utilities {
  .tm-shimmer,
  .tm-shimmer-hover {
    position: relative;
    overflow: hidden;
    isolation: isolate;
  }

  .tm-shimmer::after,
  .tm-shimmer-hover::after {
    content: '';
    position: absolute;
    inset: 0;
    background-image: linear-gradient(
      var(--tm-shimmer-angle, 100deg),
      transparent 35%,
      var(--tm-shimmer-color) 50%,
      transparent 65%
    );
    pointer-events: none;
    z-index: 1;
  }

  @supports (background-image: linear-gradient(in oklab, red, red)) {
    .tm-shimmer::after,
    .tm-shimmer-hover::after {
      background-image: linear-gradient(
        in oklab var(--tm-shimmer-angle, 100deg),
        transparent 35%,
        var(--tm-shimmer-color) 50%,
        transparent 65%
      );
    }
  }

  .tm-shimmer::after {
    opacity: var(--tm-shimmer-opacity, 0.35);
    animation-name: tm-shimmer;
    animation-duration: var(--tm-duration, calc(1600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, linear);
    animation-iteration-count: var(--tm-iteration-count, infinite);
    animation-fill-mode: both;
    will-change: transform;
  }

  .tm-shimmer-hover::after {
    opacity: 0;
    transform: translate3d(-100%, 0, 0);
  }

  .tm-shimmer-hover:hover::after,
  .tm-shimmer-hover:focus-visible::after {
    animation-name: tm-shimmer-hover;
    animation-duration: var(--tm-duration, calc(900ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.4, 0, 0.2, 1));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: forwards;
  }
}

@keyframes tm-shimmer {
  from {
    transform: translate3d(-100%, 0, 0);
  }

  to {
    transform: translate3d(100%, 0, 0);
  }
}

@keyframes tm-shimmer-hover {
  0% {
    opacity: 0;
    transform: translate3d(-100%, 0, 0);
  }

  25% {
    opacity: var(--tm-shimmer-opacity, 0.35);
  }

  100% {
    opacity: 0;
    transform: translate3d(100%, 0, 0);
  }
}


/* --- src/animations/avatar-group.css --- */
/* ==========================================================================
   AVATAR GROUP SYSTEM
   Overlapping avatar stack with hover lift and optional tooltips.
   Works with TailMotion utilities: tm-duration-*, tm-delay-*, tm-ease-*
   ========================================================================== */

@layer base {
  :root,
  :host {
    /* Avatar group specific defaults */
    --tm-avatar-overlap: -0.75rem;
    --tm-avatar-gap: 0.25rem;
    --tm-avatar-lift: -30%;
    --tm-avatar-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  }
}

@layer utilities {
  /* --------------------------------------------------------------------------
     Container: .tm-avatar-group
     Flex container for stacked avatars
     -------------------------------------------------------------------------- */
  .tm-avatar-group,
  .tm-avatar-group-invert {
    display: flex;
    align-items: center;
  }

  /* --------------------------------------------------------------------------
     Avatar Item: .tm-avatar
     Individual avatar with overlap and hover lift
     -------------------------------------------------------------------------- */
  .tm-avatar {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    transition-property: transform, margin-inline-start;
    transition-duration: var(--tm-duration, calc(200ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-avatar-spring));
    transition-delay: var(--tm-delay, 0ms);
    cursor: pointer;
  }

  /* Overlap: all but first avatar gets negative margin */
  .tm-avatar-group .tm-avatar:not(:first-child),
  .tm-avatar-group-invert .tm-avatar:not(:first-child) {
    margin-inline-start: var(--tm-avatar-overlap);
  }

  /* Group hover/focus: spread the stack so every avatar is reachable */
  .tm-avatar-group:is(:hover, :focus-within) .tm-avatar:not(:first-child),
  .tm-avatar-group-invert:is(:hover, :focus-within) .tm-avatar:not(:first-child) {
    margin-inline-start: var(--tm-avatar-gap);
  }

  /* Z-index stacking: later avatars on top (default) */
  .tm-avatar-group .tm-avatar:nth-child(1) { z-index: 1; }
  .tm-avatar-group .tm-avatar:nth-child(2) { z-index: 2; }
  .tm-avatar-group .tm-avatar:nth-child(3) { z-index: 3; }
  .tm-avatar-group .tm-avatar:nth-child(4) { z-index: 4; }
  .tm-avatar-group .tm-avatar:nth-child(5) { z-index: 5; }
  .tm-avatar-group .tm-avatar:nth-child(6) { z-index: 6; }
  .tm-avatar-group .tm-avatar:nth-child(7) { z-index: 7; }
  .tm-avatar-group .tm-avatar:nth-child(8) { z-index: 8; }
  .tm-avatar-group .tm-avatar:nth-child(9) { z-index: 9; }
  .tm-avatar-group .tm-avatar:nth-child(10) { z-index: 10; }

  /* Inverted stacking: first avatars on top */
  .tm-avatar-group-invert .tm-avatar:nth-child(1) { z-index: 10; }
  .tm-avatar-group-invert .tm-avatar:nth-child(2) { z-index: 9; }
  .tm-avatar-group-invert .tm-avatar:nth-child(3) { z-index: 8; }
  .tm-avatar-group-invert .tm-avatar:nth-child(4) { z-index: 7; }
  .tm-avatar-group-invert .tm-avatar:nth-child(5) { z-index: 6; }
  .tm-avatar-group-invert .tm-avatar:nth-child(6) { z-index: 5; }
  .tm-avatar-group-invert .tm-avatar:nth-child(7) { z-index: 4; }
  .tm-avatar-group-invert .tm-avatar:nth-child(8) { z-index: 3; }
  .tm-avatar-group-invert .tm-avatar:nth-child(9) { z-index: 2; }
  .tm-avatar-group-invert .tm-avatar:nth-child(10) { z-index: 1; }

  /* Hover: lift avatar up */
  .tm-avatar:hover,
  .tm-avatar:focus-visible {
    transform: translateY(var(--tm-avatar-lift));
    z-index: 50 !important;
  }

  /* --------------------------------------------------------------------------
     Tooltip: .tm-avatar-tooltip
     Optional tooltip that appears above avatar on hover
     -------------------------------------------------------------------------- */
  .tm-avatar-tooltip {
    position: absolute;
    bottom: calc(100% + 12px);
    left: 50%;
    transform: translateX(-50%) translateY(8px) scale(0.95);
    opacity: 0;
    visibility: hidden;
    white-space: nowrap;
    padding: 0.5rem 0.75rem;
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1;
    color: var(--tm-tooltip-color, CanvasText);
    background: var(--tm-tooltip-bg, Canvas);
    border-radius: 0.5rem;
    box-shadow: var(
      --tm-tooltip-shadow,
      0 4px 6px -1px var(--tm-shadow-color),
      0 2px 4px -2px var(--tm-shadow-color)
    );
    pointer-events: none;
    transition-property: opacity, transform, visibility;
    transition-duration: var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, cubic-bezier(0.16, 1, 0.3, 1));
    transition-delay: var(--tm-delay, 0ms);
    z-index: 100;
  }

  /* Tooltip arrow */
  .tm-avatar-tooltip::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 6px solid transparent;
    border-top-color: var(--tm-tooltip-bg, Canvas);
  }

  /* Show tooltip on hover */
  .tm-avatar:hover .tm-avatar-tooltip,
  .tm-avatar:focus-visible .tm-avatar-tooltip {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0) scale(1);
  }

  /* --------------------------------------------------------------------------
     Tooltip Positions
     -------------------------------------------------------------------------- */

  /* Bottom tooltip */
  .tm-avatar-tooltip-bottom {
    bottom: auto;
    top: calc(100% + 12px);
    transform: translateX(-50%) translateY(-8px) scale(0.95);
  }

  .tm-avatar-tooltip-bottom::after {
    top: auto;
    bottom: 100%;
    border-top-color: transparent;
    border-bottom-color: var(--tm-tooltip-bg, Canvas);
  }

  .tm-avatar:hover .tm-avatar-tooltip-bottom,
  .tm-avatar:focus-visible .tm-avatar-tooltip-bottom {
    transform: translateX(-50%) translateY(0) scale(1);
  }

  /* Left tooltip */
  .tm-avatar-tooltip-left {
    bottom: auto;
    top: 50%;
    left: auto;
    right: calc(100% + 12px);
    transform: translateY(-50%) translateX(8px) scale(0.95);
  }

  .tm-avatar-tooltip-left::after {
    top: 50%;
    left: 100%;
    transform: translateY(-50%);
    border-top-color: transparent;
    border-left-color: var(--tm-tooltip-bg, Canvas);
  }

  .tm-avatar:hover .tm-avatar-tooltip-left,
  .tm-avatar:focus-visible .tm-avatar-tooltip-left {
    transform: translateY(-50%) translateX(0) scale(1);
  }

  /* Right tooltip */
  .tm-avatar-tooltip-right {
    bottom: auto;
    top: 50%;
    left: calc(100% + 12px);
    transform: translateY(-50%) translateX(-8px) scale(0.95);
  }

  .tm-avatar-tooltip-right::after {
    top: 50%;
    left: auto;
    right: 100%;
    transform: translateY(-50%);
    border-top-color: transparent;
    border-right-color: var(--tm-tooltip-bg, Canvas);
  }

  .tm-avatar:hover .tm-avatar-tooltip-right,
  .tm-avatar:focus-visible .tm-avatar-tooltip-right {
    transform: translateY(-50%) translateX(0) scale(1);
  }

  /* --------------------------------------------------------------------------
     Size Variants (overlap amount)
     -------------------------------------------------------------------------- */
  .tm-avatar-sm {
    --tm-avatar-overlap: -0.5rem;
  }

  .tm-avatar-lg {
    --tm-avatar-overlap: -1rem;
  }

  .tm-avatar-xl {
    --tm-avatar-overlap: -1.25rem;
  }

  /* --------------------------------------------------------------------------
     Lift Amount Variants
     -------------------------------------------------------------------------- */
  .tm-avatar-lift-sm {
    --tm-avatar-lift: -15%;
  }

  .tm-avatar-lift-lg {
    --tm-avatar-lift: -45%;
  }

  .tm-avatar-lift-none {
    --tm-avatar-lift: 0;
  }

  /* --------------------------------------------------------------------------
     Ring/Border on hover
     -------------------------------------------------------------------------- */
  .tm-avatar-ring {
    box-shadow: 0 0 0 0 transparent;
    transition-property: transform, box-shadow;
    transition-duration: var(--tm-duration, calc(200ms * var(--tm-duration-scale, 1)));
    transition-timing-function: var(--tm-easing, var(--tm-avatar-spring));
    transition-delay: var(--tm-delay, 0ms);
  }

  .tm-avatar-ring:hover,
  .tm-avatar-ring:focus-visible {
    box-shadow: 0 0 0 var(--tm-ring-width, 3px) var(--tm-outline-color);
  }
}


/* --- src/animations/morph.css --- */
@layer utilities {
  .tm-morph {
    animation-name: tm-morph;
    animation-duration: var(--tm-duration, calc(4000ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.45, 0.05, 0.55, 0.95));
    animation-iteration-count: var(--tm-iteration-count, infinite);
    animation-fill-mode: both;
    will-change: transform;
  }
}

@keyframes tm-morph {
  0%,
  100% {
    transform: scale(1) rotate(0deg);
    border-radius: inherit;
  }

  25% {
    transform: scale(1.02, 0.98) rotate(0.5deg);
  }

  50% {
    transform: scale(0.98, 1.02) rotate(-0.5deg);
  }

  75% {
    transform: scale(1.01, 0.99) rotate(0.3deg);
  }
}


/* --- src/animations/sway.css --- */
@layer utilities {
  .tm-sway {
    animation-name: tm-sway;
    animation-duration: var(--tm-duration, calc(3500ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.37, 0, 0.63, 1));
    animation-iteration-count: var(--tm-iteration-count, infinite);
    animation-fill-mode: both;
    transform-origin: top center;
    will-change: transform;
  }
}

@keyframes tm-sway {
  0%,
  100% {
    transform: rotate(0deg) translateX(0);
  }

  25% {
    transform: rotate(2deg) translateX(3px);
  }

  50% {
    transform: rotate(0deg) translateX(0);
  }

  75% {
    transform: rotate(-2deg) translateX(-3px);
  }
}


/* --- src/animations/ripple.css --- */
@layer utilities {
  /* Expanding ring, for drawing attention to a live control. The ring color
     comes from --tm-outline-color, derived from currentColor by default. */
  .tm-ripple {
    animation-name: tm-ripple;
    animation-duration: var(--tm-duration, calc(1800ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.25, 0.46, 0.45, 0.94));
    animation-iteration-count: var(--tm-iteration-count, infinite);
    animation-fill-mode: both;
    will-change: transform;
  }
}

@keyframes tm-ripple {
  0% {
    transform: scale(1);
    box-shadow: 0 0 0 0 var(--tm-outline-color);
  }

  40% {
    transform: scale(1.03);
    box-shadow: 0 0 0 var(--tm-ripple-size, 10px) transparent;
  }

  100% {
    transform: scale(1);
    box-shadow: 0 0 0 0 transparent;
  }
}


/* --- src/animations/swing.css --- */
@layer utilities {
  .tm-swing-in {
    animation-name: tm-swing-in;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.68, -0.55, 0.265, 1.55));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
    transform-origin: top center;
  }

  .tm-swing-out {
    animation-name: tm-swing-out;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.68, -0.55, 0.265, 1.55));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
    transform-origin: top center;
  }

  .tm-swing-in-left {
    animation-name: tm-swing-in-left;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.68, -0.55, 0.265, 1.55));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
    transform-origin: center left;
  }

  .tm-swing-out-left {
    animation-name: tm-swing-out-left;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.68, -0.55, 0.265, 1.55));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
    transform-origin: center left;
  }

  .tm-swing-in-right {
    animation-name: tm-swing-in-right;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.68, -0.55, 0.265, 1.55));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
    transform-origin: center right;
  }

  .tm-swing-out-right {
    animation-name: tm-swing-out-right;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.68, -0.55, 0.265, 1.55));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
    transform-origin: center right;
  }
}

@keyframes tm-swing-in {
  0% {
    transform: rotateX(-100deg);
    opacity: 0;
  }

  60% {
    transform: rotateX(15deg);
    opacity: 1;
  }

  100% {
    transform: rotateX(0deg);
    opacity: 1;
  }
}

@keyframes tm-swing-out {
  0% {
    transform: rotateX(0deg);
    opacity: 1;
  }

  40% {
    transform: rotateX(15deg);
    opacity: 1;
  }

  100% {
    transform: rotateX(-100deg);
    opacity: 0;
  }
}

@keyframes tm-swing-in-left {
  0% {
    transform: rotateY(-100deg);
    opacity: 0;
  }

  60% {
    transform: rotateY(15deg);
    opacity: 1;
  }

  100% {
    transform: rotateY(0deg);
    opacity: 1;
  }
}

@keyframes tm-swing-out-left {
  0% {
    transform: rotateY(0deg);
    opacity: 1;
  }

  40% {
    transform: rotateY(15deg);
    opacity: 1;
  }

  100% {
    transform: rotateY(-100deg);
    opacity: 0;
  }
}

@keyframes tm-swing-in-right {
  0% {
    transform: rotateY(100deg);
    opacity: 0;
  }

  60% {
    transform: rotateY(-15deg);
    opacity: 1;
  }

  100% {
    transform: rotateY(0deg);
    opacity: 1;
  }
}

@keyframes tm-swing-out-right {
  0% {
    transform: rotateY(0deg);
    opacity: 1;
  }

  40% {
    transform: rotateY(-15deg);
    opacity: 1;
  }

  100% {
    transform: rotateY(100deg);
    opacity: 0;
  }
}


/* --- src/animations/wavy.css --- */
@layer utilities {
  .tm-wavy-bg {
    --tm-wavy-color1: rgba(59, 130, 246, 0.1);
    --tm-wavy-color2: rgba(147, 51, 234, 0.1);
    --tm-wavy-color3: rgba(16, 185, 129, 0.1);
    --tm-wavy-speed: 8s;
    --tm-wavy-blur: 40px;
    position: relative;
    background:
      radial-gradient(circle at 20% 80%, var(--tm-wavy-color1) 0%, transparent 50%),
      radial-gradient(circle at 80% 20%, var(--tm-wavy-color2) 0%, transparent 50%),
      radial-gradient(circle at 40% 40%, var(--tm-wavy-color3) 0%, transparent 50%);
    background-size: 400% 400%;
    animation: tm-wavy-bg var(--tm-wavy-speed) ease-in-out infinite;
  }

  .tm-wavy-bg::before {
    content: '';
    position: absolute;
    inset: 0;
    background:
      linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.05) 50%, transparent 70%),
      linear-gradient(-45deg, transparent 30%, rgba(255, 255, 255, 0.05) 50%, transparent 70%);
    background-size: 200% 200%;
    animation: tm-wavy-overlay calc(var(--tm-wavy-speed) * 0.7) ease-in-out infinite reverse;
    pointer-events: none;
  }

  .tm-wavy-bg::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
      radial-gradient(circle at 60% 70%, rgba(99, 102, 241, 0.08) 0%, transparent 40%),
      radial-gradient(circle at 30% 30%, rgba(244, 63, 94, 0.06) 0%, transparent 40%);
    filter: blur(var(--tm-wavy-blur));
    animation: tm-wavy-blur calc(var(--tm-wavy-speed) * 1.2) ease-in-out infinite;
    pointer-events: none;
  }

  /* Wavy background with subtle movement */
  .tm-wavy-bg-subtle {
    --tm-wavy-color1: rgba(59, 130, 246, 0.05);
    --tm-wavy-color2: rgba(147, 51, 234, 0.05);
    --tm-wavy-color3: rgba(16, 185, 129, 0.05);
    --tm-wavy-speed: 12s;
    --tm-wavy-blur: 60px;
    position: relative;
    background:
      radial-gradient(ellipse at 30% 70%, var(--tm-wavy-color1) 0%, transparent 60%),
      radial-gradient(ellipse at 70% 30%, var(--tm-wavy-color2) 0%, transparent 60%),
      radial-gradient(ellipse at 50% 50%, var(--tm-wavy-color3) 0%, transparent 60%);
    background-size: 300% 300%;
    animation: tm-wavy-bg-subtle var(--tm-wavy-speed) ease-in-out infinite;
  }

  .tm-wavy-bg-subtle::before {
    content: '';
    position: absolute;
    inset: 0;
    background:
      linear-gradient(60deg, transparent 40%, rgba(255, 255, 255, 0.03) 50%, transparent 60%);
    background-size: 150% 150%;
    animation: tm-wavy-overlay-subtle calc(var(--tm-wavy-speed) * 0.8) ease-in-out infinite reverse;
    pointer-events: none;
  }

  /* Wavy background fast */
  .tm-wavy-bg-fast {
    --tm-wavy-speed: 4s;
  }

  /* Wavy background slow */
  .tm-wavy-bg-slow {
    --tm-wavy-speed: 16s;
  }

  /* Wavy background with different color schemes */
  .tm-wavy-bg-blue {
    --tm-wavy-color1: rgba(59, 130, 246, 0.15);
    --tm-wavy-color2: rgba(37, 99, 235, 0.1);
    --tm-wavy-color3: rgba(147, 197, 253, 0.08);
  }

  .tm-wavy-bg-purple {
    --tm-wavy-color1: rgba(147, 51, 234, 0.15);
    --tm-wavy-color2: rgba(124, 58, 237, 0.1);
    --tm-wavy-color3: rgba(196, 181, 253, 0.08);
  }

  .tm-wavy-bg-emerald {
    --tm-wavy-color1: rgba(16, 185, 129, 0.15);
    --tm-wavy-color2: rgba(5, 150, 105, 0.1);
    --tm-wavy-color3: rgba(110, 231, 183, 0.08);
  }

  .tm-wavy-bg-rose {
    --tm-wavy-color1: rgba(244, 63, 94, 0.15);
    --tm-wavy-color2: rgba(225, 29, 72, 0.1);
    --tm-wavy-color3: rgba(253, 164, 175, 0.08);
  }
}

@keyframes tm-wavy-bg {
  0%, 100% {
    background-position: 0% 50%, 100% 50%, 50% 0%;
  }
  25% {
    background-position: 25% 75%, 75% 25%, 75% 75%;
  }
  50% {
    background-position: 50% 100%, 50% 0%, 0% 50%;
  }
  75% {
    background-position: 75% 25%, 25% 75%, 25% 25%;
  }
}

@keyframes tm-wavy-overlay {
  0%, 100% {
    background-position: 0% 0%;
  }
  50% {
    background-position: 100% 100%;
  }
}

@keyframes tm-wavy-blur {
  0%, 100% {
    opacity: 0.6;
    transform: scale(1) rotate(0deg);
  }
  33% {
    opacity: 0.8;
    transform: scale(1.1) rotate(120deg);
  }
  66% {
    opacity: 0.4;
    transform: scale(0.9) rotate(240deg);
  }
}

@keyframes tm-wavy-bg-subtle {
  0%, 100% {
    background-position: 0% 0%, 100% 100%, 50% 50%;
  }
  33% {
    background-position: 33% 66%, 66% 33%, 66% 66%;
  }
  66% {
    background-position: 66% 33%, 33% 66%, 33% 33%;
  }
}

@keyframes tm-wavy-overlay-subtle {
  0%, 100% {
    background-position: 0% 0%;
    opacity: 0.5;
  }
  50% {
    background-position: 50% 50%;
    opacity: 0.8;
  }
}


/* --- src/animations/hold-delete.css --- */
@layer utilities {
  .tm-hold-delete {
    --tm-hold-duration: 2s;
    --tm-hold-color: rgb(239, 68, 68);
    --tm-hold-bg: rgb(254, 242, 242);
    --tm-hold-success: rgb(34, 197, 94);
    --tm-hold-success-bg: rgb(254, 202, 202);
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.75rem 1.5rem;
    background-color: var(--tm-hold-bg);
    border-radius: 0.5rem;
    color: var(--tm-hold-color);
    font-weight: 500;
    cursor: pointer;
    user-select: none;
    transition-property: color, background-color, border-radius, transform;
    transition-duration: 150ms;
    transition-timing-function: ease-out;
    overflow: hidden;
    min-width: 120px;
    isolation: isolate;
  }

  .tm-hold-delete::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, transparent 0%, var(--tm-hold-color) 50%, transparent 100%);
    transform: translateX(-100%);
    transition: transform var(--tm-hold-duration) ease;
    z-index: -1;
  }

  .tm-hold-delete::after {
    content: '';
    position: absolute;
    inset: 2px;
    background: var(--tm-hold-success-bg);
    border-radius: calc(0.5rem - 2px);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform var(--tm-hold-duration) ease;
    z-index: -1;
  }

  .tm-hold-delete:active::before {
    transform: translateX(0%);
  }

  .tm-hold-delete:active::after {
    transform: scaleX(1);
  }

  .tm-hold-delete:active {
    color: var(--tm-hold-fg, Canvas);
    transform: scale(var(--tm-press-scale, 0.96));
    border-radius: 0.25rem;
  }

}


/* --- src/animations/blur-in.css --- */
@layer utilities {
  /* Resolves from blurred to sharp. Opacity and filter only, so it stacks with
     Tailwind transforms without fighting them. --tm-blur sets the starting
     radius; --tm-emphasis scales it, so a calm profile resolves from a softer
     blur without a per-element override. */
  .tm-blur-in {
    animation-name: tm-blur-in;
    animation-duration: var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, ease-out));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }
}

@keyframes tm-blur-in {
  from {
    opacity: 0;
    filter: blur(calc(var(--tm-blur, 8px) * var(--tm-emphasis, 1)));
  }

  to {
    opacity: 1;
    filter: blur(0);
  }
}


/* --- src/animations/dark-veil.css --- */
@layer utilities {
  .tm-dark-veil {
    --tm-dark-veil-hue: 0deg;
    --tm-dark-veil-saturation: 80%;
    --tm-dark-veil-lightness: 50%;
    --tm-dark-veil-opacity: 0.8;
    --tm-dark-veil-noise: 0.1;
    --tm-dark-veil-scanlines: 0.05;
    --tm-dark-veil-warp: 0.02;
    --tm-dark-veil-speed: 8s;
    --tm-dark-veil-blur: 0px;

    position: relative;
    overflow: hidden;
    background: hsl(var(--tm-dark-veil-hue), var(--tm-dark-veil-saturation), calc(var(--tm-dark-veil-lightness) * 0.2));
    filter: blur(var(--tm-dark-veil-blur));
  }

  .tm-dark-veil::before {
    content: '';
    position: absolute;
    inset: -50%;
    background:
      radial-gradient(
        circle at 20% 80%,
        hsl(calc(var(--tm-dark-veil-hue) + 0deg), var(--tm-dark-veil-saturation), calc(var(--tm-dark-veil-lightness) * 0.8)) 0%,
        transparent 50%
      ),
      radial-gradient(
        circle at 80% 20%,
        hsl(calc(var(--tm-dark-veil-hue) + 120deg), var(--tm-dark-veil-saturation), calc(var(--tm-dark-veil-lightness) * 0.6)) 0%,
        transparent 50%
      ),
      radial-gradient(
        circle at 40% 40%,
        hsl(calc(var(--tm-dark-veil-hue) + 240deg), var(--tm-dark-veil-saturation), calc(var(--tm-dark-veil-lightness) * 0.9)) 0%,
        transparent 50%
      );
    opacity: var(--tm-dark-veil-opacity);
    animation: tm-dark-veil-flow var(--tm-dark-veil-speed) ease-in-out infinite;
    will-change: transform, opacity;
  }

  .tm-dark-veil::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
      repeating-linear-gradient(
        0deg,
        transparent,
        transparent 2px,
        rgba(255, 255, 255, var(--tm-dark-veil-scanlines)) 2px,
        rgba(255, 255, 255, var(--tm-dark-veil-scanlines)) 4px
      );
    opacity: 0.3;
    animation: tm-dark-veil-scan var(--tm-dark-veil-speed) linear infinite;
    pointer-events: none;
  }

  /* Multiple layers for complex organic patterns */
  .tm-dark-veil-layer-1::before {
    background:
      conic-gradient(
        from 0deg at 50% 50%,
        hsl(calc(var(--tm-dark-veil-hue) + 0deg), var(--tm-dark-veil-saturation), calc(var(--tm-dark-veil-lightness) * 0.3)) 0deg,
        hsl(calc(var(--tm-dark-veil-hue) + 60deg), var(--tm-dark-veil-saturation), calc(var(--tm-dark-veil-lightness) * 0.7)) 120deg,
        hsl(calc(var(--tm-dark-veil-hue) + 180deg), var(--tm-dark-veil-saturation), calc(var(--tm-dark-veil-lightness) * 0.4)) 240deg,
        hsl(calc(var(--tm-dark-veil-hue) + 0deg), var(--tm-dark-veil-saturation), calc(var(--tm-dark-veil-lightness) * 0.3)) 360deg
      );
    animation: tm-dark-veil-rotate var(--tm-dark-veil-speed) linear infinite reverse;
  }

  .tm-dark-veil-layer-2::before {
    background:
      radial-gradient(
        ellipse 150% 100% at 30% 70%,
        hsl(calc(var(--tm-dark-veil-hue) + 30deg), var(--tm-dark-veil-saturation), calc(var(--tm-dark-veil-lightness) * 0.5)) 0%,
        transparent 70%
      ),
      radial-gradient(
        ellipse 120% 80% at 70% 30%,
        hsl(calc(var(--tm-dark-veil-hue) + 150deg), var(--tm-dark-veil-saturation), calc(var(--tm-dark-veil-lightness) * 0.6)) 0%,
        transparent 60%
      );
    animation: tm-dark-veil-morph calc(var(--tm-dark-veil-speed) * 0.7) ease-in-out infinite;
  }

  .tm-dark-veil-layer-3::before {
    background:
      repeating-conic-gradient(
        from 45deg at 50% 50%,
        hsl(calc(var(--tm-dark-veil-hue) + 90deg), var(--tm-dark-veil-saturation), calc(var(--tm-dark-veil-lightness) * 0.2)) 0deg 10deg,
        transparent 10deg 20deg
      );
    animation: tm-dark-veil-pulse calc(var(--tm-dark-veil-speed) * 1.3) ease-in-out infinite;
  }

  /* Noise overlay */
  .tm-dark-veil-noise::after {
    background:
      radial-gradient(circle at 25% 25%, rgba(255,255,255,var(--tm-dark-veil-noise)) 1px, transparent 1px),
      radial-gradient(circle at 75% 75%, rgba(0,0,0,var(--tm-dark-veil-noise)) 1px, transparent 1px),
      radial-gradient(circle at 50% 50%, rgba(255,255,255,var(--tm-dark-veil-noise)) 1px, transparent 1px);
    background-size: 20px 20px, 30px 30px, 40px 40px;
    animation: tm-dark-veil-noise-move calc(var(--tm-dark-veil-speed) * 0.5) linear infinite;
  }
}

@keyframes tm-dark-veil-flow {
  0%, 100% {
    transform: translate(0, 0) scale(1) rotate(0deg);
    filter: hue-rotate(0deg) saturate(1);
  }

  25% {
    transform: translate(calc(var(--tm-dark-veil-warp) * 100%), calc(var(--tm-dark-veil-warp) * -50%)) scale(1.05) rotate(1deg);
    filter: hue-rotate(30deg) saturate(1.2);
  }

  50% {
    transform: translate(calc(var(--tm-dark-veil-warp) * -50%), calc(var(--tm-dark-veil-warp) * 100%)) scale(0.95) rotate(-1deg);
    filter: hue-rotate(60deg) saturate(0.8);
  }

  75% {
    transform: translate(calc(var(--tm-dark-veil-warp) * 80%), calc(var(--tm-dark-veil-warp) * 30%)) scale(1.02) rotate(0.5deg);
    filter: hue-rotate(90deg) saturate(1.1);
  }
}

@keyframes tm-dark-veil-rotate {
  0% {
    transform: rotate(0deg) scale(1);
  }

  50% {
    transform: rotate(180deg) scale(1.1);
  }

  100% {
    transform: rotate(360deg) scale(1);
  }
}

@keyframes tm-dark-veil-morph {
  0%, 100% {
    border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
    transform: scale(1) rotate(0deg);
  }

  25% {
    border-radius: 30% 60% 70% 40% / 50% 60% 30% 60%;
    transform: scale(1.05) rotate(90deg);
  }

  50% {
    border-radius: 50% 50% 80% 20% / 80% 20% 50% 50%;
    transform: scale(0.95) rotate(180deg);
  }

  75% {
    border-radius: 70% 30% 50% 50% / 40% 60% 70% 30%;
    transform: scale(1.02) rotate(270deg);
  }
}

@keyframes tm-dark-veil-pulse {
  0%, 100% {
    opacity: 0.3;
    transform: scale(1) rotate(0deg);
  }

  50% {
    opacity: 0.8;
    transform: scale(1.2) rotate(180deg);
  }
}

@keyframes tm-dark-veil-scan {
  0% {
    transform: translateY(0);
  }

  100% {
    transform: translateY(4px);
  }
}

@keyframes tm-dark-veil-noise-move {
  0% {
    transform: translate(0, 0);
  }

  25% {
    transform: translate(5px, -3px);
  }

  50% {
    transform: translate(-3px, 5px);
  }

  75% {
    transform: translate(2px, 2px);
  }

  100% {
    transform: translate(0, 0);
  }
}

/* Color variants */
.tm-dark-veil-blue {
  --tm-dark-veil-hue: 220deg;
}

.tm-dark-veil-purple {
  --tm-dark-veil-hue: 270deg;
}

.tm-dark-veil-green {
  --tm-dark-veil-hue: 120deg;
}

.tm-dark-veil-red {
  --tm-dark-veil-hue: 0deg;
}

.tm-dark-veil-orange {
  --tm-dark-veil-hue: 30deg;
}

.tm-dark-veil-cyan {
  --tm-dark-veil-hue: 180deg;
}

/* Intensity variants */
.tm-dark-veil-subtle {
  --tm-dark-veil-opacity: 0.4;
  --tm-dark-veil-saturation: 60%;
}

.tm-dark-veil-intense {
  --tm-dark-veil-opacity: 1;
  --tm-dark-veil-saturation: 100%;
  --tm-dark-veil-lightness: 60%;
}

/* Speed variants */
.tm-dark-veil-fast {
  --tm-dark-veil-speed: 4s;
}

.tm-dark-veil-slow {
  --tm-dark-veil-speed: 12s;
}

/* Effect variants */
.tm-dark-veil-noisy {
  --tm-dark-veil-noise: 0.2;
}

.tm-dark-veil-warped {
  --tm-dark-veil-warp: 0.05;
}

.tm-dark-veil-blurry {
  --tm-dark-veil-blur: 2px;
}


/* --- src/animations/elastic.css --- */
@layer utilities {
  .tm-elastic {
    animation-name: tm-elastic;
    animation-duration: var(--tm-duration, calc(900ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.68, -0.6, 0.32, 1.6)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }
}

@keyframes tm-elastic {
  0% {
    scale: 0 0.5;
    opacity: 0;
  }

  40% {
    scale: calc(1 + 0.12 * var(--tm-overshoot, 1)) calc(1 - 0.12 * var(--tm-overshoot, 1));
    opacity: 1;
  }

  60% {
    scale: calc(1 - 0.08 * var(--tm-overshoot, 1)) calc(1 + 0.08 * var(--tm-overshoot, 1));
  }

  80% {
    scale: calc(1 + 0.04 * var(--tm-overshoot, 1)) calc(1 - 0.04 * var(--tm-overshoot, 1));
  }

  100% {
    scale: 1 1;
    opacity: 1;
  }
}


/* --- src/animations/celebrate.css --- */
@layer utilities {
  /* Sparkle - twinkling star effect */
  .tm-sparkle {
    animation-name: tm-sparkle;
    animation-duration: var(--tm-duration, calc(1400ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, ease-in-out);
    animation-iteration-count: var(--tm-iteration-count, infinite);
    animation-fill-mode: both;
    will-change: transform, opacity;
  }

  /* Fill Up - bottom to top reveal like star filling */
  .tm-fill-up {
    animation-name: tm-fill-up;
    animation-duration: var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  /* Burst - explosion outward effect */
  .tm-burst {
    animation-name: tm-burst;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.22, 1, 0.36, 1));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  /* Count reveal - slot machine number effect */
  .tm-count-reveal {
    display: inline-flex;
    overflow: hidden;
    vertical-align: bottom;
  }

  .tm-count-reveal > * {
    display: inline-block;
    animation-name: tm-count-slide;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: calc(
      var(--tm-delay, 0ms) + var(--tm-stagger, 0) * var(--tm-count-stagger-step, 50ms)
    );
    animation-timing-function: var(--tm-easing, cubic-bezier(0.16, 1, 0.3, 1));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  /* Auto-stagger children */
  .tm-count-reveal > *:nth-child(1) { --tm-stagger: 0; }
  .tm-count-reveal > *:nth-child(2) { --tm-stagger: 1; }
  .tm-count-reveal > *:nth-child(3) { --tm-stagger: 2; }
  .tm-count-reveal > *:nth-child(4) { --tm-stagger: 3; }
  .tm-count-reveal > *:nth-child(5) { --tm-stagger: 4; }
  .tm-count-reveal > *:nth-child(6) { --tm-stagger: 5; }
  .tm-count-reveal > *:nth-child(7) { --tm-stagger: 6; }
  .tm-count-reveal > *:nth-child(8) { --tm-stagger: 7; }
  .tm-count-reveal > *:nth-child(9) { --tm-stagger: 8; }
  .tm-count-reveal > *:nth-child(10) { --tm-stagger: 9; }

  /* Single digit slot animation */
  .tm-slide-digit {
    display: inline-block;
    overflow: hidden;
    vertical-align: bottom;
    animation-name: tm-count-slide;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.16, 1, 0.3, 1));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  /* Confetti - falling celebration particles */
  .tm-confetti {
    animation-name: tm-confetti;
    animation-duration: var(--tm-duration, calc(2500ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.25, 0.46, 0.45, 0.94));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }
}

@keyframes tm-sparkle {
  0%,
  100% {
    opacity: 1;
    transform: scale(1) rotate(0deg);
  }

  25% {
    opacity: 0.6;
    transform: scale(0.85) rotate(5deg);
  }

  50% {
    opacity: 1;
    transform: scale(1.1) rotate(-3deg);
  }

  75% {
    opacity: 0.8;
    transform: scale(0.95) rotate(2deg);
  }
}

@keyframes tm-fill-up {
  0% {
    clip-path: inset(100% 0 0 0);
    opacity: 0;
  }

  20% {
    opacity: 1;
  }

  100% {
    clip-path: inset(0 0 0 0);
    opacity: 1;
  }
}

@keyframes tm-burst {
  0% {
    transform: scale(0.3);
    opacity: 0;
  }

  50% {
    transform: scale(1.15);
    opacity: 1;
  }

  70% {
    transform: scale(0.9);
  }

  100% {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes tm-count-slide {
  0% {
    transform: translateY(100%);
    opacity: 0;
  }

  60% {
    opacity: 1;
  }

  75% {
    transform: translateY(-8%);
  }

  90% {
    transform: translateY(3%);
  }

  100% {
    transform: translateY(0);
    opacity: 1;
  }
}

@keyframes tm-confetti {
  0% {
    transform: translateY(-20px) rotate(0deg);
    opacity: 0;
  }

  10% {
    opacity: 1;
  }

  100% {
    transform: translateY(100px) rotate(720deg);
    opacity: 0;
  }
}


/* --- src/animations/professional.css --- */
@layer utilities {
  /* Reveal - smooth mask reveal from bottom */
  .tm-reveal {
    animation-name: tm-reveal;
    animation-duration: var(--tm-duration, calc(800ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.65, 0, 0.35, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  /* Unfold - elegant unfold from top */
  .tm-unfold {
    animation-name: tm-unfold;
    animation-duration: var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.33, 1, 0.68, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
    transform-origin: top center;
  }

  /* Glide - smooth horizontal entrance */
  .tm-glide {
    animation-name: tm-glide;
    animation-duration: var(--tm-duration, calc(900ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  .tm-glide-right {
    animation-name: tm-glide-right;
    animation-duration: var(--tm-duration, calc(900ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  /* Scale Fade - subtle scale with fade for cards */
  .tm-scale-fade {
    animation-name: tm-scale-fade;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.25, 0.46, 0.45, 0.94)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

  /* Rise - elegant rise with subtle rotation */
  .tm-rise {
    animation-name: tm-rise;
    animation-duration: var(--tm-duration, calc(1000ms * var(--tm-duration-scale, 1)));
    animation-delay: var(--tm-delay, 0ms);
    animation-timing-function: var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.16, 1, 0.3, 1)));
    animation-iteration-count: var(--tm-iteration-count, 1);
    animation-fill-mode: both;
  }

}

@keyframes tm-reveal {
  0% {
    clip-path: inset(100% 0 0 0);
    translate: 0 20px;
  }

  100% {
    clip-path: inset(0 0 0 0);
    translate: 0 0;
  }
}

@keyframes tm-unfold {
  0% {
    transform: scaleY(0) translateY(-10px);
    opacity: 0;
  }

  60% {
    opacity: 1;
  }

  100% {
    transform: scaleY(1) translateY(0);
    opacity: 1;
  }
}

@keyframes tm-glide {
  0% {
    translate: -60px 0;
    opacity: 0;
  }

  100% {
    translate: 0 0;
    opacity: 1;
  }
}

@keyframes tm-glide-right {
  0% {
    translate: 60px 0;
    opacity: 0;
  }

  100% {
    translate: 0 0;
    opacity: 1;
  }
}

@keyframes tm-scale-fade {
  0% {
    scale: calc(1 - 0.08 * var(--tm-emphasis, 1));
    opacity: 0;
  }

  100% {
    scale: 1;
    opacity: 1;
  }
}

@keyframes tm-rise {
  0% {
    translate: 0 40px;
    rotate: 1deg;
    opacity: 0;
  }

  100% {
    translate: 0 0;
    rotate: 0deg;
    opacity: 1;
  }
}


/* --- src/animations/liquid.css --- */
@layer utilities {
  /* Liquid Button - fill from bottom on hover */
  .tm-liquid-btn {
    --tm-liquid-color: currentColor;
    --tm-liquid-bg: transparent;
    --tm-liquid-duration: 0.4s;
    position: relative;
    overflow: hidden;
    background-color: var(--tm-liquid-bg);
    transition: 
      color var(--tm-liquid-duration) ease,
      transform 0.15s ease;
    isolation: isolate;
  }

  .tm-liquid-btn::before {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--tm-liquid-color);
    transform: scaleY(0);
    transform-origin: bottom center;
    transition: transform var(--tm-liquid-duration) cubic-bezier(0.4, 0, 0.2, 1);
    z-index: -1;
  }

  .tm-liquid-btn:hover::before,
  .tm-liquid-btn:focus-visible::before {
    transform: scaleY(1);
  }

  .tm-liquid-btn:active {
    transform: scale(0.97);
  }

  /* Liquid from left */
  .tm-liquid-btn-left::before {
    transform: scaleX(0);
    transform-origin: left center;
  }

  .tm-liquid-btn-left:hover::before,
  .tm-liquid-btn-left:focus-visible::before {
    transform: scaleX(1);
  }

  /* Liquid from right */
  .tm-liquid-btn-right::before {
    transform: scaleX(0);
    transform-origin: right center;
  }

  .tm-liquid-btn-right:hover::before,
  .tm-liquid-btn-right:focus-visible::before {
    transform: scaleX(1);
  }

  /* Liquid from top */
  .tm-liquid-btn-top::before {
    transform: scaleY(0);
    transform-origin: top center;
  }

  .tm-liquid-btn-top:hover::before,
  .tm-liquid-btn-top:focus-visible::before {
    transform: scaleY(1);
  }

  /* Liquid from center (radial) */
  .tm-liquid-btn-center::before {
    transform: scale(0);
    transform-origin: center center;
    border-radius: 50%;
  }

  .tm-liquid-btn-center:hover::before,
  .tm-liquid-btn-center:focus-visible::before {
    transform: scale(1.5);
    border-radius: 0;
  }

  /* Liquid wave effect - more organic */
  .tm-liquid-wave {
    --tm-liquid-color: currentColor;
    --tm-liquid-bg: transparent;
    --tm-liquid-duration: 0.5s;
    position: relative;
    overflow: hidden;
    background-color: var(--tm-liquid-bg);
    transition: 
      color var(--tm-liquid-duration) ease,
      transform 0.15s ease;
    isolation: isolate;
  }

  .tm-liquid-wave::before {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 0;
    background: var(--tm-liquid-color);
    transition: height var(--tm-liquid-duration) cubic-bezier(0.22, 1, 0.36, 1);
    z-index: -1;
  }

  .tm-liquid-wave:hover::before,
  .tm-liquid-wave:focus-visible::before {
    height: 100%;
  }

  .tm-liquid-wave:active {
    transform: scale(0.97);
  }

  /* Liquid underline - starts as line, fills up */
  .tm-liquid-underline {
    --tm-liquid-color: currentColor;
    --tm-liquid-bg: transparent;
    --tm-liquid-duration: 0.35s;
    --tm-liquid-line-height: 2px;
    position: relative;
    overflow: hidden;
    background-color: var(--tm-liquid-bg);
    transition: 
      color var(--tm-liquid-duration) ease calc(var(--tm-liquid-duration) * 0.5),
      transform 0.15s ease;
    isolation: isolate;
  }

  .tm-liquid-underline::before {
    content: '';
    position: absolute;
    bottom: 0;
    left: 50%;
    width: 0;
    height: var(--tm-liquid-line-height);
    background: var(--tm-liquid-color);
    transition: 
      width var(--tm-liquid-duration) cubic-bezier(0.4, 0, 0.2, 1),
      left var(--tm-liquid-duration) cubic-bezier(0.4, 0, 0.2, 1),
      height var(--tm-liquid-duration) cubic-bezier(0.4, 0, 0.2, 1) var(--tm-liquid-duration);
    z-index: -1;
  }

  .tm-liquid-underline:hover::before,
  .tm-liquid-underline:focus-visible::before {
    width: 100%;
    left: 0;
    height: 100%;
  }

  .tm-liquid-underline:active {
    transform: scale(0.97);
  }

  /* Color variants using CSS variables */
  .tm-liquid-blue {
    --tm-liquid-color: rgb(59, 130, 246);
  }

  .tm-liquid-purple {
    --tm-liquid-color: rgb(147, 51, 234);
  }

  .tm-liquid-emerald {
    --tm-liquid-color: rgb(16, 185, 129);
  }

  .tm-liquid-rose {
    --tm-liquid-color: rgb(244, 63, 94);
  }

  .tm-liquid-amber {
    --tm-liquid-color: rgb(245, 158, 11);
  }

  .tm-liquid-cyan {
    --tm-liquid-color: rgb(6, 182, 212);
  }

  /* Speed variants */
  .tm-liquid-fast {
    --tm-liquid-duration: 0.25s;
  }

  .tm-liquid-slow {
    --tm-liquid-duration: 0.6s;
  }
}


/* --- src/animations/text-flip.css --- */
@layer utilities {
  /* Text Flip Container */
  .tm-text-flip {
    display: inline-block;
    position: relative;
    overflow: hidden;
    vertical-align: bottom;
  }

  .tm-text-flip-word {
    display: inline-block;
    animation-name: tm-text-flip-in;
    animation-duration: var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1)));
    animation-timing-function: var(--tm-easing, cubic-bezier(0.16, 1, 0.3, 1));
    animation-fill-mode: both;
    will-change: transform, opacity, filter;
  }

  .tm-text-flip-word.tm-flip-out {
    position: absolute;
    top: 0;
    left: 0;
    animation-name: tm-text-flip-out;
  }

  /* Flip from bottom (default) */
  @keyframes tm-text-flip-in {
    0% {
      transform: translateY(100%) rotateX(-45deg);
      opacity: 0;
      filter: blur(8px);
    }
    60% {
      filter: blur(2px);
    }
    100% {
      transform: translateY(0) rotateX(0);
      opacity: 1;
      filter: blur(0);
    }
  }

  @keyframes tm-text-flip-out {
    0% {
      transform: translateY(0) rotateX(0);
      opacity: 1;
      filter: blur(0);
    }
    40% {
      filter: blur(2px);
    }
    100% {
      transform: translateY(-100%) rotateX(45deg);
      opacity: 0;
      filter: blur(8px);
    }
  }

  /* Text Rotate - simpler horizontal blur transition */
  .tm-text-rotate {
    display: inline-block;
    position: relative;
    overflow: hidden;
    vertical-align: bottom;
  }

  .tm-text-rotate-word {
    display: inline-block;
    animation-name: tm-text-rotate-in;
    animation-duration: var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1)));
    animation-timing-function: var(--tm-easing, cubic-bezier(0.22, 1, 0.36, 1));
    animation-fill-mode: both;
    will-change: transform, opacity, filter;
  }

  .tm-text-rotate-word.tm-rotate-out {
    position: absolute;
    top: 0;
    left: 0;
    animation-name: tm-text-rotate-out;
  }

  @keyframes tm-text-rotate-in {
    0% {
      transform: translateY(50%);
      opacity: 0;
      filter: blur(10px);
    }
    100% {
      transform: translateY(0);
      opacity: 1;
      filter: blur(0);
    }
  }

  @keyframes tm-text-rotate-out {
    0% {
      transform: translateY(0);
      opacity: 1;
      filter: blur(0);
    }
    100% {
      transform: translateY(-50%);
      opacity: 0;
      filter: blur(10px);
    }
  }

  /* Text Morph - horizontal blur swap */
  .tm-text-morph {
    display: inline-block;
    position: relative;
  }

  .tm-text-morph-word {
    display: inline-block;
    animation-name: tm-text-morph-in;
    animation-duration: var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1)));
    animation-timing-function: var(--tm-easing, ease-out);
    animation-fill-mode: both;
    will-change: opacity, filter;
  }

  .tm-text-morph-word.tm-morph-out {
    position: absolute;
    top: 0;
    left: 0;
    animation-name: tm-text-morph-out;
  }

  @keyframes tm-text-morph-in {
    0% {
      opacity: 0;
      filter: blur(12px);
    }
    100% {
      opacity: 1;
      filter: blur(0);
    }
  }

  @keyframes tm-text-morph-out {
    0% {
      opacity: 1;
      filter: blur(0);
    }
    100% {
      opacity: 0;
      filter: blur(12px);
    }
  }

  /* Character-by-character flip */
  .tm-text-flip-chars {
    display: inline-flex;
  }

  .tm-text-flip-chars > span {
    display: inline-block;
    animation-name: tm-char-flip-in;
    animation-duration: var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1)));
    animation-delay: calc(var(--tm-char-index, 0) * 40ms);
    animation-timing-function: var(--tm-easing, cubic-bezier(0.16, 1, 0.3, 1));
    animation-fill-mode: both;
    will-change: transform, opacity, filter;
  }

  @keyframes tm-char-flip-in {
    0% {
      transform: translateY(100%);
      opacity: 0;
      filter: blur(4px);
    }
    100% {
      transform: translateY(0);
      opacity: 1;
      filter: blur(0);
    }
  }
}


/* --- src/animations/variants.css --- */
/* TailMotion Variants - Enables Tailwind CSS variants */

@layer utilities {
  /* ========================================
     HOVER VARIANTS
     ======================================== */
  .hover\:tm-bounce:hover { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-pulse:hover { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-spin:hover { animation: tm-spin var(--tm-duration, calc(1000ms * var(--tm-duration-scale, 1))) var(--tm-easing, linear) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-float:hover { animation: tm-float var(--tm-duration, calc(3000ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-drift:hover { animation: tm-drift var(--tm-duration, calc(4000ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-shake:hover { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-wiggle:hover { animation: tm-wiggle var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-glow:hover { animation: tm-glow var(--tm-duration, calc(1500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-morph:hover { animation: tm-morph var(--tm-duration, calc(4000ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-sway:hover { animation: tm-sway var(--tm-duration, calc(2500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-ripple:hover { animation: tm-ripple var(--tm-duration, calc(1500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-elastic:hover { animation: tm-elastic var(--tm-duration, calc(800ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.68, -0.55, 0.265, 1.55))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-fade-in:hover { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-slide-up:hover { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-slide-down:hover { animation: tm-slide-block-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-slide-left:hover { animation: tm-slide-inline-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-slide-right:hover { animation: tm-slide-inline-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-pop:hover { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-drop:hover { animation: tm-drop-in var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-blur-in:hover { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-zoom-in:hover { animation: tm-zoom-in var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-zoom-out:hover { animation: tm-zoom-out var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-flip-x:hover { animation: tm-flip-x var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-flip-y:hover { animation: tm-flip-y var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-rotate-in:hover { animation: tm-rotate-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-reveal:hover { animation: tm-reveal var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-unfold:hover { animation: tm-unfold var(--tm-duration, calc(800ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-glide:hover { animation: tm-glide var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-glide-right:hover { animation: tm-glide-right var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-scale-fade:hover { animation: tm-scale-fade var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-rise:hover { animation: tm-rise var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-sparkle:hover { animation: tm-sparkle var(--tm-duration, calc(1400ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-burst:hover { animation: tm-burst var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }

  /* ========================================
     FOCUS VARIANTS
     ======================================== */
  .focus\:tm-bounce:focus { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus\:tm-pulse:focus { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus\:tm-shake:focus { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus\:tm-glow:focus { animation: tm-glow var(--tm-duration, calc(1500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus\:tm-pop:focus { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus\:tm-blur-in:focus { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus\:tm-fade-in:focus { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus\:tm-slide-up:focus { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }

  /* ========================================
     ACTIVE VARIANTS
     ======================================== */
  .active\:tm-bounce:active { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-shake:active { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-pop:active { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-elastic:active { animation: tm-elastic var(--tm-duration, calc(800ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.68, -0.55, 0.265, 1.55))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-fade-in:active { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-scale-in:active { animation: tm-scale-in var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-blur-in:active { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-slide-block-start:active { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-slide-block-end:active { animation: tm-slide-block-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-slide-inline-start:active { animation: tm-slide-inline-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-slide-inline-end:active { animation: tm-slide-inline-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-wiggle:active { animation: tm-wiggle var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-sparkle:active { animation: tm-sparkle var(--tm-duration, calc(1400ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .active\:tm-burst:active { animation: tm-burst var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }

  /* ========================================
     GROUP-HOVER VARIANTS
     ======================================== */
  .group:hover .group-hover\:tm-bounce { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-pulse { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-spin { animation: tm-spin var(--tm-duration, calc(1000ms * var(--tm-duration-scale, 1))) var(--tm-easing, linear) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-shake { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-wiggle { animation: tm-wiggle var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-glow { animation: tm-glow var(--tm-duration, calc(1500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-fade-in { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-slide-up { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-pop { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-blur-in { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-reveal { animation: tm-reveal var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-zoom-in { animation: tm-zoom-in var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }

  /* ========================================
     FOCUS-WITHIN VARIANTS
     ======================================== */
  .focus-within\:tm-glow:focus-within { animation: tm-glow var(--tm-duration, calc(1500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-within\:tm-pulse:focus-within { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }

  /* ========================================
     MOTION-SAFE VARIANTS
     ======================================== */
  @media (prefers-reduced-motion: no-preference) {
    .motion-safe\:tm-bounce { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-pulse { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-shake { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-fade-in { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-slide-up { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-blur-in { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  }

  /* ========================================
     FOCUS-VISIBLE VARIANTS
     Keyboard focus only. Always pair these with a visible focus ring: motion
     is supplementary feedback, never the sole indicator of a state.
     ======================================== */
  .focus-visible\:tm-glow:focus-visible { animation: tm-glow var(--tm-duration, calc(1600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, infinite) both; }
  .focus-visible\:tm-pulse:focus-visible { animation: tm-pulse var(--tm-duration, calc(1400ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, infinite) both; }
  .focus-visible\:tm-ripple:focus-visible { animation: tm-ripple var(--tm-duration, calc(1800ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-out) var(--tm-delay, 0ms) var(--tm-iteration-count, infinite) both; }
  .focus-visible\:tm-pop:focus-visible { animation: tm-pop var(--tm-duration, calc(380ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.18, 0.89, 0.32, 1.28))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-visible\:tm-shake:focus-visible { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-visible\:tm-scale-in:focus-visible { animation: tm-scale-in var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }

  /* ========================================
     LOGICAL ENTRANCE + EXIT VARIANTS
     ======================================== */
  .hover\:tm-scale-in:hover { animation: tm-scale-in var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-slide-block-start:hover { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-slide-block-end:hover { animation: tm-slide-block-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-slide-inline-start:hover { animation: tm-slide-inline-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-slide-inline-end:hover { animation: tm-slide-inline-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-fade-out:hover { animation: tm-fade-out var(--tm-duration, calc(200ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-scale-out:hover { animation: tm-scale-out var(--tm-duration, calc(180ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-slide-block-out:hover { animation: tm-slide-block-out var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-slide-inline-out:hover { animation: tm-slide-inline-out var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .hover\:tm-blur-out:hover { animation: tm-blur-out var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }

  .focus-visible\:tm-scale-in:focus-visible { animation: tm-scale-in var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-visible\:tm-slide-block-start:focus-visible { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-visible\:tm-slide-block-end:focus-visible { animation: tm-slide-block-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-visible\:tm-slide-inline-start:focus-visible { animation: tm-slide-inline-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-visible\:tm-slide-inline-end:focus-visible { animation: tm-slide-inline-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-visible\:tm-fade-out:focus-visible { animation: tm-fade-out var(--tm-duration, calc(200ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-visible\:tm-scale-out:focus-visible { animation: tm-scale-out var(--tm-duration, calc(180ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-visible\:tm-slide-block-out:focus-visible { animation: tm-slide-block-out var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-visible\:tm-slide-inline-out:focus-visible { animation: tm-slide-inline-out var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-visible\:tm-blur-out:focus-visible { animation: tm-blur-out var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }

  .group:hover .group-hover\:tm-scale-in { animation: tm-scale-in var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-slide-block-start { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-slide-block-end { animation: tm-slide-block-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-slide-inline-start { animation: tm-slide-inline-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-slide-inline-end { animation: tm-slide-inline-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-fade-out { animation: tm-fade-out var(--tm-duration, calc(200ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-scale-out { animation: tm-scale-out var(--tm-duration, calc(180ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-slide-block-out { animation: tm-slide-block-out var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-slide-inline-out { animation: tm-slide-inline-out var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .group:hover .group-hover\:tm-blur-out { animation: tm-blur-out var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }

  .focus-within\:tm-scale-in:focus-within { animation: tm-scale-in var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-within\:tm-slide-block-start:focus-within { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-within\:tm-slide-block-end:focus-within { animation: tm-slide-block-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-within\:tm-slide-inline-start:focus-within { animation: tm-slide-inline-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-within\:tm-slide-inline-end:focus-within { animation: tm-slide-inline-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-within\:tm-fade-out:focus-within { animation: tm-fade-out var(--tm-duration, calc(200ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-within\:tm-scale-out:focus-within { animation: tm-scale-out var(--tm-duration, calc(180ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-within\:tm-slide-block-out:focus-within { animation: tm-slide-block-out var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-within\:tm-slide-inline-out:focus-within { animation: tm-slide-inline-out var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .focus-within\:tm-blur-out:focus-within { animation: tm-blur-out var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }

  @media (prefers-reduced-motion: no-preference) {
    .motion-safe\:tm-scale-in { animation: tm-scale-in var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-slide-block-start { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-slide-block-end { animation: tm-slide-block-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-slide-inline-start { animation: tm-slide-inline-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-slide-inline-end { animation: tm-slide-inline-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-fade-out { animation: tm-fade-out var(--tm-duration, calc(200ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-scale-out { animation: tm-scale-out var(--tm-duration, calc(180ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-slide-block-out { animation: tm-slide-block-out var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-slide-inline-out { animation: tm-slide-inline-out var(--tm-duration, calc(210ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
    .motion-safe\:tm-blur-out { animation: tm-blur-out var(--tm-duration, calc(220ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-exit, ease-out)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  }
}

/* ========================================
   RESPONSIVE VARIANTS - SM (640px+)
   ======================================== */
@media (min-width: 640px) {
  .sm\:tm-bounce { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-pulse { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-spin { animation: tm-spin var(--tm-duration, calc(1000ms * var(--tm-duration-scale, 1))) var(--tm-easing, linear) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-float { animation: tm-float var(--tm-duration, calc(3000ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-shake { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-wiggle { animation: tm-wiggle var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-glow { animation: tm-glow var(--tm-duration, calc(1500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-fade-in { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-slide-up { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-slide-down { animation: tm-slide-block-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-slide-left { animation: tm-slide-inline-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-slide-right { animation: tm-slide-inline-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-pop { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-blur-in { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-zoom-in { animation: tm-zoom-in var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-reveal { animation: tm-reveal var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-glide { animation: tm-glide var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:tm-rise { animation: tm-rise var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  
  /* SM Hover */
  .sm\:hover\:tm-bounce:hover { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:hover\:tm-pulse:hover { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:hover\:tm-shake:hover { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:hover\:tm-wiggle:hover { animation: tm-wiggle var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:hover\:tm-fade-in:hover { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:hover\:tm-slide-up:hover { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:hover\:tm-pop:hover { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:hover\:tm-blur-in:hover { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .sm\:hover\:tm-zoom-in:hover { animation: tm-zoom-in var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
}

/* ========================================
   RESPONSIVE VARIANTS - MD (768px+)
   ======================================== */
@media (min-width: 768px) {
  .md\:tm-bounce { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-pulse { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-spin { animation: tm-spin var(--tm-duration, calc(1000ms * var(--tm-duration-scale, 1))) var(--tm-easing, linear) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-float { animation: tm-float var(--tm-duration, calc(3000ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-shake { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-wiggle { animation: tm-wiggle var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-glow { animation: tm-glow var(--tm-duration, calc(1500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-fade-in { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-slide-up { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-slide-down { animation: tm-slide-block-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-slide-left { animation: tm-slide-inline-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-slide-right { animation: tm-slide-inline-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-pop { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-blur-in { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-zoom-in { animation: tm-zoom-in var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-reveal { animation: tm-reveal var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-glide { animation: tm-glide var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:tm-rise { animation: tm-rise var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  
  /* MD Hover */
  .md\:hover\:tm-bounce:hover { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:hover\:tm-pulse:hover { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:hover\:tm-shake:hover { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:hover\:tm-wiggle:hover { animation: tm-wiggle var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:hover\:tm-fade-in:hover { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:hover\:tm-slide-up:hover { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:hover\:tm-pop:hover { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:hover\:tm-blur-in:hover { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .md\:hover\:tm-zoom-in:hover { animation: tm-zoom-in var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
}

/* ========================================
   RESPONSIVE VARIANTS - LG (1024px+)
   ======================================== */
@media (min-width: 1024px) {
  .lg\:tm-bounce { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-pulse { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-spin { animation: tm-spin var(--tm-duration, calc(1000ms * var(--tm-duration-scale, 1))) var(--tm-easing, linear) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-float { animation: tm-float var(--tm-duration, calc(3000ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-shake { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-wiggle { animation: tm-wiggle var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-glow { animation: tm-glow var(--tm-duration, calc(1500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-fade-in { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-slide-up { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-slide-down { animation: tm-slide-block-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-slide-left { animation: tm-slide-inline-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-slide-right { animation: tm-slide-inline-end var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-pop { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-blur-in { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-zoom-in { animation: tm-zoom-in var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-reveal { animation: tm-reveal var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-glide { animation: tm-glide var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:tm-rise { animation: tm-rise var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  
  /* LG Hover */
  .lg\:hover\:tm-bounce:hover { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:hover\:tm-pulse:hover { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:hover\:tm-shake:hover { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:hover\:tm-wiggle:hover { animation: tm-wiggle var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:hover\:tm-fade-in:hover { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:hover\:tm-slide-up:hover { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:hover\:tm-pop:hover { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:hover\:tm-blur-in:hover { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .lg\:hover\:tm-zoom-in:hover { animation: tm-zoom-in var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
}

/* ========================================
   RESPONSIVE VARIANTS - XL (1280px+)
   ======================================== */
@media (min-width: 1280px) {
  .xl\:tm-bounce { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-pulse { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-spin { animation: tm-spin var(--tm-duration, calc(1000ms * var(--tm-duration-scale, 1))) var(--tm-easing, linear) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-float { animation: tm-float var(--tm-duration, calc(3000ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-shake { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-wiggle { animation: tm-wiggle var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-glow { animation: tm-glow var(--tm-duration, calc(1500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-fade-in { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-slide-up { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-pop { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-blur-in { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-zoom-in { animation: tm-zoom-in var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-reveal { animation: tm-reveal var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-glide { animation: tm-glide var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:tm-rise { animation: tm-rise var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  
  /* XL Hover */
  .xl\:hover\:tm-bounce:hover { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:hover\:tm-pulse:hover { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:hover\:tm-shake:hover { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:hover\:tm-pop:hover { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:hover\:tm-blur-in:hover { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .xl\:hover\:tm-zoom-in:hover { animation: tm-zoom-in var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
}

/* ========================================
   RESPONSIVE VARIANTS - 2XL (1536px+)
   ======================================== */
@media (min-width: 1536px) {
  .\32xl\:tm-bounce { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:tm-pulse { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:tm-spin { animation: tm-spin var(--tm-duration, calc(1000ms * var(--tm-duration-scale, 1))) var(--tm-easing, linear) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:tm-float { animation: tm-float var(--tm-duration, calc(3000ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:tm-shake { animation: tm-shake var(--tm-duration, calc(500ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:tm-fade-in { animation: tm-fade-in var(--tm-duration, calc(250ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:tm-slide-up { animation: tm-slide-block-start var(--tm-duration, calc(260ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:tm-pop { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:tm-blur-in { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:tm-zoom-in { animation: tm-zoom-in var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.4, 0, 0.2, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:tm-reveal { animation: tm-reveal var(--tm-duration, calc(700ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  
  /* 2XL Hover */
  .\32xl\:hover\:tm-bounce:hover { animation: tm-bounce var(--tm-duration, calc(600ms * var(--tm-duration-scale, 1))) var(--tm-easing, cubic-bezier(0.34, 1.56, 0.64, 1)) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:hover\:tm-pulse:hover { animation: tm-pulse var(--tm-duration, calc(1200ms * var(--tm-duration-scale, 1))) var(--tm-easing, ease-in-out) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:hover\:tm-pop:hover { animation: tm-pop var(--tm-duration, calc(400ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-emphasis, cubic-bezier(0.34, 1.56, 0.64, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
  .\32xl\:hover\:tm-blur-in:hover { animation: tm-blur-in var(--tm-duration, calc(280ms * var(--tm-duration-scale, 1))) var(--tm-easing, var(--tm-ease-entrance, cubic-bezier(0.23, 1, 0.32, 1))) var(--tm-delay, 0ms) var(--tm-iteration-count, 1) both; }
}
