:root {
    --transition-duration: var(--td-rapid);
    --iteration-count: 1;

    --td-rapid: 0.1s;
    --td-fast: 0.325s;
    --td-medium: 0.55s;
    --td-slow: 0.775s;
}

*,
*::before,
*::after {
    transition: inherit;
}

/* raise */
*[raise] {
    --transition-duration: var(--td-medium);
    --raise-hover: 0.5rem;
    --raise-active: 1rem;

    will-change: transform;
    animation: blink var(--blink-duration) step-end var(--blink-iteration-count)
}

*[raise~="hover"]:hover { transform: translateY(calc(-1 * var(--raise-hover))) }
*[raise~="active"]:active { transform: translateY(calc(-1 * var(--raise-active))) }
*[raise~="focus"]:focus { transform: translateY(calc(-1 * var(--raise-active))) }

/* scale */
*[scale] {
    --transition-duration: var(--td-medium);
    --scale-duration: var(--transition-duration);
    --scale-hover: 1.05;
    --scale-active: 0.95;

    will-change: transform;
    transition-duration: var(--scale-duration);
}

*[scale~="hover"]:hover { transform: scale(var(--scale-hover)) }
*[scale~="active"]:active { transform: scale(var(--scale-active)) }
*[scale~="focus"]:focus { transform: scale(var(--scale-active)) }

/* rotate */
*[rotate] {
    --transition-duration: var(--td-medium);
    --rotate-duration: var(--transition-duration);
    --rotate-hover: 3deg;
    --rotate-active: -3deg;

    will-change: transform;
    transition-duration: var(--rotate-duration);
}

*[rotate~="hover"]:hover { transform: rotate(var(--rotate-hover)) }
*[rotate~="active"]:active { transform: rotate(var(--rotate-active)) }
*[rotate~="focus"]:focus { transform: rotate(var(--rotate-active)) }

/* blur */
*[blur] {
    --transition-duration: var(--td-slow);
    --blur-duration: var(--transition-duration);
    --blur-amount: 5px;

    will-change: blur;
    filter: blur(var(--blur-amount))
}

*[blur]:hover, *[blur]:active, *[blur]:focus {
    filter: blur(0)
}

/* shadow */
*[shadow] {
    --transition-duration: var(--td-medium);
    --shadow-duration: var(--transition-duration);

    --shadow-hover-offset: 5px;
    --shadow-hover-offsetX: var(--shadow-hover-offset);
    --shadow-hover-offsetY: var(--shadow-hover-offset);
    --shadow-hover-blur: 10px;
    --shadow-hover-color: rgba(0, 0, 0, 0.2);

    --shadow-active-offset: 2px;
    --shadow-active-offsetX: var(--shadow-hover-offset);
    --shadow-active-offsetY: var(--shadow-hover-offset);
    --shadow-active-blur: 8px;
    --shadow-active-color: rgba(0, 0, 0, 0.3);

    will-change: box-shadow;
    transition-duration: var(--shadow-duration);
}

*[shadow~="hover"]:hover { box-shadow: var(--shadow-hover-offsetX) var(--shadow-hover-offsetY) var(--shadow-hover-blur) var(--shadow-hover-color) }
*[shadow~="active"]:active { box-shadow: var(--shadow-active-offsetX) var(--shadow-active-offsetY) var(--shadow-active-blur) var(--shadow-active-color) }
*[shadow~="focus"]:focus { box-shadow: var(--shadow-active-offsetX) var(--shadow-active-offsetY) var(--shadow-active-blur) var(--shadow-active-color) }

/* _opacity */
@keyframes _opacity {
    0% { opacity: 1 }
    50% { opacity: 0 }
    100% { opacity: 1 }
}

*[opacity] {
    --transition-duration: var(--td-slow);
    --opacity-duration: var(--transition-duration);
    --opacity-iteration-count: var(--iteration-count);

    will-change: opacity;
    animation: _opacity var(--opacity-duration) linear var(--opacity-iteration-count)
}

*[opacity~="infinite"] { --opacity-iteration-count: infinite }

*[opacity~="hover"], *[opacity~="active"], *[opacity~="focus"] {
    animation: none
}

