1511 lines
46 KiB
HTML
1511 lines
46 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>noctura.dev | Portfolio für Web, Systeme und Infrastruktur</title>
|
|
<meta name="description" content="Persönliches Portfolio für Frontend, Backend, Linux, Hosting und saubere technische Umsetzungen auf noctura.dev." />
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;500;600;700;800&family=DM+Mono:ital,wght@0,300;0,400;1,300&display=swap" rel="stylesheet" />
|
|
<style>
|
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
|
|
:root {
|
|
--bg: #05070d;
|
|
--bg2: #0b1020;
|
|
--bg3: #12192f;
|
|
--bg4: #1a2443;
|
|
--surface: rgba(255,255,255,0.045);
|
|
--surface-strong: rgba(17,22,40,0.88);
|
|
--surface-soft: rgba(255,255,255,0.025);
|
|
--border: rgba(255,255,255,0.08);
|
|
--border-hover: rgba(255,255,255,0.18);
|
|
--text: #eef2ff;
|
|
--muted: #97a1c3;
|
|
--accent: #82a0ff;
|
|
--accent2: #67e8c8;
|
|
--accent3: #ff9e7a;
|
|
--accent4: #c8d3ff;
|
|
--glow: rgba(130,160,255,0.14);
|
|
--shadow: 0 24px 80px rgba(2,6,23,0.45);
|
|
--font: 'Syne', sans-serif;
|
|
--mono: 'DM Mono', monospace;
|
|
}
|
|
|
|
html { scroll-behavior: smooth; }
|
|
|
|
body {
|
|
background:
|
|
radial-gradient(circle at top left, rgba(130,160,255,0.12), transparent 30%),
|
|
radial-gradient(circle at 85% 20%, rgba(103,232,200,0.08), transparent 24%),
|
|
linear-gradient(180deg, #05070d 0%, #080c16 28%, #0a1020 100%);
|
|
color: var(--text);
|
|
font-family: var(--font);
|
|
line-height: 1.6;
|
|
min-height: 100vh;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
body::before {
|
|
content: '';
|
|
position: fixed;
|
|
inset: 0;
|
|
background-image:
|
|
linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px),
|
|
linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
|
|
background-size: 80px 80px;
|
|
mask-image: radial-gradient(circle at center, rgba(0,0,0,0.72), transparent 88%);
|
|
pointer-events: none;
|
|
opacity: 0.18;
|
|
z-index: 0;
|
|
}
|
|
|
|
::selection {
|
|
background: rgba(130,160,255,0.28);
|
|
color: #fff;
|
|
}
|
|
|
|
a { color: inherit; }
|
|
|
|
a:focus-visible,
|
|
button:focus-visible {
|
|
outline: 2px solid var(--accent2);
|
|
outline-offset: 4px;
|
|
}
|
|
|
|
#stars {
|
|
position: fixed;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
}
|
|
|
|
.nebula {
|
|
position: fixed;
|
|
border-radius: 50%;
|
|
filter: blur(140px);
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
}
|
|
|
|
.nebula-1 { width: 620px; height: 620px; background: radial-gradient(circle, rgba(130,160,255,0.1) 0%, transparent 72%); top: -120px; left: -140px; }
|
|
.nebula-2 { width: 520px; height: 520px; background: radial-gradient(circle, rgba(103,232,200,0.08) 0%, transparent 72%); bottom: 140px; right: -40px; }
|
|
.nebula-3 { width: 420px; height: 420px; background: radial-gradient(circle, rgba(255,158,122,0.06) 0%, transparent 72%); top: 44%; left: 42%; }
|
|
|
|
.wrapper {
|
|
position: relative;
|
|
z-index: 1;
|
|
max-width: 1180px;
|
|
margin: 0 auto;
|
|
padding: 0 2rem;
|
|
}
|
|
|
|
nav {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 100;
|
|
padding: 1rem 0;
|
|
backdrop-filter: blur(22px);
|
|
border-bottom: 1px solid var(--border);
|
|
background: rgba(5,7,13,0.62);
|
|
}
|
|
|
|
.nav-inner {
|
|
max-width: 1180px;
|
|
margin: 0 auto;
|
|
padding: 0 2rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.nav-logo {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
font-size: 0.95rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.08em;
|
|
color: var(--text);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.nav-logo::before {
|
|
content: '';
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg, var(--accent2), var(--accent));
|
|
box-shadow: 0 0 18px rgba(103,232,200,0.4);
|
|
}
|
|
|
|
.nav-logo span { color: var(--accent); }
|
|
|
|
.nav-links {
|
|
display: flex;
|
|
gap: 1.5rem;
|
|
list-style: none;
|
|
padding: 0.5rem 0.85rem;
|
|
border: 1px solid var(--border);
|
|
border-radius: 999px;
|
|
background: rgba(255,255,255,0.025);
|
|
}
|
|
|
|
.nav-links a {
|
|
font-size: 0.74rem;
|
|
font-weight: 500;
|
|
letter-spacing: 0.1em;
|
|
text-transform: uppercase;
|
|
color: var(--muted);
|
|
text-decoration: none;
|
|
transition: color 0.2s, transform 0.2s;
|
|
}
|
|
|
|
.nav-links a:hover {
|
|
color: var(--text);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.hero {
|
|
padding: 164px 0 118px;
|
|
position: relative;
|
|
}
|
|
|
|
.hero-grid {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1.2fr) minmax(320px, 0.8fr);
|
|
gap: 1.5rem;
|
|
align-items: start;
|
|
}
|
|
|
|
.hero-copy {
|
|
position: relative;
|
|
padding-right: 1rem;
|
|
}
|
|
|
|
.hero-tag {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-family: var(--mono);
|
|
font-size: 0.75rem;
|
|
color: var(--accent2);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
margin-bottom: 1.2rem;
|
|
opacity: 0;
|
|
animation: fadeUp 0.6s ease forwards 0.2s;
|
|
}
|
|
|
|
.hero-tag::before {
|
|
content: '';
|
|
display: inline-block;
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
background: var(--accent2);
|
|
box-shadow: 0 0 8px var(--accent2);
|
|
animation: pulse 2s ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%,100% { opacity: 1; transform: scale(1); }
|
|
50% { opacity: 0.6; transform: scale(0.8); }
|
|
}
|
|
|
|
.hero h1 {
|
|
max-width: 820px;
|
|
font-size: clamp(3.25rem, 8vw, 5.4rem);
|
|
font-weight: 800;
|
|
line-height: 0.92;
|
|
letter-spacing: -0.055em;
|
|
margin-bottom: 1.4rem;
|
|
opacity: 0;
|
|
animation: fadeUp 0.6s ease forwards 0.35s;
|
|
text-wrap: balance;
|
|
}
|
|
|
|
.hero h1 .line2 {
|
|
display: block;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.hero h1 .line3 {
|
|
display: block;
|
|
color: var(--accent4);
|
|
text-shadow: 0 0 32px rgba(130,160,255,0.16);
|
|
}
|
|
|
|
.hero-desc {
|
|
max-width: 690px;
|
|
font-size: 1.02rem;
|
|
color: var(--muted);
|
|
line-height: 1.85;
|
|
margin-bottom: 2.2rem;
|
|
opacity: 0;
|
|
animation: fadeUp 0.6s ease forwards 0.5s;
|
|
}
|
|
|
|
.hero-desc strong {
|
|
color: var(--text);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.hero-actions {
|
|
display: flex;
|
|
gap: 1rem;
|
|
flex-wrap: wrap;
|
|
margin-bottom: 2.6rem;
|
|
opacity: 0;
|
|
animation: fadeUp 0.6s ease forwards 0.65s;
|
|
}
|
|
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 8px;
|
|
padding: 0.9rem 1.35rem;
|
|
border-radius: 12px;
|
|
font-family: var(--font);
|
|
font-size: 0.84rem;
|
|
font-weight: 600;
|
|
letter-spacing: 0.01em;
|
|
text-decoration: none;
|
|
transition: transform 0.2s, border-color 0.2s, background 0.2s, color 0.2s, box-shadow 0.2s;
|
|
cursor: pointer;
|
|
border: none;
|
|
}
|
|
|
|
.btn-primary {
|
|
background: linear-gradient(135deg, #7094ff, #88a8ff);
|
|
color: #fff;
|
|
box-shadow: 0 16px 40px rgba(112,148,255,0.24);
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 20px 44px rgba(112,148,255,0.32);
|
|
}
|
|
|
|
.btn-outline {
|
|
background: rgba(255,255,255,0.025);
|
|
color: var(--text);
|
|
border: 1px solid var(--border-hover);
|
|
}
|
|
|
|
.btn-outline:hover {
|
|
border-color: var(--accent);
|
|
color: var(--accent4);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.hero-strip {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
gap: 1rem;
|
|
max-width: 900px;
|
|
opacity: 0;
|
|
animation: fadeUp 0.6s ease forwards 0.8s;
|
|
}
|
|
|
|
.hero-metric {
|
|
padding: 1.1rem 1.15rem;
|
|
background: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.03));
|
|
border: 1px solid var(--border);
|
|
border-radius: 18px;
|
|
backdrop-filter: blur(18px);
|
|
box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
|
|
}
|
|
|
|
.hero-metric-label {
|
|
font-family: var(--mono);
|
|
font-size: 0.62rem;
|
|
letter-spacing: 0.14em;
|
|
text-transform: uppercase;
|
|
color: var(--accent2);
|
|
margin-bottom: 0.45rem;
|
|
}
|
|
|
|
.hero-metric-value {
|
|
font-size: 1rem;
|
|
font-weight: 700;
|
|
letter-spacing: -0.02em;
|
|
margin-bottom: 0.2rem;
|
|
}
|
|
|
|
.hero-metric-copy {
|
|
font-size: 0.78rem;
|
|
color: var(--muted);
|
|
line-height: 1.55;
|
|
}
|
|
|
|
.hero-panel {
|
|
opacity: 0;
|
|
animation: fadeUp 0.6s ease forwards 0.9s;
|
|
}
|
|
|
|
.presence-card {
|
|
position: relative;
|
|
overflow: hidden;
|
|
background: linear-gradient(180deg, rgba(14,19,36,0.95), rgba(10,13,25,0.92));
|
|
border: 1px solid rgba(255,255,255,0.08);
|
|
border-radius: 26px;
|
|
padding: 1.35rem;
|
|
box-shadow: var(--shadow);
|
|
}
|
|
|
|
.presence-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
background: linear-gradient(135deg, rgba(130,160,255,0.12), transparent 40%, rgba(103,232,200,0.08));
|
|
pointer-events: none;
|
|
}
|
|
|
|
.presence-top,
|
|
.presence-row,
|
|
.availability-list li,
|
|
.project-meta,
|
|
.project-foot {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.presence-top {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.presence-title {
|
|
font-size: 1.1rem;
|
|
font-weight: 700;
|
|
letter-spacing: -0.02em;
|
|
}
|
|
|
|
.presence-subtitle {
|
|
color: var(--muted);
|
|
font-size: 0.82rem;
|
|
}
|
|
|
|
.presence-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.45rem;
|
|
padding: 0.45rem 0.75rem;
|
|
border-radius: 999px;
|
|
background: rgba(103,232,200,0.12);
|
|
color: var(--accent2);
|
|
font-family: var(--mono);
|
|
font-size: 0.68rem;
|
|
letter-spacing: 0.06em;
|
|
text-transform: uppercase;
|
|
border: 1px solid rgba(103,232,200,0.22);
|
|
}
|
|
|
|
.presence-badge::before {
|
|
content: '';
|
|
width: 7px;
|
|
height: 7px;
|
|
border-radius: 50%;
|
|
background: var(--accent2);
|
|
box-shadow: 0 0 10px rgba(103,232,200,0.55);
|
|
}
|
|
|
|
.presence-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
gap: 0.9rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.presence-row {
|
|
padding: 0.95rem;
|
|
border-radius: 18px;
|
|
background: rgba(255,255,255,0.03);
|
|
border: 1px solid rgba(255,255,255,0.06);
|
|
}
|
|
|
|
.presence-label {
|
|
display: block;
|
|
font-family: var(--mono);
|
|
font-size: 0.65rem;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
color: var(--accent2);
|
|
margin-bottom: 0.45rem;
|
|
}
|
|
|
|
.presence-value {
|
|
font-size: 0.96rem;
|
|
font-weight: 700;
|
|
letter-spacing: -0.02em;
|
|
margin-bottom: 0.2rem;
|
|
}
|
|
|
|
.presence-copy {
|
|
font-size: 0.78rem;
|
|
color: var(--muted);
|
|
line-height: 1.55;
|
|
}
|
|
|
|
.availability-list {
|
|
list-style: none;
|
|
display: grid;
|
|
gap: 0.75rem;
|
|
padding-top: 0.2rem;
|
|
}
|
|
|
|
.availability-list li {
|
|
padding: 0.85rem 0.95rem;
|
|
border-radius: 16px;
|
|
background: rgba(255,255,255,0.025);
|
|
border: 1px solid rgba(255,255,255,0.055);
|
|
color: var(--muted);
|
|
font-size: 0.82rem;
|
|
}
|
|
|
|
.availability-list strong {
|
|
display: block;
|
|
color: var(--text);
|
|
font-size: 0.82rem;
|
|
margin-bottom: 0.15rem;
|
|
}
|
|
|
|
section { padding: 88px 0; }
|
|
|
|
.section-label {
|
|
font-family: var(--mono);
|
|
font-size: 0.7rem;
|
|
letter-spacing: 0.15em;
|
|
text-transform: uppercase;
|
|
color: var(--accent2);
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: clamp(1.8rem, 3vw, 2.65rem);
|
|
font-weight: 700;
|
|
letter-spacing: -0.03em;
|
|
margin-bottom: 0.65rem;
|
|
text-wrap: balance;
|
|
}
|
|
|
|
.section-subtitle {
|
|
color: var(--muted);
|
|
font-size: 1rem;
|
|
margin-bottom: 3rem;
|
|
max-width: 720px;
|
|
}
|
|
|
|
.section-divider {
|
|
height: 1px;
|
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.05) 18%, rgba(255,255,255,0.1) 50%, rgba(255,255,255,0.05) 82%, transparent);
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.intro-panel {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1.15fr) minmax(320px, 0.85fr);
|
|
gap: 1rem;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.intro-copy,
|
|
.intro-notes {
|
|
background: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.03));
|
|
border: 1px solid var(--border);
|
|
border-radius: 24px;
|
|
padding: 1.75rem;
|
|
box-shadow: inset 0 1px 0 rgba(255,255,255,0.03);
|
|
}
|
|
|
|
.intro-copy p {
|
|
color: var(--muted);
|
|
font-size: 0.98rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.intro-copy p:last-child { margin-bottom: 0; }
|
|
|
|
.intro-notes {
|
|
background: linear-gradient(180deg, rgba(26,36,67,0.82), rgba(10,13,25,0.92));
|
|
}
|
|
|
|
.hero-card-label {
|
|
font-family: var(--mono);
|
|
font-size: 0.68rem;
|
|
letter-spacing: 0.14em;
|
|
text-transform: uppercase;
|
|
color: var(--accent2);
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.note-list {
|
|
display: grid;
|
|
gap: 0.85rem;
|
|
list-style: none;
|
|
}
|
|
|
|
.note-list li {
|
|
padding-left: 1rem;
|
|
position: relative;
|
|
color: var(--muted);
|
|
font-size: 0.88rem;
|
|
}
|
|
|
|
.note-list li::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0.6rem;
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
background: var(--accent3);
|
|
box-shadow: 0 0 10px rgba(247,136,106,0.5);
|
|
}
|
|
|
|
.principles-grid {
|
|
margin-top: 1rem;
|
|
display: grid;
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
|
|
.principle-card {
|
|
padding: 1.2rem;
|
|
border-radius: 18px;
|
|
background: var(--surface-soft);
|
|
border: 1px solid var(--border);
|
|
}
|
|
|
|
.principle-index {
|
|
font-family: var(--mono);
|
|
font-size: 0.68rem;
|
|
color: var(--accent2);
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
margin-bottom: 0.6rem;
|
|
}
|
|
|
|
.principle-title {
|
|
font-size: 0.98rem;
|
|
font-weight: 700;
|
|
margin-bottom: 0.45rem;
|
|
}
|
|
|
|
.principle-copy {
|
|
font-size: 0.83rem;
|
|
color: var(--muted);
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.skills-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
gap: 1px;
|
|
background: rgba(255,255,255,0.06);
|
|
border: 1px solid var(--border);
|
|
border-radius: 24px;
|
|
overflow: hidden;
|
|
box-shadow: var(--shadow);
|
|
}
|
|
|
|
.skill-card {
|
|
background: rgba(7,10,18,0.98);
|
|
padding: 2rem 1.85rem;
|
|
transition: background 0.25s, transform 0.25s;
|
|
position: relative;
|
|
}
|
|
|
|
.skill-card:hover {
|
|
background: var(--bg3);
|
|
transform: translateY(-3px);
|
|
}
|
|
|
|
.skill-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 3px;
|
|
opacity: 0;
|
|
transition: opacity 0.3s;
|
|
}
|
|
|
|
.skill-card:hover::before { opacity: 1; }
|
|
.skill-card.purple::before { background: linear-gradient(90deg, var(--accent), transparent); }
|
|
.skill-card.teal::before { background: linear-gradient(90deg, var(--accent2), transparent); }
|
|
.skill-card.orange::before { background: linear-gradient(90deg, var(--accent3), transparent); }
|
|
|
|
.skill-icon {
|
|
font-size: 1.6rem;
|
|
margin-bottom: 1rem;
|
|
display: block;
|
|
}
|
|
|
|
.skill-name {
|
|
font-size: 1rem;
|
|
font-weight: 700;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.skill-desc {
|
|
font-size: 0.84rem;
|
|
color: var(--muted);
|
|
line-height: 1.6;
|
|
margin-bottom: 1.35rem;
|
|
}
|
|
|
|
.skill-tags {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 6px;
|
|
}
|
|
|
|
.tag {
|
|
font-family: var(--mono);
|
|
font-size: 0.67rem;
|
|
padding: 3px 8px;
|
|
border-radius: 4px;
|
|
border: 1px solid var(--border);
|
|
color: var(--muted);
|
|
letter-spacing: 0.03em;
|
|
}
|
|
|
|
.tag.purple { border-color: rgba(130,160,255,0.3); color: rgba(130,160,255,0.85); background: rgba(130,160,255,0.08); }
|
|
.tag.teal { border-color: rgba(103,232,200,0.3); color: rgba(103,232,200,0.85); background: rgba(103,232,200,0.08); }
|
|
.tag.orange { border-color: rgba(255,158,122,0.3); color: rgba(255,158,122,0.85); background: rgba(255,158,122,0.08); }
|
|
|
|
.projects-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
|
|
.project-card {
|
|
position: relative;
|
|
overflow: hidden;
|
|
background: linear-gradient(180deg, rgba(16,21,38,0.94), rgba(9,12,23,0.96));
|
|
border: 1px solid var(--border);
|
|
border-radius: 24px;
|
|
padding: 1.55rem;
|
|
transition: border-color 0.25s, transform 0.22s, box-shadow 0.22s;
|
|
text-decoration: none;
|
|
color: var(--text);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.95rem;
|
|
min-height: 100%;
|
|
}
|
|
|
|
.project-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
background: linear-gradient(135deg, rgba(130,160,255,0.12), transparent 46%, rgba(103,232,200,0.06));
|
|
opacity: 0;
|
|
transition: opacity 0.24s;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.project-card:hover {
|
|
border-color: var(--border-hover);
|
|
transform: translateY(-4px);
|
|
box-shadow: var(--shadow);
|
|
}
|
|
|
|
.project-card:hover::before { opacity: 1; }
|
|
|
|
.project-header {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.project-icon {
|
|
width: 48px;
|
|
height: 48px;
|
|
display: inline-grid;
|
|
place-items: center;
|
|
border-radius: 14px;
|
|
background: rgba(255,255,255,0.04);
|
|
border: 1px solid rgba(255,255,255,0.06);
|
|
font-size: 1.1rem;
|
|
line-height: 1;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.project-arrow {
|
|
color: var(--muted);
|
|
font-size: 1rem;
|
|
transition: color 0.2s, transform 0.2s;
|
|
display: inline-block;
|
|
}
|
|
|
|
.project-card:hover .project-arrow {
|
|
color: var(--accent);
|
|
transform: translate(2px,-2px);
|
|
}
|
|
|
|
.project-eyebrow {
|
|
font-family: var(--mono);
|
|
font-size: 0.66rem;
|
|
color: var(--accent2);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
margin-bottom: 0.15rem;
|
|
}
|
|
|
|
.project-name {
|
|
font-size: 1.1rem;
|
|
font-weight: 700;
|
|
letter-spacing: -0.01em;
|
|
}
|
|
|
|
.project-desc {
|
|
font-size: 0.85rem;
|
|
color: var(--muted);
|
|
line-height: 1.7;
|
|
flex: 1;
|
|
}
|
|
|
|
.project-meta {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.project-pill {
|
|
font-family: var(--mono);
|
|
font-size: 0.67rem;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
padding: 0.38rem 0.55rem;
|
|
border-radius: 999px;
|
|
background: rgba(255,255,255,0.045);
|
|
border: 1px solid rgba(255,255,255,0.08);
|
|
color: var(--accent4);
|
|
}
|
|
|
|
.project-points {
|
|
list-style: none;
|
|
display: grid;
|
|
gap: 0.6rem;
|
|
}
|
|
|
|
.project-points li {
|
|
position: relative;
|
|
padding-left: 1rem;
|
|
color: var(--muted);
|
|
font-size: 0.81rem;
|
|
line-height: 1.55;
|
|
}
|
|
|
|
.project-points li::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0.58rem;
|
|
left: 0;
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
background: var(--accent2);
|
|
box-shadow: 0 0 12px rgba(103,232,200,0.5);
|
|
}
|
|
|
|
.project-foot {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
margin-top: auto;
|
|
padding-top: 0.25rem;
|
|
}
|
|
|
|
.project-status {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
font-family: var(--mono);
|
|
font-size: 0.65rem;
|
|
letter-spacing: 0.04em;
|
|
}
|
|
|
|
.status-dot {
|
|
width: 5px;
|
|
height: 5px;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.status-live { background: #4ade80; box-shadow: 0 0 6px #4ade80; }
|
|
.status-wip { background: #facc15; box-shadow: 0 0 6px #facc15; }
|
|
.status-planned { background: var(--muted); }
|
|
|
|
.project-linktext {
|
|
font-family: var(--mono);
|
|
font-size: 0.72rem;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
color: var(--accent4);
|
|
}
|
|
|
|
.proof-band {
|
|
margin-top: 1.2rem;
|
|
padding: 1.2rem 1.3rem;
|
|
border-radius: 20px;
|
|
background: linear-gradient(180deg, rgba(255,255,255,0.045), rgba(255,255,255,0.025));
|
|
border: 1px solid var(--border);
|
|
display: grid;
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
|
|
.proof-item { padding-right: 0.5rem; }
|
|
|
|
.proof-label {
|
|
font-family: var(--mono);
|
|
font-size: 0.66rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.12em;
|
|
color: var(--accent2);
|
|
margin-bottom: 0.45rem;
|
|
}
|
|
|
|
.proof-copy {
|
|
font-size: 0.84rem;
|
|
color: var(--muted);
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.snapshot-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
|
|
.snapshot-card {
|
|
background: linear-gradient(180deg, rgba(255,255,255,0.045), rgba(255,255,255,0.025));
|
|
border: 1px solid var(--border);
|
|
border-radius: 18px;
|
|
padding: 1.2rem 1.25rem;
|
|
min-height: 172px;
|
|
transition: border-color 0.2s, background 0.2s, transform 0.2s;
|
|
}
|
|
|
|
.snapshot-card:hover {
|
|
border-color: var(--border-hover);
|
|
background: rgba(255,255,255,0.06);
|
|
transform: translateY(-3px);
|
|
}
|
|
|
|
.snapshot-kicker {
|
|
font-family: var(--mono);
|
|
font-size: 0.66rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.12em;
|
|
color: var(--accent2);
|
|
margin-bottom: 0.65rem;
|
|
}
|
|
|
|
.snapshot-value {
|
|
font-size: 1.45rem;
|
|
font-weight: 700;
|
|
letter-spacing: -0.03em;
|
|
margin-bottom: 0.4rem;
|
|
}
|
|
|
|
.snapshot-desc {
|
|
font-size: 0.83rem;
|
|
color: var(--muted);
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.contact-box {
|
|
position: relative;
|
|
overflow: hidden;
|
|
background: linear-gradient(180deg, rgba(20,27,50,0.95), rgba(9,12,23,0.94));
|
|
border: 1px solid var(--border);
|
|
border-radius: 28px;
|
|
padding: 3.25rem;
|
|
text-align: center;
|
|
box-shadow: var(--shadow);
|
|
}
|
|
|
|
.contact-box::before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
background: radial-gradient(circle at top, rgba(130,160,255,0.2), transparent 42%);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.contact-box > * {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.contact-box h2 {
|
|
font-size: clamp(2rem, 4vw, 2.8rem);
|
|
font-weight: 800;
|
|
margin-bottom: 0.6rem;
|
|
letter-spacing: -0.03em;
|
|
}
|
|
|
|
.contact-box p {
|
|
color: var(--muted);
|
|
max-width: 620px;
|
|
margin: 0 auto 2rem;
|
|
}
|
|
|
|
footer {
|
|
border-top: 1px solid var(--border);
|
|
padding: 2rem 0;
|
|
font-family: var(--mono);
|
|
font-size: 0.7rem;
|
|
color: var(--muted);
|
|
}
|
|
|
|
.footer-inner {
|
|
max-width: 1180px;
|
|
margin: 0 auto;
|
|
padding: 0 2rem;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 1rem;
|
|
}
|
|
|
|
@keyframes fadeUp {
|
|
from { opacity: 0; transform: translateY(20px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.reveal {
|
|
opacity: 0;
|
|
transform: translateY(24px);
|
|
transition: opacity 0.6s ease, transform 0.6s ease;
|
|
}
|
|
|
|
.reveal.visible {
|
|
opacity: 1;
|
|
transform: none;
|
|
}
|
|
|
|
@media (max-width: 1040px) {
|
|
.hero-grid,
|
|
.intro-panel,
|
|
.projects-grid,
|
|
.skills-grid,
|
|
.snapshot-grid,
|
|
.principles-grid,
|
|
.proof-band {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.hero-copy { padding-right: 0; }
|
|
|
|
.presence-grid,
|
|
.hero-strip {
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
}
|
|
}
|
|
|
|
@media (max-width: 720px) {
|
|
.nav-links { display: none; }
|
|
|
|
.wrapper,
|
|
.nav-inner,
|
|
.footer-inner {
|
|
padding: 0 1.25rem;
|
|
}
|
|
|
|
.hero { padding: 124px 0 72px; }
|
|
section { padding: 72px 0; }
|
|
|
|
.hero-strip,
|
|
.presence-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.contact-box { padding: 2.25rem 1.35rem; }
|
|
.project-foot { align-items: flex-start; flex-direction: column; }
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
html { scroll-behavior: auto; }
|
|
|
|
*, *::before, *::after {
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
}
|
|
|
|
.reveal,
|
|
.hero-tag,
|
|
.hero h1,
|
|
.hero-desc,
|
|
.hero-actions,
|
|
.hero-strip,
|
|
.hero-panel {
|
|
opacity: 1;
|
|
transform: none;
|
|
animation: none;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<canvas id="stars"></canvas>
|
|
<div class="nebula nebula-1"></div>
|
|
<div class="nebula nebula-2"></div>
|
|
<div class="nebula nebula-3"></div>
|
|
|
|
<nav>
|
|
<div class="nav-inner">
|
|
<a href="#" class="nav-logo">noctura<span>.dev</span></a>
|
|
<ul class="nav-links">
|
|
<li><a href="#about">Über mich</a></li>
|
|
<li><a href="#skills">Skills</a></li>
|
|
<li><a href="#projects">Projekte</a></li>
|
|
<li><a href="#snapshot">Profil</a></li>
|
|
<li><a href="#contact">Kontakt</a></li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="wrapper">
|
|
<section class="hero">
|
|
<div class="hero-grid">
|
|
<div class="hero-copy">
|
|
<div class="hero-tag">Persönliches Portfolio / Web, Systeme, Infrastruktur</div>
|
|
<h1>
|
|
Interfaces mit Haltung.
|
|
<span class="line2">Systeme mit Substanz.</span>
|
|
<span class="line3">Umsetzungen, die man versteht.</span>
|
|
</h1>
|
|
<p class="hero-desc">
|
|
Ich baue digitale Arbeiten, die nicht bei schöner Oberfläche aufhören. Mich interessieren
|
|
<strong>klare Nutzerführung, saubere technische Entscheidungen und Betrieb ohne Blackbox</strong>.
|
|
Deshalb denke ich Frontend, Backend, Linux und Deployment als zusammenhängendes System.
|
|
</p>
|
|
<div class="hero-actions">
|
|
<a href="#projects" class="btn btn-primary">Arbeiten ansehen</a>
|
|
<a href="#contact" class="btn btn-outline">Kontakt aufnehmen</a>
|
|
</div>
|
|
<div class="hero-strip">
|
|
<div class="hero-metric">
|
|
<div class="hero-metric-label">Fokus</div>
|
|
<div class="hero-metric-value">Vom Interface bis zum Betrieb</div>
|
|
<p class="hero-metric-copy">Nicht nur Screens gestalten, sondern komplette technische Linien sauber zu Ende führen.</p>
|
|
</div>
|
|
<div class="hero-metric">
|
|
<div class="hero-metric-label">Arbeitsweise</div>
|
|
<div class="hero-metric-value">Präzise, direkt, nachvollziehbar</div>
|
|
<p class="hero-metric-copy">Ich bevorzuge klare Entscheidungen, echte Umsetzungen und Dokumentation, die auch später noch Sinn ergibt.</p>
|
|
</div>
|
|
<div class="hero-metric">
|
|
<div class="hero-metric-label">Stack</div>
|
|
<div class="hero-metric-value">HTML, CSS, JavaScript, Linux, Docker</div>
|
|
<p class="hero-metric-copy">Breit genug für komplette Projekte, fokussiert genug für gute Details und wartbare Ergebnisse.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<aside class="hero-panel">
|
|
<div class="presence-card">
|
|
<div class="presence-top">
|
|
<div>
|
|
<div class="presence-title">noctura.dev</div>
|
|
<div class="presence-subtitle">Portfolio mit eigener technischer Handschrift</div>
|
|
</div>
|
|
<div class="presence-badge">Aktiv</div>
|
|
</div>
|
|
<div class="presence-grid">
|
|
<div class="presence-row">
|
|
<span class="presence-label">Schwerpunkt</span>
|
|
<div class="presence-value">Produktnahe Webprojekte</div>
|
|
<p class="presence-copy">Interfaces, kleine Plattformen und technische Setups mit klarer Kante.</p>
|
|
</div>
|
|
<div class="presence-row">
|
|
<span class="presence-label">Umfeld</span>
|
|
<div class="presence-value">Self-hosted & hands-on</div>
|
|
<p class="presence-copy">Ich lerne am liebsten dort, wo Design, Code und Betrieb direkt aufeinander treffen.</p>
|
|
</div>
|
|
<div class="presence-row">
|
|
<span class="presence-label">Anspruch</span>
|
|
<div class="presence-value">Nicht nur zeigen, sondern belegen</div>
|
|
<p class="presence-copy">Portfolio heißt für mich: Entscheidungen sichtbar machen, nicht nur Ergebnisse dekorieren.</p>
|
|
</div>
|
|
<div class="presence-row">
|
|
<span class="presence-label">Ideal für</span>
|
|
<div class="presence-value">Einstieg mit Verantwortung</div>
|
|
<p class="presence-copy">Teams, die Eigeninitiative, technisches Interesse und saubere Ausführung schätzen.</p>
|
|
</div>
|
|
</div>
|
|
<ul class="availability-list">
|
|
<li>
|
|
<strong>Was diese Seite transportieren soll</strong>
|
|
Ein Entwicklerprofil mit Persönlichkeit statt generischer Agentur-Sprache.
|
|
</li>
|
|
<li>
|
|
<strong>Was hier wichtig ist</strong>
|
|
Verständliche Projekte, saubere Struktur und Signale für echte technische Tiefe.
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="section-divider"></div>
|
|
|
|
<section id="about">
|
|
<div class="reveal">
|
|
<div class="section-label">// Über mich</div>
|
|
<h2 class="section-title">Ein Portfolio sollte zeigen, wie jemand denkt, nicht nur was er aufzählt.</h2>
|
|
<p class="section-subtitle">Genau darauf ist diese Seite ausgerichtet: technische Haltung, Lernkurve und Umsetzungskompetenz sichtbar machen.</p>
|
|
</div>
|
|
<div class="intro-panel reveal">
|
|
<div class="intro-copy">
|
|
<p>
|
|
Ich entwickle Oberflächen mit Blick auf Wirkung, aber genauso auf Aufbau, Wartbarkeit und Übergabe.
|
|
Für mich endet Webentwicklung nicht am Browserfenster, sondern schließt APIs, Server, Sicherheit und Deployment ein.
|
|
</p>
|
|
<p>
|
|
Gerade deshalb passt ein persönliches Portfolio besser zu mir als eine sterile Leistungsseite.
|
|
Es darf Charakter haben, solange die Technik dahinter belastbar bleibt und die Aussagen durch Projekte gedeckt sind.
|
|
</p>
|
|
</div>
|
|
<div class="intro-notes">
|
|
<div class="hero-card-label">Was Recruiter und Teams hier schnell erfassen sollen</div>
|
|
<ul class="note-list">
|
|
<li>Ich kann gestalten, bauen, deployen und Entscheidungen begründen.</li>
|
|
<li>Ich arbeite eigenständig, lerne schnell und denke in funktionierenden Systemen.</li>
|
|
<li>Meine Projekte dienen nicht nur der Optik, sondern zeigen konkrete technische Reife.</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="principles-grid reveal">
|
|
<div class="principle-card">
|
|
<div class="principle-index">Prinzip 01</div>
|
|
<div class="principle-title">Klarheit vor Effekthascherei</div>
|
|
<p class="principle-copy">Gutes Design darf auffallen, muss aber immer lesbar, navigierbar und argumentierbar bleiben.</p>
|
|
</div>
|
|
<div class="principle-card">
|
|
<div class="principle-index">Prinzip 02</div>
|
|
<div class="principle-title">Technik sichtbar mitdenken</div>
|
|
<p class="principle-copy">Ich mag Lösungen, bei denen man nicht nur das Ergebnis, sondern auch die Struktur dahinter ernst nehmen kann.</p>
|
|
</div>
|
|
<div class="principle-card">
|
|
<div class="principle-index">Prinzip 03</div>
|
|
<div class="principle-title">Wartbarkeit ist Teil der Qualität</div>
|
|
<p class="principle-copy">Sauberer Code, nachvollziehbare Entscheidungen und robuste Deployments sind kein Bonus, sondern Standard.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="section-divider"></div>
|
|
|
|
<section id="skills">
|
|
<div class="reveal">
|
|
<div class="section-label">// Fähigkeiten</div>
|
|
<h2 class="section-title">Breit genug für ganze Produkte. Präzise genug für gute Details.</h2>
|
|
<p class="section-subtitle">Die Kombination aus Interface, Logik und Betrieb ist der Bereich, in dem ich am stärksten arbeite.</p>
|
|
</div>
|
|
<div class="skills-grid reveal">
|
|
<div class="skill-card purple">
|
|
<span class="skill-icon">⟨/⟩</span>
|
|
<div class="skill-name">Frontend & Interface Design</div>
|
|
<p class="skill-desc">Responsive Oberflächen mit Charakter, sauberer Informationshierarchie und einem klaren Gefühl für visuelle Spannung ohne Unordnung.</p>
|
|
<div class="skill-tags">
|
|
<span class="tag purple">HTML / CSS</span>
|
|
<span class="tag purple">JavaScript</span>
|
|
<span class="tag purple">UI Systems</span>
|
|
<span class="tag purple">Responsive Layouts</span>
|
|
</div>
|
|
</div>
|
|
<div class="skill-card teal">
|
|
<span class="skill-icon">⬡</span>
|
|
<div class="skill-name">Backend & Infrastruktur</div>
|
|
<p class="skill-desc">Services verbinden, Datenflüsse strukturieren und Hosting so aufsetzen, dass Anwendungen nicht nur laufen, sondern verständlich betrieben werden können.</p>
|
|
<div class="skill-tags">
|
|
<span class="tag teal">Docker</span>
|
|
<span class="tag teal">Node.js</span>
|
|
<span class="tag teal">REST APIs</span>
|
|
<span class="tag teal">Caddy</span>
|
|
<span class="tag teal">Forgejo</span>
|
|
</div>
|
|
</div>
|
|
<div class="skill-card orange">
|
|
<span class="skill-icon">$_</span>
|
|
<div class="skill-name">Linux & Betrieb</div>
|
|
<p class="skill-desc">Server einrichten, absichern und nachhaltig betreiben. Besonders spannend finde ich Self-hosting, Deployments und die Wartbarkeit echter Systeme.</p>
|
|
<div class="skill-tags">
|
|
<span class="tag orange">Debian Linux</span>
|
|
<span class="tag orange">SSH</span>
|
|
<span class="tag orange">systemd</span>
|
|
<span class="tag orange">ufw / fail2ban</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="section-divider"></div>
|
|
|
|
<section id="projects">
|
|
<div class="reveal">
|
|
<div class="section-label">// Portfolio</div>
|
|
<h2 class="section-title">Ausgewählte Arbeiten mit technischer und gestalterischer Aussage.</h2>
|
|
<p class="section-subtitle">Nicht als Produktkatalog, sondern als verdichteter Blick darauf, wie ich Probleme angehe und Qualität bewerte.</p>
|
|
</div>
|
|
<div class="projects-grid reveal">
|
|
<article class="project-card">
|
|
<div class="project-header">
|
|
<div>
|
|
<div class="project-eyebrow">Tooling</div>
|
|
<div class="project-name">Developer Utilities</div>
|
|
</div>
|
|
<span class="project-icon">⌘</span>
|
|
</div>
|
|
<p class="project-desc">Kleine Web-Tools mit klarer UX, schneller Interaktion und pragmatischem Produktgedanken. Der Fokus liegt auf Nutzbarkeit statt auf Marketing-Schichten.</p>
|
|
<div class="project-meta">
|
|
<span class="project-pill">Utility-first Denken</span>
|
|
<span class="project-pill">Schnelle Interaktion</span>
|
|
<span class="project-pill">Klares UI</span>
|
|
</div>
|
|
<ul class="project-points">
|
|
<li>Geeignet, um Produktgefühl und Reduktion auf das Wesentliche sichtbar zu machen.</li>
|
|
<li>Zeigt, dass kleine Projekte trotzdem sorgfältige Informationsarchitektur brauchen.</li>
|
|
</ul>
|
|
<div class="project-foot">
|
|
<div class="project-status">
|
|
<span class="status-dot status-wip"></span>
|
|
<span style="color: var(--muted);">In Entwicklung</span>
|
|
</div>
|
|
<span class="project-linktext">Work in progress <span class="project-arrow">↗</span></span>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="project-card">
|
|
<div class="project-header">
|
|
<div>
|
|
<div class="project-eyebrow">Backend</div>
|
|
<div class="project-name">Custom Backend API</div>
|
|
</div>
|
|
<span class="project-icon">API</span>
|
|
</div>
|
|
<p class="project-desc">Eine eigene API-Struktur für persönliche Anwendungen, bei der Routing, Datenmodelle und Hosting nicht ausgelagert, sondern bewusst kontrolliert werden.</p>
|
|
<div class="project-meta">
|
|
<span class="project-pill">Routing</span>
|
|
<span class="project-pill">Datenmodelle</span>
|
|
<span class="project-pill">Eigenes Hosting</span>
|
|
</div>
|
|
<ul class="project-points">
|
|
<li>Hilft dabei, technische Entscheidungen nicht nur zu verwenden, sondern selbst zu tragen.</li>
|
|
<li>Stärkt die Verbindung zwischen Frontend-Anforderungen und sauberem Service-Aufbau.</li>
|
|
</ul>
|
|
<div class="project-foot">
|
|
<div class="project-status">
|
|
<span class="status-dot status-wip"></span>
|
|
<span style="color: var(--muted);">In Entwicklung</span>
|
|
</div>
|
|
<span class="project-linktext">Architekturaufbau <span class="project-arrow">↗</span></span>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="project-card">
|
|
<div class="project-header">
|
|
<div>
|
|
<div class="project-eyebrow">Experiment</div>
|
|
<div class="project-name">Lab / Playground</div>
|
|
</div>
|
|
<span class="project-icon">△</span>
|
|
</div>
|
|
<p class="project-desc">Ein Bereich für Prototypen, visuelle Versuche und technische Experimente. Gerade dort wird sichtbar, wie ich neue Themen erschließe und Entscheidungen teste.</p>
|
|
<div class="project-meta">
|
|
<span class="project-pill">Prototyping</span>
|
|
<span class="project-pill">Designstudien</span>
|
|
<span class="project-pill">Lernsystem</span>
|
|
</div>
|
|
<ul class="project-points">
|
|
<li>Macht Neugier und Iteration sichtbar, statt nur fertige Ergebnisse zu zeigen.</li>
|
|
<li>Ist der Bereich, in dem Stil, Technik und persönliche Handschrift am direktesten zusammenlaufen.</li>
|
|
</ul>
|
|
<div class="project-foot">
|
|
<div class="project-status">
|
|
<span class="status-dot status-planned"></span>
|
|
<span style="color: var(--muted);">Geplant</span>
|
|
</div>
|
|
<span class="project-linktext">In Vorbereitung <span class="project-arrow">↗</span></span>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="project-card">
|
|
<div class="project-header">
|
|
<div>
|
|
<div class="project-eyebrow">Infrastruktur</div>
|
|
<div class="project-name">noctura.dev Infrastruktur</div>
|
|
</div>
|
|
<span class="project-icon">▣</span>
|
|
</div>
|
|
<p class="project-desc">Der stärkste Portfolio-Baustein im Hintergrund: ein selbst verwalteter VPS mit realen Services, Sicherheitsmaßnahmen und einer Umgebung, die mehr kann als nur statische Auslieferung.</p>
|
|
<div class="project-meta">
|
|
<span class="project-pill">VPS</span>
|
|
<span class="project-pill">Deployment</span>
|
|
<span class="project-pill">Security Basics</span>
|
|
</div>
|
|
<ul class="project-points">
|
|
<li>Belegt, dass ich nicht nur UI baue, sondern Verantwortung für den Betrieb mitdenke.</li>
|
|
<li>Ist besonders relevant für Rollen, in denen Eigenständigkeit und technisches Verständnis erwartet werden.</li>
|
|
</ul>
|
|
<div class="project-foot">
|
|
<div class="project-status">
|
|
<span class="status-dot status-live"></span>
|
|
<span style="color: var(--muted);">Live</span>
|
|
</div>
|
|
<span class="project-linktext">Produktiv im Einsatz <span class="project-arrow">↗</span></span>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
<div class="proof-band reveal">
|
|
<div class="proof-item">
|
|
<div class="proof-label">Portfolio-Ziel</div>
|
|
<p class="proof-copy">Die Arbeiten sollen nach echter Substanz aussehen, nicht nach Platzhaltern mit hübschem Rahmen.</p>
|
|
</div>
|
|
<div class="proof-item">
|
|
<div class="proof-label">Signalwirkung</div>
|
|
<p class="proof-copy">Jede Karte trägt eine erkennbare Perspektive: Produkt, Architektur, Lernen oder Betrieb.</p>
|
|
</div>
|
|
<div class="proof-item">
|
|
<div class="proof-label">Wirkung im Gespräch</div>
|
|
<p class="proof-copy">Die Inhalte liefern Einstiegspunkte für Fachgespräche statt austauschbarer Selbstdarstellung.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="section-divider"></div>
|
|
|
|
<section id="snapshot">
|
|
<div class="reveal">
|
|
<div class="section-label">// Profil</div>
|
|
<h2 class="section-title">Die komprimierte Version für Bewerbung, Erstgespräch und schnellen Eindruck.</h2>
|
|
<p class="section-subtitle">Vier kurze Aussagen, die im Kopf bleiben sollen, wenn sich jemand nur wenige Minuten Zeit nimmt.</p>
|
|
</div>
|
|
<div class="snapshot-grid reveal">
|
|
<div class="snapshot-card">
|
|
<div class="snapshot-kicker">Arbeitsweise</div>
|
|
<div class="snapshot-value">Hands-on</div>
|
|
<p class="snapshot-desc">Ich lerne bevorzugt über echte Umsetzung, Fehleranalyse und Iteration statt über reines Tutorial-Nachbauen.</p>
|
|
</div>
|
|
<div class="snapshot-card">
|
|
<div class="snapshot-kicker">Stärke</div>
|
|
<div class="snapshot-value">Frontend plus Betrieb</div>
|
|
<p class="snapshot-desc">Ich kann Entscheidungen vom Interface bis zum Deployment zusammenhängend betrachten und daraus bessere Lösungen ableiten.</p>
|
|
</div>
|
|
<div class="snapshot-card">
|
|
<div class="snapshot-kicker">Motivation</div>
|
|
<div class="snapshot-value">Systeme wirklich verstehen</div>
|
|
<p class="snapshot-desc">Mich reizt Technik dann besonders, wenn ich sie nicht nur benutze, sondern selbst strukturieren und betreiben kann.</p>
|
|
</div>
|
|
<div class="snapshot-card">
|
|
<div class="snapshot-kicker">Eindruck</div>
|
|
<div class="snapshot-value">Substanz vor Buzzwords</div>
|
|
<p class="snapshot-desc">Diese Seite soll zeigen, wie ich arbeite und entscheide, nicht nur welche Begriffe ich aufzählen könnte.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="section-divider"></div>
|
|
|
|
<section id="contact">
|
|
<div class="contact-box reveal">
|
|
<h2>Kontakt für Bewerbungen, Zusammenarbeit oder technische Gespräche</h2>
|
|
<p>Wenn du einen Entwickler suchst, der Design nicht von Technik trennt und Verantwortung auch hinter der Oberfläche übernimmt, schreib mir direkt.</p>
|
|
<a href="mailto:kontakt@noctura.dev" class="btn btn-primary">kontakt@noctura.dev</a>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<footer>
|
|
<div class="footer-inner">
|
|
<span>noctura.dev - persönliches Portfolio mit eigener Infrastruktur</span>
|
|
<span>HTML · CSS · JavaScript · Debian 12</span>
|
|
</div>
|
|
</footer>
|
|
|
|
<script>
|
|
const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
const canvas = document.getElementById('stars');
|
|
const ctx = canvas.getContext('2d');
|
|
let stars = [];
|
|
let animationId;
|
|
|
|
function resize() {
|
|
canvas.width = window.innerWidth;
|
|
canvas.height = window.innerHeight;
|
|
stars = Array.from({ length: window.innerWidth < 720 ? 110 : 180 }, () => ({
|
|
x: Math.random() * canvas.width,
|
|
y: Math.random() * canvas.height,
|
|
r: Math.random() * 1.2 + 0.2,
|
|
o: Math.random() * 0.6 + 0.12,
|
|
s: Math.random() * 0.45 + 0.08,
|
|
t: Math.random() * Math.PI * 2
|
|
}));
|
|
}
|
|
|
|
function drawStars() {
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
stars.forEach((star) => {
|
|
star.t += 0.008 * star.s;
|
|
const opacity = star.o * (0.62 + 0.38 * Math.sin(star.t));
|
|
ctx.beginPath();
|
|
ctx.arc(star.x, star.y, star.r, 0, Math.PI * 2);
|
|
ctx.fillStyle = `rgba(210,220,255,${opacity})`;
|
|
ctx.fill();
|
|
});
|
|
animationId = requestAnimationFrame(drawStars);
|
|
}
|
|
|
|
window.addEventListener('resize', resize);
|
|
resize();
|
|
|
|
if (!reducedMotion) {
|
|
drawStars();
|
|
} else {
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
}
|
|
|
|
const reveals = document.querySelectorAll('.reveal');
|
|
if (!reducedMotion) {
|
|
const io = new IntersectionObserver((entries) => {
|
|
entries.forEach((entry, index) => {
|
|
if (entry.isIntersecting) {
|
|
setTimeout(() => entry.target.classList.add('visible'), index * 90);
|
|
io.unobserve(entry.target);
|
|
}
|
|
});
|
|
}, { threshold: 0.14 });
|
|
|
|
reveals.forEach((el) => io.observe(el));
|
|
} else {
|
|
reveals.forEach((el) => el.classList.add('visible'));
|
|
}
|
|
|
|
window.addEventListener('beforeunload', () => {
|
|
if (animationId) cancelAnimationFrame(animationId);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|