Landingpage/index.html
JaysonCleve 77d847583c
All checks were successful
Deploy landingpage / deploy (push) Successful in 3s
changes to index.html
2026-04-14 14:11:35 +02:00

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>