*[opacity~="hover"]:hover, *[opacity~="active"]:active, *[opacity~="focus"]:focus {
    animation: _opacity var(--opacity-duration) linear var(--opacity-iteration-count)
}

/* blink */
@keyframes blink {
    50% { opacity: 0 }
}

*[blink] {
    --transition-duration: 1s;
    --blink-duration: var(--transition-duration);
    --blink-iteration-count: var(--iteration-count);

    will-change: opacity;
    animation: blink var(--blink-duration) step-end var(--blink-iteration-count)
}

*[blink~="infinite"] { --blink-iteration-count: infinite }

*[blink~="hover"], *[blink~="active"], *[blink~="focus"] {
    animation: none
}

*[blink~="hover"]:hover, *[blink~="active"]:active, *[blink~="focus"]:focus {
    animation: blink var(--blink-duration) step-end var(--blink-iteration-count)
}

/* typing-text */
@keyframes typing-text { 
    from { width: 0 }
    to { width: 100% }
}

*[typing-text] {
    --transition-duration: 3s;
    --typing-duration: var(--transition-duration);
    --typing-steps: 24;
    --typing-chars: 10;
    --typing-color: #000;
    --typing-width: 2px;

    will-change: width;
    position: relative !important;
    display: inline-block;
    overflow: hidden;
    white-space: nowrap;
    width: 0;
    min-width: calc(var(--typing-chars) * 1ch);
    max-width: max-content;
    animation: typing-text var(--typing-duration) steps(var(--typing-steps), end) forwards;
}

*[typing-text]::after {
    will-change: opacity;
    content: "";
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    display: inline-block;
    width: var(--typing-width);
    background: var(--typing-color);

    animation: blink 1s step-end infinite;
}

*[typing-text~="hover"], *[typing-text~="active"], *[typing-text~="focus"] {
    animation-play-state: paused
}

*[typing-text~="hover"]:hover, *[typing-text~="active"]:active, *[typing-text~="focus"]:focus {
    animation-play-state: running;
}

/* pulse */
@keyframes pulse {
    0%, 100% { transform: scale(1) }
    50% { transform: scale(var(--pulse-scale)) }
}

*[pulse] {
    --transition-duration: var(--td-medium);
    --pulse-duration: var(--transition-duration);
    --pulse-scale: 1.03;
    --pulse-iteration-count: var(--iteration-count);

    will-change: transform;
    animation: pulse var(--pulse-duration) ease-in-out var(--pulse-iteration-count)
}

*[pulse~="infinite"] { --pulse-iteration-count: infinite }

*[pulse~="hover"], *[pulse~="active"], *[pulse~="focus"] {
    animation: none
}

*[pulse~="hover"]:hover, *[pulse~="active"]:active, *[pulse~="focus"]:focus {
    animation: pulse var(--pulse-duration) ease-in-out var(--pulse-iteration-count)
}

/* wobble */
@keyframes wobble {
    0%,
    100% { transform: rotate(0deg) }
    25% { transform: rotate(var(--wobble-angle)) }
    75% { transform: rotate(calc(-1 * var(--wobble-angle))) }
}

*[wobble] {
    --transition-duration: var(--td-fast);
    --wobble-duration: var(--transition-duration);
    --wobble-angle: 10deg;
    --wobble-iteration-count: var(--iteration-count);

    will-change: transform;
    animation: wobble var(--wobble-duration) ease-in-out var(--wobble-iteration-count)
}

*[wobble~="infinite"] { --wobble-iteration-count: infinite }

/* поведение: когда указано hover/active/focus — проигрывается только при событии */
*[wobble~="hover"],
*[wobble~="active"],
*[wobble~="focus"] {
    animation: none
}

*[wobble~="hover"]:hover, *[wobble~="active"]:active, *[wobble~="focus"]:focus {
    animation: wobble var(--wobble-duration) ease-in-out var(--wobble-iteration-count)
}

/* sheen */
@keyframes sheen {
    0% { left: -150% }
    100% { left: 150% }
}

