Files
marcandClaude Sonnet 5 61c4701115 Convert to Flask app with password-protected admin panel
Links now live in data/links.json instead of hardcoded HTML, editable
via /admin (add/rename/reorder/delete sections and links, per-link
color and half-width side-by-side layout). New pages can be added
without code changes. Docker image only needs rebuilding on code
changes now, not on content changes (data/ is volume-mounted).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 22:50:05 +02:00

348 lines
6.9 KiB
CSS

* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', sans-serif;
color: #f3f4f6;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 20px;
min-height: 100dvh;
overflow-x: hidden; /* verhindert horizontales Scrollen */
overflow-y: auto; /* nur vertikal scrollen, wenn nötig */
position: relative;
background: #0f172a;
}
.background-glow {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -1;
pointer-events: none;
background: radial-gradient(circle at 30% 30%, rgba(0, 200, 255, 0.35), transparent 60%),
radial-gradient(circle at 70% 60%, rgba(255, 50, 160, 0.35), transparent 60%),
radial-gradient(circle at 50% 80%, rgba(80, 255, 180, 0.3), transparent 60%);
background-size: 200% 200%;
animation: flowBackground 40s ease-in-out infinite;
}
@keyframes flowBackground {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
body::before {
content: '';
position: fixed; /* fixed statt absolute, bleibt innerhalb Viewport */
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
pointer-events: none;
background: radial-gradient(circle at 30% 30%, rgba(12, 75, 119, 0.534), transparent 70%),
radial-gradient(circle at 70% 60%, rgba(230, 86, 158, 0.35), transparent 70%),
radial-gradient(circle at 50% 80%, rgba(69, 218, 69, 0.3), transparent 70%);
animation: flowBackground 30s ease-in-out infinite;
}
.fade-in {
animation: fadeIn 1s ease-out forwards;
}
@keyframes fadeIn {
0% { opacity: 0; transform: translateY(10px); }
100% { opacity: 1; transform: translateY(0); }
}
@keyframes gradientShift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.profile-pic {
width: 120px;
height: 120px;
border-radius: 50%;
object-fit: cover;
border: 3px solid #4b5563;
margin-bottom: 20px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
filter: brightness(0.9) contrast(1.05);
border: 3px solid rgba(0, 0, 0, 0.3);
}
h1 {
font-size: 26px;
font-weight: 600;
margin-bottom: 8px;
text-align: center;
color: #eccb0ec5;
text-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
}
p.bio {
color: #9ca3af;
font-size: 14px;
text-align: center;
max-width: 320px;
}
p.bio2 {
color: #9ca3af;
font-size: 14px;
margin-bottom: 32px;
text-align: center;
max-width: 320px;
}
h2.section-title {
font-size: 18px;
margin-bottom: 10px;
color: #a5f3fc;
text-shadow: 0 0 6px rgba(0, 255, 255, 0.2);
border-bottom: 1px solid #1a3458cb;
padding-bottom: 6px;
width: 100%;
max-width: 320px;
text-align: left;
}
.section-title {
font-size: 18px;
margin-bottom: 10px;
color: #f9fafb;
border-bottom: 1px solid #374151;
padding-bottom: 6px;
width: 100%;
max-width: 320px;
text-align: left;
animation: pulseGlow 3s ease-in-out infinite;
}
@keyframes pulseGlow {
0%, 100% { text-shadow: 0 0 3px rgba(255, 255, 255, 0.1); }
50% { text-shadow: 0 0 10px rgba(255, 255, 255, 0.3); }
}
.links-grid {
display: flex;
flex-wrap: wrap;
gap: 10px;
width: 100%;
max-width: 320px;
margin-bottom: 14px;
}
.link {
display: block;
flex: 0 0 100%;
padding: 14px 24px;
background-color: rgba(255, 255, 255, 0.04);
color: #f3f4f6;
text-decoration: none;
border-radius: 10px;
border: 1px solid #4b5563;
transition: all 0.4s ease, box-shadow 0.6s ease;
font-weight: 600;
text-align: left;
}
/* Opt-in: two links next to each other instead of full width */
.link.half {
flex: 0 0 calc(50% - 5px);
padding: 14px 14px;
}
.link:hover {
background-color: rgba(255, 255, 255, 0.07); /* softer highlight */
color: #e0e7ff; /* gentle light blue tint */
transform: scale(1.04) translateZ(0);
box-shadow:
0 0 8px rgba(77, 180, 255, 0.3),
0 0 12px rgba(255, 105, 180, 0.25),
0 0 15px rgba(144, 238, 144, 0.2);
transition: background-color 0.3s ease, color 0.3s ease, transform 0.25s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.4s ease;
}
.blue-glow:hover {
box-shadow: 0 0 12px rgba(0, 200, 255, 0.3);
}
.pink-glow:hover {
box-shadow: 0 0 12px rgba(252, 111, 184, 0.527);
}
.green-glow:hover {
box-shadow: 0 0 12px rgba(144, 238, 144, 0.3);
}
.orange-glow:hover {
box-shadow: 0 0 12px rgba(197, 130, 29, 0.705);
}
.link-title {
font-size: 16px;
font-weight: 600;
}
.link-note {
font-size: 13px;
color: #9ca3af;
margin-top: 4px;
font-weight: 400;
}
footer {
margin-top: 60px;
font-size: 12px;
color: #cbd5e1;
text-shadow: 0 0 4px rgba(255, 255, 255, 0.1);
text-align: center;
}
.link-footer {
text-decoration: none;
color: #21e4d3;
font-size: 1,5em;
}
.link-footer:hover {
color: #24ffed; /* lighter, glowing version of the base color */
text-shadow: 0 0 6px rgba(255, 209, 136, 0.6);
}
.firefly {
position: absolute;
width: 6px;
height: 6px;
background: hsl(55, 100%, 75%);
border-radius: 50%;
box-shadow: 0 0 12px 5px hsla(55, 100%, 60%, 0.3);
animation:
fly 14s ease-in-out infinite,
blink 2.5s ease-in-out infinite alternate,
hueShift 10s ease-in-out infinite;
}
@keyframes fly {
0% {
transform: translate(0, 0) scale(0.9) rotate(0deg);
}
25% {
transform: translate(50px, -60px) scale(1) rotate(20deg);
}
50% {
transform: translate(-80px, 40px) scale(1.1) rotate(-20deg);
}
75% {
transform: translate(60px, -20px) scale(1) rotate(10deg);
}
100% {
transform: translate(0, 0) scale(0.9) rotate(0deg);
}
}
@keyframes hueShift {
0% { filter: hue-rotate(0deg); }
50% { filter: hue-rotate(60deg); }
100% { filter: hue-rotate(0deg); }
}
@keyframes blink {
0% { opacity: 0.2; }
50% { opacity: 1; }
100% { opacity: 0.3; }
}
/* Random positions and delays */
.firefly:nth-child(1) { top: 10%; left: 20%; animation-delay: 0s; }
.firefly:nth-child(2) { top: 40%; left: 70%; animation-delay: 2s; }
.firefly:nth-child(3) { top: 80%; left: 30%; animation-delay: 4s; }
.firefly:nth-child(4) { top: 25%; left: 85%; animation-delay: 6s; }
.firefly:nth-child(5) { top: 60%; left: 15%; animation-delay: 8s; }
.firefly:nth-child(6) { top: 90%; left: 50%; animation-delay: 10s; }
@keyframes fadeInUpSmooth {
0% {
opacity: 0;
transform: translateY(30px) scale(0.96);
filter: blur(4px);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
filter: blur(0);
}
}
.animated-link {
opacity: 0;
transform: translateY(30px) scale(0.96);
animation: fadeInUpSmooth 0.9s cubic-bezier(0.22, 1, 0.36, 1) forwards;
animation-delay: calc(0.15s * var(--i));
will-change: opacity, transform, filter;
}
@media (max-width: 480px) {
.profile-pic {
width: 100px;
height: 100px;
}
h1 {
font-size: 22px;
}
.link {
font-size: 14px;
padding: 12px 20px;
}
.link.half {
flex-basis: 100%;
}
}
@media (max-width: 768px) {
body {
padding: 24px 16px;
}
.link {
font-size: 15px;
padding: 12px 18px;
}
h1 {
font-size: 24px;
}
.profile-pic {
width: 110px;
height: 110px;
}
}