/* TextFX: per-letter text animations. Markup is built by textfx.js.
   Each letter is .tfx-c (its entrance animation) wrapping one span per looping effect,
   so several effects can stack without fighting over `transform`. --i is the letter index
   (used to phase-shift loops along the word), --d is the entrance delay. */

.tfx-word { display: inline-block; white-space: nowrap; }
.tfx-sp { display: inline-block; width: .3em; }
.tfx-c, .tfx-c span { display: inline-block; }

/* ---------- entrances (one per letter) ---------- */
.tfx-in-pop     { animation: tfx-pop .38s cubic-bezier(.2,.9,.3,1.6) var(--d, 0s) both; }
.tfx-in-drop    { animation: tfx-drop .55s cubic-bezier(.3,.8,.4,1) var(--d, 0s) both; }
.tfx-in-rise    { animation: tfx-rise .35s cubic-bezier(.2,.8,.3,1) var(--d, 0s) both; }
.tfx-in-spin    { animation: tfx-spin-in .5s cubic-bezier(.3,1.4,.5,1) var(--d, 0s) both; }
.tfx-in-slam    { animation: tfx-slam .34s cubic-bezier(.5,0,.3,1) var(--d, 0s) both; }
.tfx-in-fade    { animation: tfx-fade .45s ease-out var(--d, 0s) both; }
.tfx-in-stretch { animation: tfx-stretch .42s cubic-bezier(.2,.9,.3,1.3) var(--d, 0s) both; transform-origin: 50% 100%; }
.tfx-in-swirl   { animation: tfx-swirl .5s cubic-bezier(.2,.9,.3,1.2) var(--d, 0s) both; }

@keyframes tfx-pop     { from { transform: scale(0) translateY(.3em); opacity: 0; } 60% { transform: scale(1.25); opacity: 1; } to { transform: none; } }
@keyframes tfx-drop    { from { transform: translateY(-1.4em); opacity: 0; } 55% { transform: translateY(.14em); opacity: 1; } 78% { transform: translateY(-.06em); } to { transform: none; } }
@keyframes tfx-rise    { from { transform: translateY(.7em); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes tfx-spin-in { from { transform: rotate(-200deg) scale(0); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes tfx-slam    { from { transform: scale(3.2); opacity: 0; } 65% { transform: scale(.88); opacity: 1; } 82% { transform: scale(1.07) rotate(-3deg); } to { transform: none; } }
@keyframes tfx-fade    { from { opacity: 0; filter: blur(4px); } to { opacity: 1; filter: none; } }
@keyframes tfx-stretch { from { transform: scale(1.5, 0); opacity: 0; } 55% { transform: scale(.85, 1.35); opacity: 1; } 80% { transform: scale(1.06, .94); } to { transform: none; } }
@keyframes tfx-swirl   { from { transform: rotate(90deg) translate(.8em, -.6em); opacity: 0; } to { transform: none; opacity: 1; } }

/* ---------- looping effects (stackable) ---------- */
.tfx-float   { animation: tfx-float 1.6s ease-in-out infinite calc(var(--i, 0) * -.1s); }
.tfx-wave    { animation: tfx-wave 1.1s ease-in-out infinite calc(var(--i, 0) * -.09s); }
.tfx-bounce  { animation: tfx-bounce .9s cubic-bezier(.3,0,.6,1) infinite calc(var(--i, 0) * -.12s); transform-origin: 50% 100%; }
.tfx-shake   { animation: tfx-shake .28s steps(1) infinite calc(var(--i, 0) * -.07s); }
.tfx-shiver  { animation: tfx-shiver .12s steps(1) infinite calc(var(--i, 0) * -.05s); }
.tfx-wiggle  { animation: tfx-wiggle .45s ease-in-out infinite alternate calc(var(--i, 0) * -.11s); }
.tfx-swing   { animation: tfx-swing 1.4s ease-in-out infinite alternate calc(var(--i, 0) * -.15s); transform-origin: 50% -30%; }
.tfx-dangle  { animation: tfx-dangle 2s ease-in-out infinite calc(var(--i, 0) * -.23s); transform-origin: 50% 0; }
.tfx-pulse   { animation: tfx-pulse .8s ease-in-out infinite calc(var(--i, 0) * -.06s); }
.tfx-spin    { animation: tfx-spin 1.6s linear infinite calc(var(--i, 0) * -.1s); }
.tfx-rainbow { animation: tfx-rainbow 1.6s linear infinite calc(var(--i, 0) * -.1s); }
.tfx-glitch  { animation: tfx-glitch 2.2s steps(1) infinite calc(var(--i, 0) * -.37s); }
.tfx-flicker { animation: tfx-flicker 1.8s steps(1) infinite calc(var(--i, 0) * -.29s); }

@keyframes tfx-float   { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-.08em); } }
@keyframes tfx-wave    { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-.28em); } }
@keyframes tfx-bounce  { 0%, 100% { transform: translateY(0); } 35% { transform: translateY(-.45em); } 55% { transform: translateY(0) scale(1.12, .86); } 68% { transform: scale(1); } }
@keyframes tfx-shake   { 0% { transform: translate(.05em, -.04em); } 25% { transform: translate(-.06em, .05em); } 50% { transform: translate(.04em, .06em); } 75% { transform: translate(-.05em, -.05em); } }
@keyframes tfx-shiver  { 0% { transform: translate(.02em, -.015em); } 50% { transform: translate(-.02em, .02em); } }
@keyframes tfx-wiggle  { from { transform: rotate(-9deg); } to { transform: rotate(9deg); } }
@keyframes tfx-swing   { from { transform: rotate(-14deg); } to { transform: rotate(14deg); } }
@keyframes tfx-dangle  { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(22deg) translateY(.04em); } 70% { transform: rotate(-14deg); } }
@keyframes tfx-pulse   { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.28); } }
@keyframes tfx-spin    { to { transform: rotate(360deg); } }
@keyframes tfx-rainbow { 0%, 100% { color: #ff4f9a; } 20% { color: #ffb020; } 40% { color: #5ed64b; } 60% { color: #35b8ff; } 80% { color: #a98bff; } }
@keyframes tfx-glitch  { 0%, 86% { transform: none; text-shadow: none; } 88% { transform: translate(.08em, 0) skewX(-14deg); text-shadow: -.07em 0 #35e0ff, .07em 0 #ff4f9a; } 92% { transform: translate(-.1em, .04em); } 96% { transform: translate(.04em, -.06em) skewX(10deg); text-shadow: .05em 0 #35e0ff, -.05em 0 #ff4f9a; } }
@keyframes tfx-flicker { 0%, 100% { opacity: 1; } 40% { opacity: .2; } 44% { opacity: 1; } 70% { opacity: .5; } 72% { opacity: 1; } }

/* ---------- static styles ---------- */
.tfx-pink   { color: #ff4f9a; }
.tfx-orange { color: #f07f1c; }
.tfx-yellow { color: #ffc21a; }
.tfx-green  { color: #2fae4a; }
.tfx-blue   { color: #1f8fd6; }
.tfx-purple { color: #7a3fe0; }
.tfx-red    { color: #e8364f; }

@media (prefers-reduced-motion: reduce) {
  .tfx-c, .tfx-c span { animation: none !important; }
}