*[sheen] {
    --transition-duration: var(--td-medium);
    --sheen-duration: var(--transition-duration);
    --sheen-color: rgba(255, 255, 255, 0.1);
    --sheen-width: max(30px, 30%);
    --sheen-angle: -45deg;
    --sheen-iteration-count: var(--iteration-count);

    position: relative;
    overflow: hidden;
}

*[sheen]::before {
    will-change: left;
    content: "";
    position: absolute;
    top: 0;
    left: -150%;
    width: var(--sheen-width);
    height: 100%;
    background: linear-gradient(to right, #fff0 0%, var(--sheen-color) 50%, #fff0 100%);
    transform: skewX(var(--sheen-angle));
    pointer-events: none;
    z-index: 10;
    animation: sheen var(--sheen-duration) linear var(--sheen-iteration-count)
}

*[sheen~="infinite"] { --sheen-iteration-count: infinite }

*[sheen~="hover"]::before, *[sheen~="active"]::before, *[sheen~="focus"]::before {
    animation: none
}

*[sheen~="hover"]:hover::before, *[sheen~="active"]:active::before, *[sheen~="focus"]:focus::before {
    animation: sheen var(--sheen-duration) linear var(--sheen-iteration-count)
}

/* vibrate */
@keyframes vibrate {
    0%   { transform: translate(0, 0) rotate(0); }
    10%  { transform: translate(var(--vibrate-x), var(--vibrate-y)) rotate(var(--vibrate-rotate)); }
    30%  { transform: translate(calc(var(--vibrate-x) * -1), var(--vibrate-y)) rotate(calc(var(--vibrate-rotate) * -1)); }
    50%  { transform: translate(var(--vibrate-x), calc(var(--vibrate-y) * -1)) rotate(var(--vibrate-rotate)); }
    70%  { transform: translate(calc(var(--vibrate-x) * -1), calc(var(--vibrate-y) * -1)) rotate(calc(var(--vibrate-rotate) * -1)); }
    90%  { transform: translate(var(--vibrate-x), var(--vibrate-y)) rotate(var(--vibrate-rotate)); }
    100% { transform: translate(0, 0) rotate(0); }
}

*[vibrate] {
    --transition-duration: var(--td-fast);
    --vibrate-duration: var(--transition-duration);
    --vibrate-iteration-count: infinite;
    --vibrate-x: 2px;
    --vibrate-y: 1px;
    --vibrate-rotate: 0.5deg;

    will-change: transform;
    animation: vibrate var(--vibrate-duration) linear var(--vibrate-iteration-count);
    animation-play-state: paused
}

*[vibrate~="hover"]:hover, *[vibrate~="active"]:active, *[vibrate~="focus"]:focus {
    animation-play-state: running
}

*[vibrate~="reverse"] { animation-play-state: running }

*[vibrate~="reverse"][vibrate~="hover"]:hover, *[vibrate~="reverse"][vibrate~="hover"]:active, *[vibrate~="reverse"][vibrate~="hover"]:focus {
    animation-play-state: paused
}

/* float */
@keyframes floatY {
    0%, 100% { transform: translateY(0) }
    25%      { transform: translateY(var(--float-range)) }
    75%      { transform: translateY(calc(-1 * var(--float-range))) }
}

@keyframes floatX {
    0%, 100% { transform: translateX(0) }
    25%      { transform: translateX(var(--float-range)) }
    75%      { transform: translateX(calc(-1 * var(--float-range))) }
}

*[float] {
    --transition-duration: var(--td-slow);
    --float-duration: var(--transition-duration);
    --float-iteration-count: var(--iteration-count);
    --float-range: 6px;

    will-change: transform;
    animation: floatY var(--float-duration) ease-in-out var(--float-iteration-count);
}

*[float~='horizontal'] {
    animation: floatX var(--float-duration) ease-in-out var(--float-iteration-count);
}

*[float~="infinite"] { --float-iteration-count: infinite; }

*[float~="hover"], *[float~="active"], *[float~="focus"] {
    animation: none;
}

*[float~="hover"]:hover,
*[float~="active"]:active,
*[float~="focus"]:focus {
    animation: floatY var(--float-duration) ease-in-out var(--float-iteration-count);
}

*[float~="hover"][float~="horizontal"]:hover,
*[float~="active"][float~="horizontal"]:active,
*[float~="focus"][float~="horizontal"]:focus {
    animation: floatX var(--float-duration) ease-in-out var(--float-iteration-count);
}

/* heartbeat */
@keyframes heartbeat {
    0%   { transform: scale(1) }
    30%  { transform: scale(var(--heartbeat-first-scale)) }
    60%  { transform: scale(var(--heartbeat-second-scale)) }
    100% { transform: scale(1) }
}

*[heartbeat] {
    --transition-duration: var(--td-slow);
    --heartbeat-duration: var(--transition-duration);
    --heartbeat-iteration-count: var(--iteration-count);
    --heartbeat-first-scale: 1.10;
    --heartbeat-second-scale: 0.95;

    will-change: transform;
    animation: heartbeat var(--heartbeat-duration) cubic-bezier(.4, .0, .2, 1) var(--heartbeat-iteration-count)
}

*[heartbeat~="infinite"] { --heartbeat-iteration-count: infinite }

*[heartbeat~="hover"], *[heartbeat~="active"], *[heartbeat~="focus"] {
    animation: none
}

*[heartbeat~="hover"]:hover, *[heartbeat~="active"]:active, *[heartbeat~="focus"]:focus {
    animation: heartbeat var(--heartbeat-duration) cubic-bezier(.4, .0, .2, 1) var(--heartbeat-iteration-count)
}

/* jello */
@keyframes jello {
    0%   { transform: scale3d(1,1,1); }
    30%  { transform: scale3d(1.25,0.85,1); }
    45%  { transform: scale3d(0.9,1.05,1); }
    60%  { transform: scale3d(1.05,0.95,1); }
    100% { transform: scale3d(1,1,1); }
}

*[jello] {
    --transition-duration: var(--td-medium);
    --jello-duration: var(--transition-duration);
    --jello-iteration-count: var(--iteration-count);

    will-change: transform;
    animation: jello var(--jello-duration) cubic-bezier(.2,.7,.2,1) var(--jello-iteration-count);
}

*[jello~="infinite"] { --jello-iteration-count: infinite }

*[jello~="hover"], *[jello~="active"], *[jello~="focus"] {
    animation: none
}

*[jello~="hover"]:hover, *[jello~="active"]:active, *[jello~="focus"]:focus {
    animation: jello var(--jello-duration) cubic-bezier(.2,.7,.2,1) var(--jello-iteration-count)
}


/* ripple */
@keyframes ripple {
    0%   { transform: translate(-50%,-50%) scale(0); opacity: 0.8; }
    60%  { transform: translate(-50%,-50%) scale(10); opacity: 0.28; }
    100% { transform: translate(-50%,-50%) scale(14); opacity: 0; }
}

*[ripple] {
    --transition-duration: var(--td-medium);
    --ripple-duration: var(--transition-duration);
    --ripple-color: rgba(255, 255, 255, 0.479);

    position: relative;
}

*[ripple]::before {
    will-change: transform;
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 8px;
    height: 8px;
    background-color: var(--ripple-color);
    border-radius: 50%;
    transform: translate(-50%,-50%) scale(0);
    opacity: 0;
    pointer-events: none
}

*[ripple~="active"]:active::before, *[ripple~="hover"]:hover::before, *[ripple~="focus"]:focus::before {
    animation: ripple var(--ripple-duration) ease-out
}

/* shimmer-text */
@keyframes shimmer {
    0%   { background-position: 200% 0 }
    100% { background-position: -200% 0 }
}

*[shimmer-text] {
    --transition-duration: 2s;
    --shimmer-duration: var(--transition-duration);
    --shimmer-color: var(--color, black);
    --shimmer-size: 100%;
    --shimmer-iteration-count: var(--iteration-count);

    will-change: background-position;
    background: linear-gradient(90deg, transparent calc(50% - var(--shimmer-size)), var(--shimmer-color) 50%, transparent calc(50% + var(--shimmer-size)));
    background-size: 200% 100%;
    background-clip: text;
    animation: shimmer var(--shimmer-duration) linear infinite;
}

*[shimmer-text]:not([shimmer-text~="active"]):not([shimmer-text~="focus"]) { color: transparent }

*[shimmer-text~="hover"] {
    animation-play-state: paused
}

*[shimmer-text~="hover"]:hover {
    animation-play-state: running
}

*[shimmer-text~="active"], *[shimmer-text~="focus"] {
    animation: none
}

*[shimmer-text~="active"]:active, *[shimmer-text~="focus"]:focus {
    color: transparent;
    animation: shimmer var(--shimmer-duration) linear infinite
}

/* underline */
*[underline] {
    --transition-duration: var(--td-slow);
    --underline-duration: var(--transition-duration);
    --underline-color: currentColor;
    --underline-width: 2px;
    --underline-offset: 2px;
    --underline-start: 0%;
    --underline-direction: center;

    position: relative
}

*[underline]::after {
    will-change: width;
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    margin-left: auto;
    margin-right: auto;
    bottom: calc(-1 * var(--underline-offset));
    height: var(--underline-width);
    width: var(--underline-start);
    background: var(--underline-color);
    transition: width var(--underline-duration) ease
}

*[underline~="left"]::after { margin-left: 0 }
*[underline~="right"]::after { margin-right: 0 }
*[underline~="left"][underline~="right"]::after { margin-left: auto; margin-right: auto; }

*[underline]:not([underline~="hover"]):not([underline~="active"]):not([underline~="focus"])::after { width: 100% }

*[underline~="hover"]:hover::after, *[underline~="active"]:active::after, *[underline~="focus"]:focus::after {
    width: 100%
}

/* spin */
@keyframes spin { to { transform: rotate(360deg) } }

*[spin] {
    --transition-duration: var(--td-slow);
    --spin-duration: var(--transition-duration);
    --spin-iteration-count: var(--iteration-count);

    will-change: transform;
    animation: spin var(--spin-duration) linear var(--spin-iteration-count);
}

*[spin~="infinite"] { --spin-iteration-count: infinite }

*[spin~="hover"], *[spin~="active"], *[spin~="focus"] {
    animation: none
}

*[spin~="hover"]:hover, *[spin~="active"]:active, *[spin~="focus"]:focus {
    animation: spin var(--spin-duration) linear var(--spin-iteration-count)
}

/* bounce */
@keyframes bounce {
  0%, 100% {
        transform: translateY(0);
        animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
  }
  50% {
        transform: translateY(calc(-1 * var(--bounce-height)));
        animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
  }
}

*[bounce] {
    --transition-duration: var(--td-medium);
    --bounce-duration: var(--transition-duration);
    --bounce-height: 30px;
    --bounce-iteration-count: var(--iteration-count);

    will-change: transform;
    animation: bounce var(--bounce-duration) ease-in-out var(--bounce-iteration-count)
}

*[bounce~="infinite"] { --bounce-iteration-count: infinite }

*[bounce~="hover"], *[bounce~="active"], *[bounce~="focus"] {
    animation: none
}

*[bounce~="hover"]:hover, *[bounce~="active"]:active, *[bounce~="focus"]:focus {
    animation: bounce var(--bounce-duration) ease-in-out var(--bounce-iteration-count)
}

*[td], *[td]::before, *[td]::after { transition-duration: var(--transition-duration) !important }
*[td="rapid"] { --transition-duration: var(--td-rapid) }
*[td="fast"] { --transition-duration: var(--td-fast) }
*[td="medium"] { --transition-duration: var(--td-medium) }
*[td="slow"] { --transition-duration: var(--td-slow) }
*[td="1s"] { --transition-duration: 1s }
*[td="2s"] { --transition-duration: 2s }
*[td="3s"] { --transition-duration: 3s }
*[td="5s"] { --transition-duration: 5s }
*[td="none"] { --transition-duration: none }

*[infinite] { --iteration-count: infinite; }

@media (prefers-reduced-motion:reduce) {
    *[pulse],
    *[wobble],
    *[sheen]::before,
    *[float], 
    *[heartbeat], 
    *[jello], 
    *[ripple]::after, 
    *[shimmer-text],
    *[shadow-pop],
    *[vibrate],
    *[bounce],
    *[spin] {
        animation: none !important;
        transition: none !important
    }
}