1
0
Fork 0

feat(campaigns): add one-shot glitch hover effects for official campaign cards

This commit is contained in:
Jason Fraley 2026-09-09 19:42:50 -04:00
parent 8668a59d06
commit a7c50c5fd0

View file

@ -841,3 +841,292 @@
.wiki-markdown .hljs-strong {
font-weight: 600;
}
/* Glitch hover effect for official campaign card titles: fires once (~1s) on hover, then reverts. */
.glitch-hover {
position: relative;
}
.glitch-ghost {
position: absolute;
inset: 0;
text-wrap: balance;
opacity: 0;
pointer-events: none;
}
.glitch-shard-a {
color: #22d3ee;
}
.glitch-shard-b {
color: #f43f5e;
}
.glitch-shard-c {
color: #ffffff;
}
.group:hover .glitch-hover {
animation: glitch-jitter 1s ease-out 1;
}
.group:hover .glitch-shard-a {
animation: glitch-shard-a 1s ease-out 1;
}
.group:hover .glitch-shard-b {
animation: glitch-shard-b 1s ease-out 1;
}
.group:hover .glitch-shard-c {
animation: glitch-shard-c 1s ease-out 1;
}
@keyframes glitch-jitter {
0% {
transform: translate(3px, -2px) skewX(2deg);
text-shadow:
-4px 0 rgba(34, 211, 238, 0.7),
4px 0 rgba(244, 63, 94, 0.7);
animation-timing-function: steps(1, end);
}
5% {
transform: translate(-3px, 2px) skewX(-2deg);
text-shadow:
3px 0 rgba(34, 211, 238, 0.7),
-3px 0 rgba(244, 63, 94, 0.7);
animation-timing-function: steps(1, end);
}
10% {
transform: translate(2px, -1px) skewX(1deg);
text-shadow:
-2px 0 rgba(34, 211, 238, 0.6),
2px 0 rgba(244, 63, 94, 0.6);
animation-timing-function: steps(1, end);
}
15% {
transform: translate(-1px, 1px);
text-shadow:
1px 0 rgba(34, 211, 238, 0.5),
-1px 0 rgba(244, 63, 94, 0.5);
animation-timing-function: ease-out;
}
25% {
transform: translate(0, 0) skewX(0deg);
text-shadow: none;
}
100% {
transform: translate(0, 0) skewX(0deg);
text-shadow: none;
}
}
@keyframes glitch-shard-a {
0% {
opacity: 0.9;
clip-path: polygon(0 0, 62% 0, 54% 34%, 0 34%);
transform: translate(-8px, -4px);
animation-timing-function: steps(1, end);
}
8% {
clip-path: polygon(6% 4%, 68% 0, 58% 38%, 0 30%);
transform: translate(8px, 4px);
animation-timing-function: steps(1, end);
}
16% {
opacity: 0.35;
clip-path: polygon(0 0, 50% 6%, 44% 30%, 0 38%);
transform: translate(-3px, -2px);
animation-timing-function: ease-out;
}
35% {
opacity: 0;
clip-path: polygon(0 0, 62% 0, 54% 34%, 0 34%);
transform: translate(-5px, -3px);
}
100% {
opacity: 0;
clip-path: polygon(0 0, 62% 0, 54% 34%, 0 34%);
transform: translate(-5px, -3px);
}
}
@keyframes glitch-shard-b {
0% {
opacity: 0.9;
clip-path: polygon(38% 66%, 100% 58%, 100% 100%, 30% 100%);
transform: translate(8px, 4px);
animation-timing-function: steps(1, end);
}
8% {
clip-path: polygon(32% 62%, 100% 66%, 100% 100%, 24% 96%);
transform: translate(-8px, -4px);
animation-timing-function: steps(1, end);
}
16% {
opacity: 0.35;
clip-path: polygon(50% 70%, 100% 62%, 100% 100%, 44% 100%);
transform: translate(3px, 2px);
animation-timing-function: ease-out;
}
35% {
opacity: 0;
clip-path: polygon(38% 66%, 100% 58%, 100% 100%, 30% 100%);
transform: translate(5px, 3px);
}
100% {
opacity: 0;
clip-path: polygon(38% 66%, 100% 58%, 100% 100%, 30% 100%);
transform: translate(5px, 3px);
}
}
@keyframes glitch-shard-c {
0% {
opacity: 0.95;
clip-path: polygon(8% 42%, 96% 38%, 88% 62%, 0 66%);
transform: translate(6px, -4px);
animation-timing-function: steps(1, end);
}
6% {
transform: translate(-6px, 4px);
animation-timing-function: steps(1, end);
}
12% {
clip-path: polygon(0 46%, 88% 40%, 96% 58%, 4% 62%);
transform: translate(4px, 2px);
animation-timing-function: steps(1, end);
}
20% {
transform: translate(-2px, -1px);
animation-timing-function: ease-out;
}
35% {
opacity: 0;
clip-path: polygon(8% 42%, 96% 38%, 88% 62%, 0 66%);
transform: translate(1px, 2px);
}
100% {
opacity: 0;
clip-path: polygon(8% 42%, 96% 38%, 88% 62%, 0 66%);
transform: translate(1px, 2px);
}
}
.group:hover .glitch-soft {
animation: glitch-soft 1s ease-out 1;
}
.group:hover .glitch-soft-late {
animation-delay: 0.1s;
}
@keyframes glitch-soft {
0% {
transform: translate(1px, -1px);
text-shadow:
1px 0 rgba(34, 211, 238, 0.45),
-1px 0 rgba(244, 63, 94, 0.45);
animation-timing-function: steps(1, end);
}
8% {
transform: translate(-1px, 1px);
text-shadow:
-1px 0 rgba(34, 211, 238, 0.45),
1px 0 rgba(244, 63, 94, 0.45);
animation-timing-function: steps(1, end);
}
16% {
transform: translate(1px, 1px);
animation-timing-function: ease-out;
}
30% {
transform: translate(0, 0);
text-shadow: none;
}
100% {
transform: translate(0, 0);
text-shadow: none;
}
}
.glitch-ghost-img {
opacity: 0;
}
.group:hover .glitch-ghost-img-a {
animation: glitch-img-band-a 2s ease-out 1;
}
.group:hover .glitch-ghost-img-b {
animation: glitch-img-band-b 2s ease-out 1;
}
@keyframes glitch-img-band-a {
0% {
opacity: 0.45;
clip-path: inset(0 0 55% 0);
transform: translate(-4px, 0);
animation-timing-function: steps(1, end);
}
6% {
clip-path: inset(5% 0 60% 0);
transform: translate(4px, 2px);
animation-timing-function: steps(1, end);
}
12% {
opacity: 0.35;
clip-path: inset(10% 0 62% 0);
transform: translate(-2px, 0);
}
100% {
opacity: 0;
clip-path: inset(0 0 55% 0);
transform: translate(0, 0);
}
}
@keyframes glitch-img-band-b {
0% {
opacity: 0.45;
clip-path: inset(45% 0 0 0);
transform: translate(4px, 0);
animation-timing-function: steps(1, end);
}
6% {
clip-path: inset(40% 0 5% 0);
transform: translate(-4px, -2px);
animation-timing-function: steps(1, end);
}
12% {
opacity: 0.35;
clip-path: inset(38% 0 10% 0);
transform: translate(2px, 0);
}
100% {
opacity: 0;
clip-path: inset(45% 0 0 0);
transform: translate(0, 0);
}
}
@media (prefers-reduced-motion: reduce) {
.group:hover .glitch-hover {
animation: none;
}
.group:hover .glitch-ghost {
animation: none;
opacity: 0;
}
.group:hover .glitch-soft {
animation: none;
}
.group:hover .glitch-ghost-img {
animation: none;
opacity: 0;
}
}