Files
2026-05-15 23:22:58 +02:00

685 lines
20 KiB
CSS
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ============================================================
ApolloNvim – animations.css
Web: apollo-nvim.lukan.cz
All keyframes, scroll animations, stagger delays,
micro-interactions and loading screen transitions.
============================================================ */
/* ────────────────────────────────────────────────────────────
1. CORE KEYFRAMES
──────────────────────────────────────────────────────────── */
/* 1.1 fadeIn ─ simple opacity */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* 1.2 slideUp ─ rise + fade */
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(40px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 1.3 slideInLeft ─ enter from left */
@keyframes slideInLeft {
from {
opacity: 0;
transform: translateX(-60px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
/* 1.4 slideInRight ─ enter from right */
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(60px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
/* 1.5 float ─ gentle levitation for hero images / icons */
@keyframes float {
0%, 100% {
transform: translateY(0px);
}
33% {
transform: translateY(-10px);
}
66% {
transform: translateY(-6px);
}
}
/* 1.6 pulse-glow ─ pulsing purple box-shadow */
@keyframes pulse-glow {
0%, 100% {
box-shadow:
0 0 0 0 rgba(189, 147, 249, 0),
0 0 20px 2px rgba(189, 147, 249, 0.15);
}
50% {
box-shadow:
0 0 0 4px rgba(189, 147, 249, 0.08),
0 0 40px 8px rgba(189, 147, 249, 0.35);
}
}
/* 1.7 typing ─ blinking cursor caret */
@keyframes typing {
0%, 100% { border-right-color: rgba(189, 147, 249, 1); }
50% { border-right-color: transparent; }
}
/* Typewriter text reveal (pair with .typewriter class) */
@keyframes typewriter {
from { width: 0; }
to { width: 100%; }
}
/* 1.8 spin-slow ─ slow full rotation (used by loading logo) */
@keyframes spin-slow {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* 1.9 glitch ─ subtle horizontal glitch for headings */
@keyframes glitch {
0% { clip-path: inset(0 0 100% 0); transform: translate(0); }
10% { clip-path: inset(10% 0 60% 0); transform: translate(-3px, 1px); }
20% { clip-path: inset(60% 0 10% 0); transform: translate(3px, -1px); }
30% { clip-path: inset(30% 0 40% 0); transform: translate(-2px, 0); }
40% { clip-path: inset(0 0 80% 0); transform: translate(2px, 1px); }
50% { clip-path: inset(80% 0 0 0); transform: translate(-1px, -2px); }
60% { clip-path: inset(20% 0 50% 0); transform: translate(1px, 0); }
70% { clip-path: inset(50% 0 20% 0); transform: translate(-2px, 1px); }
80% { clip-path: inset(5% 0 70% 0); transform: translate(2px, -1px); }
90% { clip-path: inset(70% 0 5% 0); transform: translate(0, 2px); }
100% { clip-path: inset(0 0 0 0); transform: translate(0); }
}
/* 1.10 rocket-launch ─ rocket rises with shrinking trail */
@keyframes rocket-launch {
0% {
transform: translateY(0) scale(1);
opacity: 1;
filter: drop-shadow(0 8px 16px rgba(189, 147, 249, 0.6));
}
30% {
transform: translateY(-20px) scale(1.05);
filter: drop-shadow(0 16px 32px rgba(255, 121, 198, 0.7));
}
70% {
transform: translateY(-80px) scale(0.9);
opacity: 0.85;
filter: drop-shadow(0 4px 8px rgba(139, 233, 253, 0.5));
}
100% {
transform: translateY(-200px) scale(0.4);
opacity: 0;
filter: drop-shadow(0 0 0 transparent);
}
}
/* Rocket trail (::after pseudo) */
@keyframes rocket-trail {
0% { opacity: 0.8; transform: scaleY(1) scaleX(1); }
50% { opacity: 0.5; transform: scaleY(1.4) scaleX(0.7); }
100% { opacity: 0; transform: scaleY(2) scaleX(0.3); }
}
/* 1.11 star-twinkle ─ random opacity blink for star dots */
@keyframes star-twinkle {
0%, 100% { opacity: 0.15; transform: scale(0.85); }
25% { opacity: 0.9; transform: scale(1.1); }
50% { opacity: 0.4; transform: scale(0.95); }
75% { opacity: 1; transform: scale(1.05); }
}
/* 1.12 gradient-shift ─ animated gradient background */
@keyframes gradient-shift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* ────────────────────────────────────────────────────────────
2. ANIMATION UTILITY CLASSES
──────────────────────────────────────────────────────────── */
/* Basic named animations */
.anim-fade-in { animation: fadeIn 0.5s ease both; }
.anim-slide-up { animation: slideUp 0.55s ease both; }
.anim-slide-left { animation: slideInLeft 0.55s ease both; }
.anim-slide-right { animation: slideInRight 0.55s ease both; }
.anim-float { animation: float 4s ease-in-out infinite; }
.anim-pulse-glow { animation: pulse-glow 2.5s ease-in-out infinite; }
.anim-spin-slow { animation: spin-slow 20s linear infinite; }
.anim-star-twinkle { animation: star-twinkle 3s ease-in-out infinite; }
/* Gradient-shift background (set background-size: 200% 200% on element) */
.anim-gradient-bg {
background-size: 200% 200%;
animation: gradient-shift 6s ease infinite;
}
/* ────────────────────────────────────────────────────────────
3. TYPEWRITER EFFECT
──────────────────────────────────────────────────────────── */
.typewriter {
display: inline-block;
overflow: hidden;
white-space: nowrap;
border-right: 2px solid;
/* combine reveal + cursor blink */
animation:
typewriter 2s steps(30, end) both,
typing 0.7s step-end infinite;
}
/* Standalone cursor only (no text reveal) */
.cursor-blink {
display: inline-block;
width: 2px;
height: 1.1em;
background: #bd93f9;
vertical-align: text-bottom;
animation: typing 0.7s step-end infinite;
}
/* ────────────────────────────────────────────────────────────
4. GLITCH EFFECT
──────────────────────────────────────────────────────────── */
.glitch-text {
position: relative;
display: inline-block;
}
/* Glitch layers via pseudo-elements */
.glitch-text::before,
.glitch-text::after {
content: attr(data-text);
position: absolute;
inset: 0;
pointer-events: none;
}
.glitch-text::before {
color: #ff79c6;
animation: glitch 3.5s infinite linear alternate-reverse;
animation-delay: 0.1s;
opacity: 0.7;
}
.glitch-text::after {
color: #8be9fd;
animation: glitch 2.8s infinite linear alternate;
animation-delay: 0.25s;
opacity: 0.6;
}
/* On hover only */
.glitch-text--hover::before,
.glitch-text--hover::after {
animation-play-state: paused;
}
.glitch-text--hover:hover::before,
.glitch-text--hover:hover::after {
animation-play-state: running;
}
/* ────────────────────────────────────────────────────────────
5. ROCKET LAUNCH
──────────────────────────────────────────────────────────── */
.rocket {
display: inline-block;
position: relative;
transition: transform 0.3s ease;
}
.rocket--launch {
animation: rocket-launch 1.2s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
}
/* Trail element */
.rocket__trail {
position: absolute;
bottom: -8px;
left: 50%;
transform: translateX(-50%);
width: 6px;
height: 20px;
border-radius: 0 0 4px 4px;
background: linear-gradient(180deg, rgba(255, 121, 198, 0.8), transparent);
transform-origin: top center;
animation: rocket-trail 1.2s ease forwards;
opacity: 0;
}
.rocket--launch .rocket__trail {
opacity: 0.8;
}
/* ────────────────────────────────────────────────────────────
6. STAR FIELD
──────────────────────────────────────────────────────────── */
.star {
position: absolute;
width: 3px;
height: 3px;
background: #f8f8f2;
border-radius: 50%;
animation: star-twinkle var(--duration, 3s) ease-in-out infinite;
animation-delay: var(--delay, 0s);
}
.star--sm { width: 1.5px; height: 1.5px; }
.star--md { width: 2.5px; height: 2.5px; }
.star--lg { width: 4px; height: 4px; box-shadow: 0 0 4px 1px rgba(248, 248, 242, 0.4); }
/* ────────────────────────────────────────────────────────────
7. SCROLL-TRIGGERED ANIMATIONS
──────────────────────────────────────────────────────────── */
/* Base hidden state – applied by JS IntersectionObserver */
.animate-on-scroll {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
/* Revealed state – JS adds .visible class */
.animate-on-scroll.visible {
opacity: 1;
transform: translateY(0);
}
/* Directional variants */
.animate-on-scroll--left {
opacity: 0;
transform: translateX(-40px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.animate-on-scroll--left.visible {
opacity: 1;
transform: translateX(0);
}
.animate-on-scroll--right {
opacity: 0;
transform: translateX(40px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.animate-on-scroll--right.visible {
opacity: 1;
transform: translateX(0);
}
.animate-on-scroll--scale {
opacity: 0;
transform: scale(0.9);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.animate-on-scroll--scale.visible {
opacity: 1;
transform: scale(1);
}
/* ────────────────────────────────────────────────────────────
8. STAGGER DELAYS
──────────────────────────────────────────────────────────── */
.delay-1 { animation-delay: 100ms; transition-delay: 100ms; }
.delay-2 { animation-delay: 200ms; transition-delay: 200ms; }
.delay-3 { animation-delay: 300ms; transition-delay: 300ms; }
.delay-4 { animation-delay: 400ms; transition-delay: 400ms; }
.delay-5 { animation-delay: 500ms; transition-delay: 500ms; }
/* Extended stagger for large grids */
.delay-6 { animation-delay: 600ms; transition-delay: 600ms; }
.delay-7 { animation-delay: 700ms; transition-delay: 700ms; }
.delay-8 { animation-delay: 800ms; transition-delay: 800ms; }
/* ────────────────────────────────────────────────────────────
9. HOVER MICRO-ANIMATIONS
──────────────────────────────────────────────────────────── */
/* ── Buttons ── */
/* Primary button shine sweep */
.btn-primary {
position: relative;
overflow: hidden;
}
.btn-primary::after {
content: '';
position: absolute;
top: 0;
left: -75%;
width: 50%;
height: 100%;
background: linear-gradient(
120deg,
transparent 20%,
rgba(255, 255, 255, 0.22) 50%,
transparent 80%
);
transform: skewX(-20deg);
transition: left 0.55s ease;
pointer-events: none;
}
.btn-primary:hover::after {
left: 135%;
}
/* Secondary button border glow pulse */
.btn-secondary {
position: relative;
}
.btn-secondary::before {
content: '';
position: absolute;
inset: -1px;
border-radius: inherit;
background: linear-gradient(135deg, transparent, rgba(189, 147, 249, 0.3), transparent);
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
z-index: -1;
}
.btn-secondary:hover::before {
opacity: 1;
}
/* ── Links ── */
.link-underline {
position: relative;
text-decoration: none;
display: inline-block;
}
.link-underline::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 100%;
height: 1px;
background: linear-gradient(90deg, #bd93f9, #ff79c6);
transform: scaleX(0);
transform-origin: right;
transition: transform 0.35s ease;
}
.link-underline:hover::after {
transform: scaleX(1);
transform-origin: left;
}
/* ── Card tilt (subtle) ── */
.card-tilt {
transition: transform 0.3s ease, box-shadow 0.3s ease;
will-change: transform;
}
/* Managed by JS mousemove if desired – CSS fallback hover */
.card-tilt:hover {
transform: perspective(800px) rotateX(2deg) rotateY(-2deg) translateY(-4px);
}
/* ── Icon bounce ── */
.icon-bounce {
display: inline-block;
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.icon-bounce:hover {
transform: scale(1.25) translateY(-2px);
}
/* ── Icon spin on hover ── */
.icon-spin-hover {
transition: transform 0.4s ease;
display: inline-block;
}
.icon-spin-hover:hover {
transform: rotate(180deg);
}
/* ── Pill/badge pop ── */
.badge {
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
box-shadow 0.2s ease;
}
.badge:hover {
transform: scale(1.08) translateY(-1px);
box-shadow: 0 4px 12px rgba(189, 147, 249, 0.3);
}
/* ── Nav link underline (already in style.css, reinforced here) ── */
.navbar__link {
will-change: color;
}
/* ── Feature card shimmer border ── */
.feature-card {
background-clip: padding-box;
}
/* ────────────────────────────────────────────────────────────
10. ANIMATED GRADIENT HERO BACKGROUND
──────────────────────────────────────────────────────────── */
.hero-gradient-bg {
background: linear-gradient(
-45deg,
#0d0d1a,
#12122a,
#1a0a2e,
#0d1a2e
);
background-size: 400% 400%;
animation: gradient-shift 12s ease infinite;
}
/* ────────────────────────────────────────────────────────────
11. LOADING SCREEN – FADE OUT
──────────────────────────────────────────────────────────── */
@keyframes loading-fade-out {
0% { opacity: 1; transform: scale(1); }
80% { opacity: 1; transform: scale(1.02); }
100% { opacity: 0; transform: scale(0.98); }
}
/* Trigger by adding .is-hiding to .loading-screen via JS */
.loading-screen.is-hiding {
animation: loading-fade-out 0.55s ease forwards;
pointer-events: none;
}
/* Orbiting dots spinner (used inside loading screen) */
@keyframes orbit {
from { transform: rotate(0deg) translateX(28px) rotate(0deg); }
to { transform: rotate(360deg) translateX(28px) rotate(-360deg); }
}
.loader-orbit {
position: relative;
width: 60px;
height: 60px;
}
.loader-orbit__dot {
position: absolute;
top: 50%;
left: 50%;
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--purple, #bd93f9);
margin: -4px 0 0 -4px;
animation: orbit 1.4s linear infinite;
}
.loader-orbit__dot:nth-child(2) {
background: var(--pink, #ff79c6);
animation-delay: -0.46s;
}
.loader-orbit__dot:nth-child(3) {
background: var(--cyan, #8be9fd);
animation-delay: -0.93s;
}
/* ────────────────────────────────────────────────────────────
12. REVEAL ANIMATIONS FOR PAGE SECTIONS
──────────────────────────────────────────────────────────── */
/* Used by JS: section fades in as a block */
.section-reveal {
opacity: 0;
transition: opacity 0.8s ease, transform 0.8s ease;
transform: translateY(24px);
}
.section-reveal.in-view {
opacity: 1;
transform: translateY(0);
}
/* Hero content staggered entrance */
.hero__content > * {
opacity: 0;
animation: slideUp 0.65s ease both;
}
.hero__content > *:nth-child(1) { animation-delay: 0.1s; }
.hero__content > *:nth-child(2) { animation-delay: 0.25s; }
.hero__content > *:nth-child(3) { animation-delay: 0.4s; }
.hero__content > *:nth-child(4) { animation-delay: 0.55s; }
.hero__content > *:nth-child(5) { animation-delay: 0.7s; }
/* ────────────────────────────────────────────────────────────
13. PROGRESS / SKILL BARS
──────────────────────────────────────────────────────────── */
@keyframes bar-fill {
from { width: 0%; }
}
.progress-bar {
height: 4px;
background: var(--border, rgba(189, 147, 249, 0.2));
border-radius: 4px;
overflow: hidden;
}
.progress-bar__fill {
height: 100%;
border-radius: 4px;
background: linear-gradient(90deg, var(--purple, #bd93f9), var(--pink, #ff79c6));
width: var(--progress, 0%);
animation: bar-fill 1.2s cubic-bezier(0.22, 1, 0.36, 1) both;
animation-delay: var(--delay, 0.2s);
}
/* ────────────────────────────────────────────────────────────
14. NOTIFICATION / TOAST ENTRANCE
──────────────────────────────────────────────────────────── */
@keyframes toast-in {
from {
opacity: 0;
transform: translateX(calc(100% + 24px));
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes toast-out {
from {
opacity: 1;
transform: translateX(0);
}
to {
opacity: 0;
transform: translateX(calc(100% + 24px));
}
}
.toast {
animation: toast-in 0.35s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.toast.closing {
animation: toast-out 0.3s ease forwards;
}
/* ────────────────────────────────────────────────────────────
15. REDUCED MOTION OVERRIDES
──────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
/* Disable all custom animations */
.anim-fade-in,
.anim-slide-up,
.anim-slide-left,
.anim-slide-right,
.anim-float,
.anim-pulse-glow,
.anim-spin-slow,
.anim-star-twinkle,
.anim-gradient-bg,
.typewriter,
.cursor-blink,
.glitch-text::before,
.glitch-text::after,
.hero__content > *,
.rocket--launch,
.rocket__trail,
.loader-orbit__dot,
.loading-screen__bar-fill,
.loading-screen__logo,
.section-reveal,
.progress-bar__fill,
.toast,
.toast.closing {
animation: none !important;
transition: none !important;
}
/* Scroll-triggered: instantly reveal instead */
.animate-on-scroll,
.animate-on-scroll--left,
.animate-on-scroll--right,
.animate-on-scroll--scale {
opacity: 1 !important;
transform: none !important;
transition: none !important;
}
/* Hero items also visible immediately */
.hero__content > * {
opacity: 1 !important;
}
}