diff --git a/index.html b/index.html
index 781b0ba3..5b684594 100644
--- a/index.html
+++ b/index.html
@@ -6,7 +6,6 @@
Akkoma
-
diff --git a/src/components/status_content/mfm.scss b/src/components/status_content/mfm.scss
index 45d32d4e..f5d77938 100644
--- a/src/components/status_content/mfm.scss
+++ b/src/components/status_content/mfm.scss
@@ -1,5 +1,331 @@
-/* Some MFM CSS is also defined in ./static/mfm.css */
-.StatusContent {
+/**
+ * "FEP-c16b: Formatting MFM functions" attributes that Akkoma supports
+ */
+
+.StatusContent:not(.mfm-disabled) {
+ /* The following are the non-animated MFM */
+ .mfm-center {
+ display: block;
+ text-align: center;
+ }
+
+ .mfm-flip {
+ display: inline-block;
+ transform: scaleX(-1);
+ }
+
+ .mfm-flip[data-mfm-v] {
+ transform: scaleY(-1);
+ }
+
+ .mfm-flip[data-mfm-v][data-mfm-h] {
+ transform: scale(-1, -1);
+ }
+
+ .mfm-font[data-mfm-serif] {
+ font-family: serif;
+ }
+
+ .mfm-font[data-mfm-monospace] {
+ font-family: monospace;
+ }
+
+ .mfm-font[data-mfm-cursive] {
+ font-family: cursive;
+ }
+
+ .mfm-font[data-mfm-fantasy] {
+ font-family: fantasy;
+ }
+
+ .mfm-font[data-mfm-emoji] {
+ font-family: emoji;
+ }
+
+ .mfm-font[data-mfm-math] {
+ font-family: math;
+ }
+
+ .mfm-blur {
+ filter: blur(6px);
+ transition: filter 0.3s;
+
+ &:hover {
+ filter: blur(0);
+ }
+ }
+
+ .mfm-rotate {
+ display: inline-block;
+ transform: rotate(calc(var(--mfm-deg, 90) * 1deg));
+ transform-origin: center center;
+ }
+
+ .mfm-x2 {
+ --mfm-zoom-size: 200%;
+ }
+
+ .mfm-x3 {
+ --mfm-zoom-size: 400%;
+ }
+
+ .mfm-x4 {
+ --mfm-zoom-size: 600%;
+ }
+
+ .mfm-x2,
+ .mfm-x3,
+ .mfm-x4,
+ .mfm-tada {
+ font-size: var(--mfm-zoom-size);
+
+ .mfm-x2,
+ .mfm-x3,
+ .mfm-x4,
+ .mfm-tada {
+ /* only half effective */
+ font-size: calc(var(--mfm-zoom-size) / 2 + 50%);
+
+ .mfm-x2,
+ .mfm-x3,
+ .mfm-x4,
+ .mfm-tada {
+ /* disabled */
+ font-size: 100%;
+ }
+ }
+ }
+
+ .mfm-position {
+ transform: translate(calc(var(--mfm-x, 0) * 1em), calc(var(--mfm-y, 0) * 1em));
+ }
+
+ .mfm-scale {
+ transform: scale(var(--mfm-x, 1), var(--mfm-y, 1));
+ }
+
+ .mfm-fg {
+ color: var(--mfm-color, #f00);
+ }
+
+ .mfm-bg {
+ background-color: var(--mfm-color, #0f0);
+ }
+
+ /* The following are the animated MFM */
+
+ /* .mfm-hover means that we should only play animation when hovering over the StatusContent
+ * So either StatusContent does not have this class,
+ * or it has the class and we are hovering over StatusContent
+ */
+ &:not(.mfm-hover:not(:hover)) {
+ .mfm-jelly {
+ display: inline-block;
+ animation: mfm-rubberBand var(--mfm-speed, 1s) linear infinite both;
+ }
+
+ .mfm-twitch {
+ display: inline-block;
+ animation: mfm-twitch var(--mfm-speed, 0.5s) ease infinite;
+ }
+
+ .mfm-shake {
+ display: inline-block;
+ animation: mfm-shake var(--mfm-speed, 0.5s) ease infinite;
+ }
+
+ .mfm-spin {
+ display: inline-block;
+ animation: mfm-spin var(--mfm-speed, 1.5s) linear infinite;
+ }
+
+ .mfm-spin[data-mfm-y] {
+ animation-name: mfm-spinY;
+ }
+
+ .mfm-spin[data-mfm-x] {
+ animation-name: mfm-spinX;
+ }
+
+ .mfm-spin[data-mfm-alternate] {
+ animation-direction: alternate;
+ }
+
+ .mfm-spin[data-mfm-left] {
+ animation-direction: reverse;
+ }
+
+ .mfm-jump {
+ display: inline-block;
+ animation: mfm-jump var(--mfm-speed, 0.75s) linear infinite;
+ }
+
+ .mfm-bounce {
+ display: inline-block;
+ animation: mfm-bounce var(--mfm-speed, 0.75s) linear infinite;
+ transform-origin: center bottom;
+ }
+
+ .mfm-rainbow {
+ animation: mfm-rainbow var(--mfm-speed, 1s) linear infinite;
+ }
+
+ .mfm-tada {
+ display: inline-block;
+ animation: mfm-tada var(--mfm-speed, 1s) linear infinite both;
+
+ --mfm-zoom-size: 150%;
+ }
+ }
+
+ /* animation keyframes */
+
+ @keyframes mfm-spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+ }
+
+ @keyframes mfm-spinX {
+ 0% { transform: perspective(128px) rotateX(0deg); }
+ 100% { transform: perspective(128px) rotateX(360deg); }
+ }
+
+ @keyframes mfm-spinY {
+ 0% { transform: perspective(128px) rotateY(0deg); }
+ 100% { transform: perspective(128px) rotateY(360deg); }
+ }
+
+ @keyframes mfm-jump {
+ 0% { transform: translateY(0); }
+ 25% { transform: translateY(-16px); }
+ 50% { transform: translateY(0); }
+ 75% { transform: translateY(-8px); }
+ 100% { transform: translateY(0); }
+ }
+
+ @keyframes mfm-bounce {
+ 0% { transform: translateY(0) scale(1, 1); }
+ 25% { transform: translateY(-16px) scale(1, 1); }
+ 50% { transform: translateY(0) scale(1, 1); }
+ 75% { transform: translateY(0) scale(1.5, 0.75); }
+ 100% { transform: translateY(0) scale(1, 1); }
+ }
+
+ @keyframes mfm-twitch {
+ 0% { transform: translate(7px, -2px); }
+ 5% { transform: translate(-3px, 1px); }
+ 10% { transform: translate(-7px, -1px); }
+ 15% { transform: translate(0, -1px); }
+ 20% { transform: translate(-8px, 6px); }
+ 25% { transform: translate(-4px, -3px); }
+ 30% { transform: translate(-4px, -6px); }
+ 35% { transform: translate(-8px, -8px); }
+ 40% { transform: translate(4px, 6px); }
+ 45% { transform: translate(-3px, 1px); }
+ 50% { transform: translate(2px, -10px); }
+ 55% { transform: translate(-7px, 0); }
+ 60% { transform: translate(-2px, 4px); }
+ 65% { transform: translate(3px, -8px); }
+ 70% { transform: translate(6px, 7px); }
+ 75% { transform: translate(-7px, -2px); }
+ 80% { transform: translate(-7px, -8px); }
+ 85% { transform: translate(9px, 3px); }
+ 90% { transform: translate(-3px, -2px); }
+ 95% { transform: translate(-10px, 2px); }
+ 100% { transform: translate(-2px, -6px); }
+ }
+
+ @keyframes mfm-shake {
+ 0% { transform: translate(-3px, -1px) rotate(-8deg); }
+ 5% { transform: translate(0, -1px) rotate(-10deg); }
+ 10% { transform: translate(1px, -3px) rotate(0deg); }
+ 15% { transform: translate(1px, 1px) rotate(11deg); }
+ 20% { transform: translate(-2px, 1px) rotate(1deg); }
+ 25% { transform: translate(-1px, -2px) rotate(-2deg); }
+ 30% { transform: translate(-1px, 2px) rotate(-3deg); }
+ 35% { transform: translate(2px, 1px) rotate(6deg); }
+ 40% { transform: translate(-2px, -3px) rotate(-9deg); }
+ 45% { transform: translate(0, -1px) rotate(-12deg); }
+ 50% { transform: translate(1px, 2px) rotate(10deg); }
+ 55% { transform: translate(0, -3px) rotate(8deg); }
+ 60% { transform: translate(1px, -1px) rotate(8deg); }
+ 65% { transform: translate(0, -1px) rotate(-7deg); }
+ 70% { transform: translate(-1px, -3px) rotate(6deg); }
+ 75% { transform: translate(0, -2px) rotate(4deg); }
+ 80% { transform: translate(-2px, -1px) rotate(3deg); }
+ 85% { transform: translate(1px, -3px) rotate(-10deg); }
+ 90% { transform: translate(1px, 0) rotate(3deg); }
+ 95% { transform: translate(-2px, 0) rotate(-3deg); }
+ 100% { transform: translate(2px, 1px) rotate(2deg); }
+ }
+
+ @keyframes mfm-rubberBand {
+ 0% { transform: scale3d(1, 1, 1); }
+ 30% { transform: scale3d(1.25, 0.75, 1); }
+ 40% { transform: scale3d(0.75, 1.25, 1); }
+ 50% { transform: scale3d(1.15, 0.85, 1); }
+ 65% { transform: scale3d(0.95, 1.05, 1); }
+ 75% { transform: scale3d(1.05, 0.95, 1); }
+ 100% { transform: scale3d(1, 1, 1); }
+ }
+
+ @keyframes mfm-rainbow {
+ 0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); }
+ 100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); }
+ }
+
+ @keyframes mfm-tada {
+ 0%,
+ 100% { transform: scale3d(1, 1, 1); }
+
+ 10%,
+ 20% { transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); }
+
+ 30%,
+ 50%,
+ 70%,
+ 90% { transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); }
+
+ 40%,
+ 60%,
+ 80% { transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); }
+ }
+
+ /**
+ * Legacy MFM
+ * This is for backwards compatibility with posts formatted on Akkoma before support for FEP-c16b
+ * Note that it uses the keyframes as defined above for the FEP-c16b compatible MFM representation
+ */
+
+ .mfm {
+ display: inline-block;
+ }
+
+ /* The following are the legacy non-animated MFM */
+ ._mfm_flip_[data-h][data-v] {
+ transform: scale(-1, -1);
+ }
+
+ ._mfm_flip_[data-v] {
+ transform: scaleY(-1);
+ }
+
+ ._mfm_flip_:not([data-v]) {
+ transform: scaleX(-1);
+ }
+
+ ._mfm_x2_ {
+ font-size: 200%;
+ }
+
+ ._mfm_x3_ {
+ font-size: 400%;
+ }
+
+ ._mfm_x4_ {
+ font-size: 600%;
+ }
+
._mfm_x2_ {
.emoji {
height: 100px;
@@ -18,20 +344,75 @@
}
}
- &.mfm-hover:not(:hover) {
- .mfm {
- animation: none !important;
- }
+ ._mfm_blur_ {
+ filter: blur(6px);
+ transition: filter 0.3s;
}
- &.mfm-disabled {
- span {
- font-size: 100% !important;
+
+ ._mfm_blur_:hover {
+ filter: blur(0);
+ }
+
+ ._mfm_rotate_ {
+ transform: rotate(90deg);
+ transform-origin: center center;
+ }
+
+ /* The following are the legacy animated MFM */
+
+ /* .mfm-hover means that we should only play animation when hovering over the StatusContent
+ * So either StatusContent does not have this class,
+ * or it has the class and we are hovering over StatusContent
+ */
+ &:not(.mfm-hover:not(:hover)) {
+ ._mfm_tada_ {
+ font-size: 150%;
+ animation: mfm-tada 1s linear infinite both;
}
- .mfm {
- animation: none !important;
+
+ ._mfm_jelly_ {
+ animation: mfm-rubberBand 1s linear infinite both;
}
- .emoji {
- height: 32px !important;
+
+ ._mfm_twitch_ {
+ animation: mfm-twitch 0.5s ease infinite;
+ }
+
+ ._mfm_shake_ {
+ animation: mfm-shake 0.5s ease infinite;
+ }
+
+ ._mfm_spin_ {
+ animation: mfm-spin 0.5s linear infinite;
+ }
+
+ ._mfm_spin_[data-x] {
+ animation-name: mfm-spinX;
+ }
+
+ ._mfm_spin_[data-y] {
+ animation-name: mfm-spinY;
+ }
+
+ ._mfm_spin_[left] {
+ animation-direction: reverse;
+ }
+
+ ._mfm_spin_[alternate] {
+ animation-direction: alternate;
+ }
+
+ ._mfm_jump_ {
+ animation: mfm-jump 0.75s linear infinite;
+ }
+
+ ._mfm_bounce_ {
+ animation: mfm-bounce 0.75s linear infinite;
+ transform-origin: center bottom;
+ }
+
+ ._mfm_rainbow_ {
+ animation: mfm-rainbow 1s linear infinite;
}
}
}
diff --git a/src/components/status_content/mfm_foundkey.scss b/src/components/status_content/mfm_foundkey.scss
deleted file mode 100644
index 6932b98a..00000000
--- a/src/components/status_content/mfm_foundkey.scss
+++ /dev/null
@@ -1,274 +0,0 @@
-.mfm-center {
- display: block;
- text-align: center;
-}
-
-.mfm-flip {
- display: inline-block;
- transform: scaleX(-1);
-}
-.mfm-flip[data-mfm-v] {
- transform: scaleY(-1);
-}
-.mfm-flip[data-mfm-v][data-mfm-h] {
- transform: scale(-1, -1);
-}
-
-.mfm-font[data-mfm-serif] {
- font-family: serif;
-}
-.mfm-font[data-mfm-monospace] {
- font-family: monospace;
-}
-.mfm-font[data-mfm-cursive] {
- font-family: cursive;
-}
-.mfm-font[data-mfm-fantasy] {
- font-family: fantasy;
-}
-.mfm-font[data-mfm-emoji] {
- font-family: emoji;
-}
-.mfm-font[data-mfm-math] {
- font-family: math;
-}
-
-.mfm-blur {
- filter: blur(6px);
- transition: filter 0.3s;
-
- &:hover {
- filter: blur(0px);
- }
-}
-
-.mfm-rotate {
- display: inline-block;
- transform: rotate(calc(var(--mfm-deg, 90) * 1deg));
- transform-origin: center center;
-}
-
-.mfm-x2 {
- --mfm-zoom-size: 200%;
-}
-.mfm-x3 {
- --mfm-zoom-size: 400%;
-}
-.mfm-x4 {
- --mfm-zoom-size: 600%;
-}
-.mfm-x2, .mfm-x3, .mfm-x4, .mfm-tada {
- font-size: var(--mfm-zoom-size);
-
- .mfm-x2, .mfm-x3, .mfm-x4, .mfm-tada {
- /* only half effective */
- font-size: calc(var(--mfm-zoom-size) / 2 + 50%);
-
- .mfm-x2, .mfm-x3, .mfm-x4, .mfm-tada {
- /* disabled */
- font-size: 100%;
- }
- }
-}
-
-.mfm-position {
- transform: translate(calc(var(--mfm-x, 0) * 1em), calc(var(--mfm-y, 0) * 1em));
-}
-
-.mfm-scale {
- transform: scale(var(--mfm-x, 1), var(--mfm-y, 1));
-}
-
-.mfm-fg {
- color: var(--mfm-color, #f00);
-}
-
-.mfm-bg {
- background-color: var(--mfm-color, #0f0);
-}
-
-.markdown-container {
- blockquote {
- display: block;
- margin: 8px;
- padding: 6px 0 6px 12px;
- color: var(--fg);
- border-left: solid 3px var(--fg);
- opacity: 0.7;
- }
-
- blockquote blockquote blockquote {
- opacity: 1;
- }
-
- blockquote > p:first-child {
- margin-top: 0;
- }
- blockquote > p:last-child {
- margin-bottom: 0;
- }
-}
-
-.animated-mfm {
- .mfm-jelly {
- display: inline-block;
- animation: mfm-rubberBand var(--mfm-speed, 1s) linear infinite both;
- }
-
- .mfm-twitch {
- display: inline-block;
- animation: mfm-twitch var(--mfm-speed, .5s) ease infinite;
- }
-
- .mfm-shake {
- display: inline-block;
- animation: mfm-shake var(--mfm-speed, .5s) ease infinite;
- }
-
- .mfm-spin {
- display: inline-block;
- animation: mfm-spin var(--mfm-speed, 1.5s) linear infinite;
- }
- .mfm-spin[data-mfm-y] {
- animation-name: mfm-spinY;
- }
- .mfm-spin[data-mfm-x] {
- animation-name: mfm-spinX;
- }
- .mfm-spin[data-mfm-alternate] {
- animation-direction: alternate;
- }
- .mfm-spin[data-mfm-left] {
- animation-direction: reverse;
- }
-
- .mfm-jump {
- display: inline-block;
- animation: mfm-jump var(--mfm-speed, .75s) linear infinite;
- }
-
- .mfm-bounce {
- display: inline-block;
- animation: mfm-bounce var(--mfm-speed, .75s) linear infinite;
- transform-origin: center bottom;
- }
-
- .mfm-rainbow {
- animation: mfm-rainbow var(--mfm-speed, 1s) linear infinite;
- }
-
- .mfm-tada {
- display: inline-block;
- animation: mfm-tada var(--mfm-speed, 1s) linear infinite both;
- --mfm-zoom-size: 150%;
- }
-}
-
-/* animation keyframes */
-
-@keyframes mfm-spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
-}
-
-@keyframes mfm-spinX {
- 0% { transform: perspective(128px) rotateX(0deg); }
- 100% { transform: perspective(128px) rotateX(360deg); }
-}
-
-@keyframes mfm-spinY {
- 0% { transform: perspective(128px) rotateY(0deg); }
- 100% { transform: perspective(128px) rotateY(360deg); }
-}
-
-@keyframes mfm-jump {
- 0% { transform: translateY(0); }
- 25% { transform: translateY(-16px); }
- 50% { transform: translateY(0); }
- 75% { transform: translateY(-8px); }
- 100% { transform: translateY(0); }
-}
-
-@keyframes mfm-bounce {
- 0% { transform: translateY(0) scale(1, 1); }
- 25% { transform: translateY(-16px) scale(1, 1); }
- 50% { transform: translateY(0) scale(1, 1); }
- 75% { transform: translateY(0) scale(1.5, 0.75); }
- 100% { transform: translateY(0) scale(1, 1); }
-}
-
-// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`;
-// let css = '';
-// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
-@keyframes mfm-twitch {
- 0% { transform: translate(7px, -2px) }
- 5% { transform: translate(-3px, 1px) }
- 10% { transform: translate(-7px, -1px) }
- 15% { transform: translate(0px, -1px) }
- 20% { transform: translate(-8px, 6px) }
- 25% { transform: translate(-4px, -3px) }
- 30% { transform: translate(-4px, -6px) }
- 35% { transform: translate(-8px, -8px) }
- 40% { transform: translate(4px, 6px) }
- 45% { transform: translate(-3px, 1px) }
- 50% { transform: translate(2px, -10px) }
- 55% { transform: translate(-7px, 0px) }
- 60% { transform: translate(-2px, 4px) }
- 65% { transform: translate(3px, -8px) }
- 70% { transform: translate(6px, 7px) }
- 75% { transform: translate(-7px, -2px) }
- 80% { transform: translate(-7px, -8px) }
- 85% { transform: translate(9px, 3px) }
- 90% { transform: translate(-3px, -2px) }
- 95% { transform: translate(-10px, 2px) }
- 100% { transform: translate(-2px, -6px) }
-}
-
-// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`;
-// let css = '';
-// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
-@keyframes mfm-shake {
- 0% { transform: translate(-3px, -1px) rotate(-8deg) }
- 5% { transform: translate(0px, -1px) rotate(-10deg) }
- 10% { transform: translate(1px, -3px) rotate(0deg) }
- 15% { transform: translate(1px, 1px) rotate(11deg) }
- 20% { transform: translate(-2px, 1px) rotate(1deg) }
- 25% { transform: translate(-1px, -2px) rotate(-2deg) }
- 30% { transform: translate(-1px, 2px) rotate(-3deg) }
- 35% { transform: translate(2px, 1px) rotate(6deg) }
- 40% { transform: translate(-2px, -3px) rotate(-9deg) }
- 45% { transform: translate(0px, -1px) rotate(-12deg) }
- 50% { transform: translate(1px, 2px) rotate(10deg) }
- 55% { transform: translate(0px, -3px) rotate(8deg) }
- 60% { transform: translate(1px, -1px) rotate(8deg) }
- 65% { transform: translate(0px, -1px) rotate(-7deg) }
- 70% { transform: translate(-1px, -3px) rotate(6deg) }
- 75% { transform: translate(0px, -2px) rotate(4deg) }
- 80% { transform: translate(-2px, -1px) rotate(3deg) }
- 85% { transform: translate(1px, -3px) rotate(-10deg) }
- 90% { transform: translate(1px, 0px) rotate(3deg) }
- 95% { transform: translate(-2px, 0px) rotate(-3deg) }
- 100% { transform: translate(2px, 1px) rotate(2deg) }
-}
-
-@keyframes mfm-rubberBand {
- from { transform: scale3d(1, 1, 1); }
- 30% { transform: scale3d(1.25, 0.75, 1); }
- 40% { transform: scale3d(0.75, 1.25, 1); }
- 50% { transform: scale3d(1.15, 0.85, 1); }
- 65% { transform: scale3d(0.95, 1.05, 1); }
- 75% { transform: scale3d(1.05, 0.95, 1); }
- to { transform: scale3d(1, 1, 1); }
-}
-
-@keyframes mfm-rainbow {
- 0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); }
- 100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); }
-}
-
-@keyframes mfm-tada {
- 0%, 100% { transform: scale3d(1, 1, 1); }
- 10%, 20% { transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); }
- 30%, 50%, 70%, 90% { transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); }
- 40%, 60%, 80% { transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); }
-}
diff --git a/static/mfm.css b/static/mfm.css
deleted file mode 100644
index a386ad3c..00000000
--- a/static/mfm.css
+++ /dev/null
@@ -1,228 +0,0 @@
-/* Some MFM CSS is also defined in ./src/components/status_content/mfm.scss */
-.mfm {
- display: inline-block;
-}
-
-._mfm_tada_ {
- font-size: 150%;
- animation: mfm-tada 1s linear infinite both;
-}
-
-._mfm_jelly_ {
- animation: mfm-jelly 1s linear infinite both;
-}
-
-._mfm_twitch_ {
- animation: mfm-twitch 0.5s ease infinite;
-}
-
-._mfm_shake_ {
- animation: mfm-shake 0.5s ease infinite;
-}
-
-._mfm_spin_ {
- animation: mfm-spin 0.5s linear infinite;
-}
-
-._mfm_spin_[data-x] {
- animation-name: mfm-spinX;
-}
-._mfm_spin_[data-y] {
- animation-name: mfm-spinY;
-}
-._mfm_spin_[left] {
- animation-direction: reverse;
-}
-._mfm_spin_[alternate] {
- animation-direction: alternate;
-}
-
-._mfm_jump_ {
- animation: mfm-jump 0.75s linear infinite;
-}
-
-._mfm_bounce_ {
- animation: mfm-bounce 0.75s linear infinite;
- transform-origin: center bottom;
-}
-
-._mfm_flip_[data-h][data-v] {
- transform: scale(-1, -1);
-}
-._mfm_flip_[data-v] {
- transform: scaleY(-1);
-}
-._mfm_flip_:not([data-v]) {
- transform: scaleX(-1);
-}
-
-._mfm_x2_ {
- font-size: 200%;
-}
-
-._mfm_x3_ {
- font-size: 400%;
-}
-
-._mfm_x4_ {
- font-size: 600%;
-}
-
-._mfm_blur_ {
- filter: blur(6px);
- transition: filter 0.3s
-}
-._mfm_blur_:hover {
- filter: blur(0px);
-}
-
-._mfm_rainbow_ {
- animation: mfm-rainbow 1s linear infinite;
-}
-
-._mfm_rotate_ {
- transform: rotate(90deg);
- transform-origin: center center;
-}
-
-/* sparkle */
-
-@keyframes mfm-tada {
- from {
- transform: scale3d(1, 1, 1);
- }
-
- 10%,
- 20% {
- transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
- }
-
- 30%,
- 50%,
- 70%,
- 90% {
- transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
- }
-
- 40%,
- 60%,
- 80% {
- transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
- }
-
- to {
- transform: scale3d(1, 1, 1);
- }
-}
-
-@keyframes bounce {
- 0% {
- transform: scaleX(0.9) scaleY(0.9);
- }
-
- 19% {
- transform: scaleX(1.1) scaleY(1.1);
- }
-
- 48% {
- transform: scaleX(0.95) scaleY(0.95);
- }
-
- 100% {
- transform: scaleX(1) scaleY(1);
- }
-}
-
-@keyframes mfm-spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
-}
-
-@keyframes mfm-spinX {
- 0% { transform: perspective(128px) rotateX(0deg); }
- 100% { transform: perspective(128px) rotateX(360deg); }
-}
-
-@keyframes mfm-spinY {
- 0% { transform: perspective(128px) rotateY(0deg); }
- 100% { transform: perspective(128px) rotateY(360deg); }
-}
-
-@keyframes mfm-jump {
- 0% { transform: translateY(0); }
- 25% { transform: translateY(-16px); }
- 50% { transform: translateY(0); }
- 75% { transform: translateY(-8px); }
- 100% { transform: translateY(0); }
-}
-
-@keyframes mfm-bounce {
- 0% { transform: translateY(0) scale(1, 1); }
- 25% { transform: translateY(-16px) scale(1, 1); }
- 50% { transform: translateY(0) scale(1, 1); }
- 75% { transform: translateY(0) scale(1.5, 0.75); }
- 100% { transform: translateY(0) scale(1, 1); }
-}
-
-@keyframes mfm-twitch {
- 0% { transform: translate(7px, -2px); }
- 5% { transform: translate(-3px, 1px); }
- 10% { transform: translate(-7px, -1px); }
- 15% { transform: translate(0, -1px); }
- 20% { transform: translate(-8px, 6px); }
- 25% { transform: translate(-4px, -3px); }
- 30% { transform: translate(-4px, -6px); }
- 35% { transform: translate(-8px, -8px); }
- 40% { transform: translate(4px, 6px); }
- 45% { transform: translate(-3px, 1px); }
- 50% { transform: translate(2px, -10px); }
- 55% { transform: translate(-7px, 0); }
- 60% { transform: translate(-2px, 4px); }
- 65% { transform: translate(3px, -8px); }
- 70% { transform: translate(6px, 7px); }
- 75% { transform: translate(-7px, -2px); }
- 80% { transform: translate(-7px, -8px); }
- 85% { transform: translate(9px, 3px); }
- 90% { transform: translate(-3px, -2px); }
- 95% { transform: translate(-10px, 2px); }
- 100% { transform: translate(-2px, -6px); }
-}
-
-@keyframes mfm-shake {
- 0% { transform: translate(-3px, -1px) rotate(-8deg); }
- 5% { transform: translate(0, -1px) rotate(-10deg); }
- 10% { transform: translate(1px, -3px) rotate(0deg); }
- 15% { transform: translate(1px, 1px) rotate(11deg); }
- 20% { transform: translate(-2px, 1px) rotate(1deg); }
- 25% { transform: translate(-1px, -2px) rotate(-2deg); }
- 30% { transform: translate(-1px, 2px) rotate(-3deg); }
- 35% { transform: translate(2px, 1px) rotate(6deg); }
- 40% { transform: translate(-2px, -3px) rotate(-9deg); }
- 45% { transform: translate(0, -1px) rotate(-12deg); }
- 50% { transform: translate(1px, 2px) rotate(10deg); }
- 55% { transform: translate(0, -3px) rotate(8deg); }
- 60% { transform: translate(1px, -1px) rotate(8deg); }
- 65% { transform: translate(0, -1px) rotate(-7deg); }
- 70% { transform: translate(-1px, -3px) rotate(6deg); }
- 75% { transform: translate(0, -2px) rotate(4deg); }
- 80% { transform: translate(-2px, -1px) rotate(3deg); }
- 85% { transform: translate(1px, -3px) rotate(-10deg); }
- 90% { transform: translate(1px, 0) rotate(3deg); }
- 95% { transform: translate(-2px, 0) rotate(-3deg); }
- 100% { transform: translate(2px, 1px) rotate(2deg); }
-}
-
-@keyframes mfm-jelly {
- from { transform: scale3d(1, 1, 1); }
- 30% { transform: scale3d(1.25, 0.75, 1); }
- 40% { transform: scale3d(0.75, 1.25, 1); }
- 50% { transform: scale3d(1.15, 0.85, 1); }
- 65% { transform: scale3d(0.95, 1.05, 1); }
- 75% { transform: scale3d(1.05, 0.95, 1); }
- to { transform: scale3d(1, 1, 1); }
-}
-
-@keyframes mfm-rainbow {
- 0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); }
- 100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); }
-}