1023 lines
37 KiB
HTML
1023 lines
37 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</title>
|
|
<meta name="description" content="Portfolio für Web, Systeme und Infrastruktur."/>
|
|
<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=Instrument+Serif:ital@0;1&family=Geist:wght@300;400;500;600&family=Geist+Mono:wght@300;400&display=swap" rel="stylesheet"/>
|
|
<style>
|
|
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
|
:root{
|
|
--ink:#0a0a0c;
|
|
--ink-soft:#141417;
|
|
--ink-mid:#1c1c22;
|
|
--ink-border:rgba(255,255,255,0.07);
|
|
--ink-border-hi:rgba(255,255,255,0.14);
|
|
--text:#f0ede8;
|
|
--text-dim:#8a8780;
|
|
--text-muted:#5a5855;
|
|
--gold:#c9a96e;
|
|
--gold-dim:rgba(201,169,110,0.15);
|
|
--gold-glow:rgba(201,169,110,0.08);
|
|
--teal:#5ec4a8;
|
|
--teal-dim:rgba(94,196,168,0.12);
|
|
--ff-serif:'Instrument Serif',Georgia,serif;
|
|
--ff-sans:'Geist',system-ui,sans-serif;
|
|
--ff-mono:'Geist Mono',monospace;
|
|
--ease-out:cubic-bezier(0.16,1,0.3,1);
|
|
}
|
|
html{scroll-behavior:smooth;font-size:16px}
|
|
body{
|
|
background:var(--ink);
|
|
color:var(--text);
|
|
font-family:var(--ff-sans);
|
|
line-height:1.6;
|
|
min-height:100vh;
|
|
overflow-x:hidden;
|
|
}
|
|
::selection{background:rgba(201,169,110,0.22);color:#fff}
|
|
a{color:inherit;text-decoration:none}
|
|
img{display:block}
|
|
|
|
/* ── NOISE TEXTURE ───────────────────────────── */
|
|
body::after{
|
|
content:'';
|
|
position:fixed;inset:0;
|
|
background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='1'/%3E%3C/svg%3E");
|
|
opacity:0.028;
|
|
pointer-events:none;
|
|
z-index:999;
|
|
}
|
|
|
|
/* ── CANVAS ──────────────────────────────────── */
|
|
#c{position:fixed;inset:0;z-index:0;pointer-events:none}
|
|
|
|
/* ── NAV ─────────────────────────────────────── */
|
|
nav{
|
|
position:fixed;top:0;left:0;right:0;z-index:100;
|
|
padding:0 2.5rem;
|
|
height:60px;
|
|
display:flex;align-items:center;justify-content:space-between;
|
|
border-bottom:1px solid var(--ink-border);
|
|
background:rgba(10,10,12,0.82);
|
|
backdrop-filter:blur(24px);
|
|
}
|
|
.nav-logo{
|
|
font-family:var(--ff-mono);
|
|
font-size:0.78rem;
|
|
letter-spacing:0.12em;
|
|
color:var(--text-dim);
|
|
}
|
|
.nav-logo span{color:var(--gold)}
|
|
.nav-links{
|
|
display:flex;gap:2.5rem;
|
|
list-style:none;
|
|
}
|
|
.nav-links a{
|
|
font-size:0.72rem;
|
|
letter-spacing:0.1em;
|
|
text-transform:uppercase;
|
|
color:var(--text-muted);
|
|
transition:color 0.2s;
|
|
}
|
|
.nav-links a:hover{color:var(--text)}
|
|
|
|
/* ── LAYOUT ─────────────────────────────────── */
|
|
.container{
|
|
position:relative;z-index:1;
|
|
max-width:1140px;
|
|
margin:0 auto;
|
|
padding:0 2.5rem;
|
|
}
|
|
|
|
/* ── HERO ───────────────────────────────────── */
|
|
.hero{
|
|
padding:148px 0 100px;
|
|
display:grid;
|
|
grid-template-columns:1fr 360px;
|
|
gap:3rem;
|
|
align-items:start;
|
|
}
|
|
.hero-eyebrow{
|
|
font-family:var(--ff-mono);
|
|
font-size:0.68rem;
|
|
letter-spacing:0.18em;
|
|
text-transform:uppercase;
|
|
color:var(--gold);
|
|
margin-bottom:1.75rem;
|
|
display:flex;align-items:center;gap:0.75rem;
|
|
opacity:0;animation:up 0.7s var(--ease-out) 0.1s forwards;
|
|
}
|
|
.hero-eyebrow::before{
|
|
content:'';width:24px;height:1px;
|
|
background:var(--gold);opacity:0.5;
|
|
}
|
|
.hero h1{
|
|
font-family:var(--ff-serif);
|
|
font-size:clamp(3.5rem,7vw,6rem);
|
|
font-weight:400;
|
|
line-height:0.95;
|
|
letter-spacing:-0.02em;
|
|
margin-bottom:2rem;
|
|
opacity:0;animation:up 0.8s var(--ease-out) 0.25s forwards;
|
|
}
|
|
.hero h1 em{
|
|
font-style:italic;
|
|
color:var(--gold);
|
|
}
|
|
.hero-desc{
|
|
font-size:1rem;
|
|
color:var(--text-dim);
|
|
line-height:1.85;
|
|
max-width:560px;
|
|
margin-bottom:2.5rem;
|
|
opacity:0;animation:up 0.8s var(--ease-out) 0.4s forwards;
|
|
}
|
|
.hero-desc strong{color:var(--text);font-weight:500}
|
|
.hero-actions{
|
|
display:flex;gap:1rem;flex-wrap:wrap;
|
|
opacity:0;animation:up 0.8s var(--ease-out) 0.55s forwards;
|
|
}
|
|
.btn{
|
|
display:inline-flex;align-items:center;gap:8px;
|
|
padding:0.78rem 1.5rem;
|
|
font-family:var(--ff-sans);
|
|
font-size:0.8rem;
|
|
font-weight:500;
|
|
letter-spacing:0.03em;
|
|
border-radius:4px;
|
|
transition:all 0.2s var(--ease-out);
|
|
cursor:pointer;border:none;
|
|
}
|
|
.btn-gold{
|
|
background:var(--gold);
|
|
color:#0a0a0c;
|
|
}
|
|
.btn-gold:hover{background:#d4b07c;transform:translateY(-1px)}
|
|
.btn-ghost{
|
|
background:transparent;
|
|
color:var(--text-dim);
|
|
border:1px solid var(--ink-border-hi);
|
|
}
|
|
.btn-ghost:hover{color:var(--text);border-color:rgba(255,255,255,0.28);transform:translateY(-1px)}
|
|
|
|
/* Hero metrics row */
|
|
.hero-metrics{
|
|
display:flex;gap:0;
|
|
border:1px solid var(--ink-border);
|
|
border-radius:6px;
|
|
overflow:hidden;
|
|
margin-top:3rem;
|
|
opacity:0;animation:up 0.8s var(--ease-out) 0.7s forwards;
|
|
}
|
|
.hero-metric{
|
|
flex:1;
|
|
padding:1.2rem 1.5rem;
|
|
border-right:1px solid var(--ink-border);
|
|
}
|
|
.hero-metric:last-child{border-right:none}
|
|
.hero-metric-label{
|
|
font-family:var(--ff-mono);
|
|
font-size:0.6rem;
|
|
letter-spacing:0.14em;
|
|
text-transform:uppercase;
|
|
color:var(--teal);
|
|
margin-bottom:0.5rem;
|
|
}
|
|
.hero-metric-val{font-size:0.88rem;font-weight:500;margin-bottom:0.2rem}
|
|
.hero-metric-copy{font-size:0.76rem;color:var(--text-muted);line-height:1.5}
|
|
|
|
/* ── HERO CARD ───────────────────────────────── */
|
|
.hero-card{
|
|
opacity:0;animation:up 0.8s var(--ease-out) 0.6s forwards;
|
|
position:sticky;top:80px;
|
|
border:1px solid var(--ink-border);
|
|
border-radius:10px;
|
|
overflow:hidden;
|
|
background:var(--ink-soft);
|
|
}
|
|
.hc-bar{
|
|
height:3px;
|
|
background:linear-gradient(90deg,var(--gold),var(--teal));
|
|
}
|
|
.hc-body{padding:1.5rem}
|
|
.hc-top{
|
|
display:flex;align-items:center;justify-content:space-between;
|
|
margin-bottom:1.25rem;
|
|
}
|
|
.hc-name{font-size:0.92rem;font-weight:500}
|
|
.hc-sub{font-size:0.75rem;color:var(--text-muted);margin-top:2px}
|
|
.hc-badge{
|
|
display:inline-flex;align-items:center;gap:6px;
|
|
padding:0.3rem 0.7rem;
|
|
border-radius:99px;
|
|
background:rgba(94,196,168,0.1);
|
|
border:1px solid rgba(94,196,168,0.2);
|
|
font-family:var(--ff-mono);
|
|
font-size:0.63rem;
|
|
letter-spacing:0.06em;
|
|
color:var(--teal);
|
|
}
|
|
.hc-badge::before{
|
|
content:'';width:6px;height:6px;border-radius:50%;
|
|
background:var(--teal);
|
|
animation:blink 2s ease-in-out infinite;
|
|
}
|
|
@keyframes blink{0%,100%{opacity:1}50%{opacity:0.35}}
|
|
.hc-grid{display:grid;grid-template-columns:1fr 1fr;gap:0.6rem;margin-bottom:1rem}
|
|
.hc-cell{
|
|
padding:0.85rem;
|
|
border-radius:6px;
|
|
background:var(--ink-mid);
|
|
border:1px solid var(--ink-border);
|
|
}
|
|
.hc-cell-label{
|
|
font-family:var(--ff-mono);
|
|
font-size:0.6rem;letter-spacing:0.12em;text-transform:uppercase;
|
|
color:var(--gold);margin-bottom:0.35rem;
|
|
}
|
|
.hc-cell-val{font-size:0.82rem;font-weight:500;margin-bottom:0.15rem}
|
|
.hc-cell-copy{font-size:0.72rem;color:var(--text-muted);line-height:1.45}
|
|
.hc-list{display:grid;gap:0.5rem}
|
|
.hc-list-item{
|
|
padding:0.75rem;border-radius:6px;
|
|
background:var(--ink-mid);border:1px solid var(--ink-border);
|
|
font-size:0.76rem;color:var(--text-muted);line-height:1.5;
|
|
}
|
|
.hc-list-item strong{display:block;color:var(--text);font-weight:500;margin-bottom:2px;font-size:0.78rem}
|
|
|
|
/* ── SECTION COMMONS ─────────────────────────── */
|
|
section{padding:96px 0;position:relative;z-index:1}
|
|
.divider{
|
|
height:1px;
|
|
background:linear-gradient(90deg,transparent,var(--ink-border) 30%,var(--ink-border) 70%,transparent);
|
|
}
|
|
.s-label{
|
|
font-family:var(--ff-mono);
|
|
font-size:0.66rem;
|
|
letter-spacing:0.18em;
|
|
text-transform:uppercase;
|
|
color:var(--gold);
|
|
margin-bottom:1rem;
|
|
}
|
|
.s-title{
|
|
font-family:var(--ff-serif);
|
|
font-size:clamp(2rem,3.5vw,3rem);
|
|
font-weight:400;
|
|
line-height:1.1;
|
|
letter-spacing:-0.02em;
|
|
margin-bottom:0.75rem;
|
|
}
|
|
.s-title em{font-style:italic;color:var(--gold)}
|
|
.s-subtitle{
|
|
font-size:0.95rem;
|
|
color:var(--text-dim);
|
|
max-width:640px;
|
|
line-height:1.75;
|
|
margin-bottom:3.5rem;
|
|
}
|
|
|
|
/* ── ABOUT ───────────────────────────────────── */
|
|
.about-grid{
|
|
display:grid;
|
|
grid-template-columns:1fr 1fr;
|
|
gap:1px;
|
|
background:var(--ink-border);
|
|
border:1px solid var(--ink-border);
|
|
border-radius:10px;
|
|
overflow:hidden;
|
|
margin-bottom:1px;
|
|
}
|
|
.about-cell{
|
|
background:var(--ink-soft);
|
|
padding:2rem;
|
|
}
|
|
.about-cell p{font-size:0.9rem;color:var(--text-dim);line-height:1.85;margin-bottom:1rem}
|
|
.about-cell p:last-child{margin-bottom:0}
|
|
.about-cell p strong{color:var(--text);font-weight:500}
|
|
.about-notes{
|
|
background:var(--ink-soft);
|
|
border:1px solid var(--ink-border);
|
|
border-top:none;
|
|
border-radius:0 0 10px 10px;
|
|
padding:1.5rem 2rem;
|
|
}
|
|
.notes-label{
|
|
font-family:var(--ff-mono);
|
|
font-size:0.62rem;letter-spacing:0.14em;text-transform:uppercase;
|
|
color:var(--teal);margin-bottom:1rem;
|
|
}
|
|
.notes-list{display:flex;flex-wrap:wrap;gap:0.5rem;list-style:none}
|
|
.notes-list li{
|
|
padding:0.4rem 0.85rem;
|
|
border-radius:4px;
|
|
border:1px solid var(--ink-border-hi);
|
|
font-size:0.78rem;
|
|
color:var(--text-dim);
|
|
}
|
|
.principles{
|
|
display:grid;grid-template-columns:repeat(3,1fr);
|
|
gap:1px;
|
|
background:var(--ink-border);
|
|
border:1px solid var(--ink-border);
|
|
border-radius:10px;
|
|
overflow:hidden;
|
|
margin-top:1rem;
|
|
}
|
|
.principle{
|
|
background:var(--ink-soft);
|
|
padding:1.75rem;
|
|
}
|
|
.p-num{
|
|
font-family:var(--ff-mono);
|
|
font-size:0.62rem;letter-spacing:0.14em;
|
|
color:var(--text-muted);
|
|
margin-bottom:0.85rem;
|
|
}
|
|
.p-title{font-weight:500;font-size:0.92rem;margin-bottom:0.5rem}
|
|
.p-copy{font-size:0.82rem;color:var(--text-muted);line-height:1.65}
|
|
|
|
/* ── SKILLS ──────────────────────────────────── */
|
|
.skills-grid{
|
|
display:grid;grid-template-columns:repeat(3,1fr);
|
|
gap:1px;
|
|
background:var(--ink-border);
|
|
border:1px solid var(--ink-border);
|
|
border-radius:10px;
|
|
overflow:hidden;
|
|
}
|
|
.skill{
|
|
background:var(--ink-soft);
|
|
padding:2.25rem 2rem;
|
|
transition:background 0.25s;
|
|
}
|
|
.skill:hover{background:var(--ink-mid)}
|
|
.skill-icon{
|
|
font-family:var(--ff-mono);
|
|
font-size:1.1rem;
|
|
color:var(--gold);
|
|
margin-bottom:1.25rem;
|
|
display:block;
|
|
}
|
|
.skill-name{font-size:1rem;font-weight:500;margin-bottom:0.6rem}
|
|
.skill-desc{font-size:0.83rem;color:var(--text-dim);line-height:1.7;margin-bottom:1.5rem}
|
|
.tags{display:flex;flex-wrap:wrap;gap:6px}
|
|
.tag{
|
|
font-family:var(--ff-mono);
|
|
font-size:0.62rem;letter-spacing:0.04em;
|
|
padding:4px 8px;border-radius:3px;
|
|
}
|
|
.tag-gold{background:var(--gold-dim);color:var(--gold);border:1px solid rgba(201,169,110,0.25)}
|
|
.tag-teal{background:var(--teal-dim);color:var(--teal);border:1px solid rgba(94,196,168,0.25)}
|
|
.tag-dim{background:rgba(255,255,255,0.04);color:var(--text-muted);border:1px solid var(--ink-border-hi)}
|
|
|
|
/* ── PROJECTS ────────────────────────────────── */
|
|
.projects-grid{
|
|
display:grid;grid-template-columns:repeat(2,1fr);
|
|
gap:1px;
|
|
background:var(--ink-border);
|
|
border:1px solid var(--ink-border);
|
|
border-radius:10px;
|
|
overflow:hidden;
|
|
}
|
|
.project{
|
|
background:var(--ink-soft);
|
|
padding:2rem;
|
|
display:flex;flex-direction:column;
|
|
gap:1rem;
|
|
transition:background 0.25s;
|
|
position:relative;
|
|
}
|
|
.project::before{
|
|
content:'';
|
|
position:absolute;top:0;left:0;right:0;
|
|
height:2px;
|
|
background:linear-gradient(90deg,var(--gold),transparent);
|
|
opacity:0;
|
|
transition:opacity 0.25s;
|
|
}
|
|
.project:hover{background:var(--ink-mid)}
|
|
.project:hover::before{opacity:1}
|
|
.proj-top{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem}
|
|
.proj-icon{
|
|
width:44px;height:44px;
|
|
border-radius:8px;
|
|
border:1px solid var(--ink-border-hi);
|
|
display:flex;align-items:center;justify-content:center;
|
|
font-family:var(--ff-mono);
|
|
font-size:0.78rem;
|
|
color:var(--text-dim);
|
|
flex-shrink:0;
|
|
}
|
|
.proj-eyebrow{
|
|
font-family:var(--ff-mono);
|
|
font-size:0.62rem;letter-spacing:0.1em;text-transform:uppercase;
|
|
color:var(--text-muted);margin-bottom:4px;
|
|
}
|
|
.proj-name{font-size:1.05rem;font-weight:500}
|
|
.proj-desc{font-size:0.83rem;color:var(--text-dim);line-height:1.7;flex:1}
|
|
.proj-tags{display:flex;flex-wrap:wrap;gap:6px}
|
|
.proj-pts{list-style:none;display:grid;gap:0.5rem}
|
|
.proj-pts li{
|
|
font-size:0.78rem;color:var(--text-muted);
|
|
padding-left:1rem;position:relative;line-height:1.55;
|
|
}
|
|
.proj-pts li::before{
|
|
content:'';position:absolute;
|
|
left:0;top:0.55rem;
|
|
width:4px;height:4px;border-radius:50%;
|
|
background:var(--teal);
|
|
}
|
|
.proj-foot{
|
|
display:flex;align-items:center;justify-content:space-between;
|
|
margin-top:auto;padding-top:0.25rem;
|
|
}
|
|
.proj-status{
|
|
display:flex;align-items:center;gap:6px;
|
|
font-family:var(--ff-mono);font-size:0.62rem;color:var(--text-muted);
|
|
}
|
|
.dot{width:5px;height:5px;border-radius:50%;flex-shrink:0}
|
|
.dot-live{background:#4ade80;box-shadow:0 0 5px #4ade80}
|
|
.dot-wip{background:#facc15;box-shadow:0 0 5px #facc15}
|
|
.dot-plan{background:var(--text-muted)}
|
|
.proj-link{
|
|
font-family:var(--ff-mono);font-size:0.65rem;letter-spacing:0.06em;
|
|
text-transform:uppercase;color:var(--text-muted);
|
|
transition:color 0.2s;
|
|
}
|
|
.project:hover .proj-link{color:var(--gold)}
|
|
|
|
/* proof band */
|
|
.proof-band{
|
|
display:grid;grid-template-columns:repeat(3,1fr);
|
|
gap:1px;background:var(--ink-border);
|
|
border:1px solid var(--ink-border);
|
|
border-top:none;
|
|
border-radius:0 0 10px 10px;
|
|
overflow:hidden;
|
|
}
|
|
.proof-item{background:var(--ink-soft);padding:1.25rem 1.5rem}
|
|
.proof-label{
|
|
font-family:var(--ff-mono);
|
|
font-size:0.6rem;letter-spacing:0.14em;text-transform:uppercase;
|
|
color:var(--teal);margin-bottom:0.5rem;
|
|
}
|
|
.proof-copy{font-size:0.8rem;color:var(--text-muted);line-height:1.6}
|
|
|
|
/* ── SNAPSHOT ────────────────────────────────── */
|
|
.snapshot-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--ink-border);border:1px solid var(--ink-border);border-radius:10px;overflow:hidden}
|
|
.snap{
|
|
background:var(--ink-soft);padding:1.75rem 1.5rem;
|
|
transition:background 0.25s;
|
|
}
|
|
.snap:hover{background:var(--ink-mid)}
|
|
.snap-kicker{
|
|
font-family:var(--ff-mono);font-size:0.6rem;letter-spacing:0.14em;text-transform:uppercase;
|
|
color:var(--gold);margin-bottom:0.75rem;
|
|
}
|
|
.snap-val{
|
|
font-family:var(--ff-serif);font-size:1.4rem;font-weight:400;font-style:italic;
|
|
line-height:1.2;margin-bottom:0.6rem;
|
|
}
|
|
.snap-desc{font-size:0.78rem;color:var(--text-muted);line-height:1.6}
|
|
|
|
/* ── CONTACT ─────────────────────────────────── */
|
|
.contact-box{
|
|
position:relative;overflow:hidden;
|
|
border:1px solid var(--ink-border);
|
|
border-radius:10px;
|
|
padding:5rem 3rem;
|
|
text-align:center;
|
|
background:var(--ink-soft);
|
|
}
|
|
.contact-box::before{
|
|
content:'';position:absolute;
|
|
top:-80px;left:50%;transform:translateX(-50%);
|
|
width:500px;height:200px;
|
|
background:radial-gradient(ellipse,rgba(201,169,110,0.07),transparent 70%);
|
|
pointer-events:none;
|
|
}
|
|
.contact-box h2{
|
|
font-family:var(--ff-serif);
|
|
font-size:clamp(2rem,4vw,3.2rem);
|
|
font-weight:400;letter-spacing:-0.02em;
|
|
margin-bottom:1rem;position:relative;
|
|
}
|
|
.contact-box h2 em{font-style:italic;color:var(--gold)}
|
|
.contact-box p{
|
|
font-size:0.95rem;color:var(--text-dim);
|
|
max-width:560px;margin:0 auto 2.5rem;
|
|
line-height:1.8;position:relative;
|
|
}
|
|
.contact-email{
|
|
font-family:var(--ff-mono);
|
|
font-size:0.78rem;letter-spacing:0.08em;
|
|
color:var(--text-dim);
|
|
margin-top:1.5rem;
|
|
display:block;
|
|
position:relative;
|
|
}
|
|
|
|
/* ── FOOTER ──────────────────────────────────── */
|
|
footer{
|
|
border-top:1px solid var(--ink-border);
|
|
padding:2rem 0;
|
|
}
|
|
.footer-inner{
|
|
max-width:1140px;margin:0 auto;padding:0 2.5rem;
|
|
display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:1rem;
|
|
}
|
|
.footer-inner span{
|
|
font-family:var(--ff-mono);font-size:0.65rem;letter-spacing:0.06em;
|
|
color:var(--text-muted);
|
|
}
|
|
|
|
/* ── REVEAL ──────────────────────────────────── */
|
|
.reveal{
|
|
opacity:0;transform:translateY(28px);
|
|
transition:opacity 0.7s var(--ease-out),transform 0.7s var(--ease-out);
|
|
}
|
|
.reveal.in{opacity:1;transform:none}
|
|
@keyframes up{
|
|
from{opacity:0;transform:translateY(22px)}
|
|
to{opacity:1;transform:none}
|
|
}
|
|
|
|
/* ── RESPONSIVE ──────────────────────────────── */
|
|
@media(max-width:1060px){
|
|
.hero{grid-template-columns:1fr}
|
|
.hero-card{position:static}
|
|
.hero-metrics{flex-wrap:wrap}
|
|
.hero-metric{flex:1 1 160px}
|
|
.snapshot-grid{grid-template-columns:repeat(2,1fr)}
|
|
}
|
|
@media(max-width:760px){
|
|
nav{padding:0 1.25rem}
|
|
.nav-links{display:none}
|
|
.container{padding:0 1.25rem}
|
|
.hero{padding:100px 0 64px}
|
|
section{padding:72px 0}
|
|
.about-grid,.skills-grid,.projects-grid,.proof-band,.principles,.snapshot-grid{
|
|
grid-template-columns:1fr
|
|
}
|
|
.hc-grid{grid-template-columns:1fr}
|
|
.contact-box{padding:3rem 1.5rem}
|
|
.footer-inner{padding:0 1.25rem}
|
|
}
|
|
@media(prefers-reduced-motion:reduce){
|
|
*,*::before,*::after{
|
|
animation-duration:0.01ms!important;
|
|
transition-duration:0.01ms!important;
|
|
}
|
|
.reveal,.hero-eyebrow,.hero h1,.hero-desc,.hero-actions,.hero-metrics,.hero-card{
|
|
opacity:1;transform:none;animation:none;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<canvas id="c"></canvas>
|
|
|
|
<nav>
|
|
<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>
|
|
</nav>
|
|
|
|
<div class="container">
|
|
|
|
<!-- HERO -->
|
|
<section class="hero">
|
|
<div class="hero-copy">
|
|
<div class="hero-eyebrow">Persönliches Portfolio · Web · Systeme · Infrastruktur</div>
|
|
<h1>Interfaces mit<br><em>Haltung.</em><br>Systeme mit<br>Substanz.</h1>
|
|
<p class="hero-desc">Ich baue digitale Projekte, die nicht bei einer schönen Oberfläche aufhören. Mir ist wichtig, dass <strong>Gestaltung, technische Entscheidungen und Betrieb zusammenpassen</strong> — also nicht nur, wie etwas aussieht, sondern auch, wie sauber es aufgebaut ist und wie zuverlässig es läuft.</p>
|
|
<div class="hero-actions">
|
|
<a href="#projects" class="btn btn-gold">Arbeiten ansehen</a>
|
|
<a href="#contact" class="btn btn-ghost">Kontakt aufnehmen</a>
|
|
</div>
|
|
<div class="hero-metrics">
|
|
<div class="hero-metric">
|
|
<div class="hero-metric-label">Fokus</div>
|
|
<div class="hero-metric-val">End-to-End</div>
|
|
<div class="hero-metric-copy">Vom ersten Layout bis zur laufenden Anwendung mitgedacht.</div>
|
|
</div>
|
|
<div class="hero-metric">
|
|
<div class="hero-metric-label">Arbeitsweise</div>
|
|
<div class="hero-metric-val">Präzise & direkt</div>
|
|
<div class="hero-metric-copy">Lieber sauber bauen als groß darüber reden.</div>
|
|
</div>
|
|
<div class="hero-metric">
|
|
<div class="hero-metric-label">Stack</div>
|
|
<div class="hero-metric-val">HTML · CSS · JS · Linux</div>
|
|
<div class="hero-metric-copy">Genug Breite für komplette Projekte, ohne beliebig zu werden.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<aside class="hero-card">
|
|
<div class="hc-bar"></div>
|
|
<div class="hc-body">
|
|
<div class="hc-top">
|
|
<div>
|
|
<div class="hc-name">noctura.dev</div>
|
|
<div class="hc-sub">Portfolio · eigene Infrastruktur</div>
|
|
</div>
|
|
<div class="hc-badge">Aktiv</div>
|
|
</div>
|
|
<div class="hc-grid">
|
|
<div class="hc-cell">
|
|
<div class="hc-cell-label">Schwerpunkt</div>
|
|
<div class="hc-cell-val">Webprojekte mit Substanz</div>
|
|
<div class="hc-cell-copy">Oberflächen, die nicht nur gut aussehen, sondern sauber funktionieren.</div>
|
|
</div>
|
|
<div class="hc-cell">
|
|
<div class="hc-cell-label">Umfeld</div>
|
|
<div class="hc-cell-val">Eigene Infrastruktur</div>
|
|
<div class="hc-cell-copy">Ich finde es spannend, Dinge nicht nur zu bauen, sondern auch selbst zu betreiben.</div>
|
|
</div>
|
|
<div class="hc-cell">
|
|
<div class="hc-cell-label">Anspruch</div>
|
|
<div class="hc-cell-val">Nachvollziehbare Arbeit</div>
|
|
<div class="hc-cell-copy">Ich möchte zeigen, wie ich denke und entscheide, nicht nur fertige Screens.</div>
|
|
</div>
|
|
<div class="hc-cell">
|
|
<div class="hc-cell-label">Ideal für</div>
|
|
<div class="hc-cell-val">Passend für Teams</div>
|
|
<div class="hc-cell-copy">Vor allem dort, wo Eigeninitiative und sauberes Arbeiten geschätzt werden.</div>
|
|
</div>
|
|
</div>
|
|
<div class="hc-list">
|
|
<div class="hc-list-item">
|
|
<strong>Worum es mir hier geht</strong>
|
|
Kein aufpoliertes Schaufenster, sondern ein ehrlicher Eindruck davon, wie ich an Projekte herangehe.
|
|
</div>
|
|
<div class="hc-list-item">
|
|
<strong>Was mir wichtig ist</strong>
|
|
Verständliche Projekte, klare Entscheidungen und Technik, die nicht unnötig kompliziert wirkt.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
</section>
|
|
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<!-- ABOUT -->
|
|
<div class="container">
|
|
<section id="about">
|
|
<div class="reveal">
|
|
<div class="s-label">// Über mich</div>
|
|
<h2 class="s-title">Ein Portfolio sollte zeigen,<br>wie jemand <em>arbeitet.</em></h2>
|
|
<p class="s-subtitle">Nicht nur, was auf einer Liste steht. Mir ist wichtiger, dass man hier ein Gefühl für meine Arbeitsweise, meinen Anspruch und meinen Lernweg bekommt.</p>
|
|
</div>
|
|
<div class="reveal">
|
|
<div class="about-grid">
|
|
<div class="about-cell">
|
|
<p>Ich entwickle Oberflächen nicht nur danach, ob sie gut aussehen, sondern auch danach, ob sie verständlich aufgebaut sind und sich sauber weiterentwickeln lassen. Für mich hört Webentwicklung nicht im Browser auf, sondern geht bis zu Servern, Deployment und dem Betrieb im Alltag.</p>
|
|
<p>Genau deshalb ist dieses <strong>persönliche Portfolio</strong> bewusst keine klassische Leistungsseite. Ich wollte lieber etwas bauen, das zu mir passt: etwas mit Charakter, aber ohne leere Inszenierung und ohne technische Fassade.</p>
|
|
</div>
|
|
<div class="about-cell" style="border-left:1px solid var(--ink-border)">
|
|
<div class="notes-label">Was diese Seite über mich zeigt</div>
|
|
<ul class="notes-list">
|
|
<li>Ich kombiniere Gestaltung, Umsetzung und Betrieb.</li>
|
|
<li>Ich arbeite gern eigenständig und lerne über echte Projekte.</li>
|
|
<li>Mich interessieren saubere Lösungen statt laute Buzzwords.</li>
|
|
<li>Die Seite soll eher Haltung zeigen als Selbstdarstellung.</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="about-notes">
|
|
<div class="notes-label">Stack & Kontext</div>
|
|
<ul class="notes-list">
|
|
<li>HTML / CSS / JavaScript</li>
|
|
<li>Node.js / REST APIs</li>
|
|
<li>Docker & Compose</li>
|
|
<li>Debian Linux</li>
|
|
<li>Caddy / systemd</li>
|
|
<li>Forgejo</li>
|
|
<li>ufw / fail2ban</li>
|
|
<li>SSH-Härtung</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="principles reveal">
|
|
<div class="principle">
|
|
<div class="p-num">01 —</div>
|
|
<div class="p-title">Klarheit vor Effekten</div>
|
|
<p class="p-copy">Ich mag Gestaltung, die Charakter hat, aber nicht im Weg steht. Dinge sollen auffallen dürfen, nur eben nicht auf Kosten der Lesbarkeit.</p>
|
|
</div>
|
|
<div class="principle" style="border-left:1px solid var(--ink-border)">
|
|
<div class="p-num">02 —</div>
|
|
<div class="p-title">Technik mitdenken</div>
|
|
<p class="p-copy">Mich interessieren Lösungen, bei denen nicht nur das Ergebnis stimmt, sondern auch der Aufbau dahinter nachvollziehbar ist.</p>
|
|
</div>
|
|
<div class="principle" style="border-left:1px solid var(--ink-border)">
|
|
<div class="p-num">03 —</div>
|
|
<div class="p-title">Wartbarkeit gehört dazu</div>
|
|
<p class="p-copy">Sauberer Code und vernünftige Strukturen sind für mich kein Extra, sondern Teil davon, ob sich eine Lösung gut anfühlt.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<!-- SKILLS -->
|
|
<div class="container">
|
|
<section id="skills">
|
|
<div class="reveal">
|
|
<div class="s-label">// Fähigkeiten</div>
|
|
<h2 class="s-title">Breit genug für ganze Projekte.<br><em>Präzise</em> genug für gute Details.</h2>
|
|
<p class="s-subtitle">Am liebsten arbeite ich dort, wo Oberfläche, Logik und Betrieb nicht getrennt betrachtet werden.</p>
|
|
</div>
|
|
<div class="skills-grid reveal">
|
|
<div class="skill">
|
|
<span class="skill-icon"></></span>
|
|
<div class="skill-name">Frontend & Interface Design</div>
|
|
<p class="skill-desc">Responsive Oberflächen mit klarer Struktur, guter Typografie und einem Anspruch daran, dass sich eine Seite bewusst gestaltet anfühlt.</p>
|
|
<div class="tags">
|
|
<span class="tag tag-gold">HTML / CSS</span>
|
|
<span class="tag tag-gold">JavaScript</span>
|
|
<span class="tag tag-gold">UI Systems</span>
|
|
<span class="tag tag-gold">Responsive</span>
|
|
</div>
|
|
</div>
|
|
<div class="skill" style="border-left:1px solid var(--ink-border)">
|
|
<span class="skill-icon">⬡</span>
|
|
<div class="skill-name">Backend & Infrastruktur</div>
|
|
<p class="skill-desc">Ich mag es, Services selbst zu verbinden, Datenflüsse zu ordnen und Hosting so aufzusetzen, dass man eine Anwendung nicht nur startet, sondern auch versteht.</p>
|
|
<div class="tags">
|
|
<span class="tag tag-teal">Docker</span>
|
|
<span class="tag tag-teal">Node.js</span>
|
|
<span class="tag tag-teal">REST APIs</span>
|
|
<span class="tag tag-teal">Caddy</span>
|
|
<span class="tag tag-teal">Forgejo</span>
|
|
</div>
|
|
</div>
|
|
<div class="skill" style="border-left:1px solid var(--ink-border)">
|
|
<span class="skill-icon">$_</span>
|
|
<div class="skill-name">Linux & Betrieb</div>
|
|
<p class="skill-desc">Server einrichten, absichern und sinnvoll betreiben. Gerade Self-Hosting und Deployments sind für mich der Bereich, in dem Technik besonders greifbar wird.</p>
|
|
<div class="tags">
|
|
<span class="tag tag-dim">Debian Linux</span>
|
|
<span class="tag tag-dim">SSH</span>
|
|
<span class="tag tag-dim">systemd</span>
|
|
<span class="tag tag-dim">ufw / fail2ban</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<!-- PROJECTS -->
|
|
<div class="container">
|
|
<section id="projects">
|
|
<div class="reveal">
|
|
<div class="s-label">// Portfolio</div>
|
|
<h2 class="s-title">Ausgewählte Arbeiten mit<br>technischer und <em>gestalterischer</em> Handschrift.</h2>
|
|
<p class="s-subtitle">Kein Produktkatalog, sondern ein Ausschnitt der Themen und Projektarten, an denen ich wirklich gern arbeite.</p>
|
|
</div>
|
|
<div class="reveal">
|
|
<div class="projects-grid">
|
|
<article class="project">
|
|
<div class="proj-top">
|
|
<div>
|
|
<div class="proj-eyebrow">Tooling</div>
|
|
<div class="proj-name">Developer Utilities</div>
|
|
</div>
|
|
<div class="proj-icon">⌘</div>
|
|
</div>
|
|
<p class="proj-desc">Kleinere Web-Tools, bei denen schnelle Nutzung und klare Interaktion wichtiger sind als große Verpackung. Gerade solche Projekte zeigen oft am besten, wie sorgfältig man in Details arbeitet.</p>
|
|
<div class="proj-tags">
|
|
<span class="tag tag-gold">Utility-first</span>
|
|
<span class="tag tag-dim">Schnelle Interaktion</span>
|
|
<span class="tag tag-dim">Klares UI</span>
|
|
</div>
|
|
<ul class="proj-pts">
|
|
<li>Zeigt, wie viel Wirkung in einer einfachen, gut gebauten Lösung stecken kann.</li>
|
|
<li>Gerade kleine Projekte zwingen dazu, auf unnötigen Ballast zu verzichten.</li>
|
|
</ul>
|
|
<div class="proj-foot">
|
|
<div class="proj-status"><span class="dot dot-wip"></span>In Entwicklung</div>
|
|
<span class="proj-link">Work in progress ↗</span>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="project">
|
|
<div class="proj-top">
|
|
<div>
|
|
<div class="proj-eyebrow">Backend</div>
|
|
<div class="proj-name">Custom Backend API</div>
|
|
</div>
|
|
<div class="proj-icon" style="font-size:0.65rem">API</div>
|
|
</div>
|
|
<p class="proj-desc">Eine eigene API-Struktur für persönliche Anwendungen, bei der ich Routing, Datenmodelle und Hosting bewusst selbst in der Hand behalte.</p>
|
|
<div class="proj-tags">
|
|
<span class="tag tag-teal">Routing</span>
|
|
<span class="tag tag-teal">Datenmodelle</span>
|
|
<span class="tag tag-dim">Eigenes Hosting</span>
|
|
</div>
|
|
<ul class="proj-pts">
|
|
<li>Hilft mir, technische Entscheidungen nicht nur zu übernehmen, sondern selbst zu durchdenken.</li>
|
|
<li>Verbindet die Anforderungen aus dem Frontend direkt mit einem sauberen Backend-Aufbau.</li>
|
|
</ul>
|
|
<div class="proj-foot">
|
|
<div class="proj-status"><span class="dot dot-wip"></span>In Entwicklung</div>
|
|
<span class="proj-link">Architekturaufbau ↗</span>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="project">
|
|
<div class="proj-top">
|
|
<div>
|
|
<div class="proj-eyebrow">Experiment</div>
|
|
<div class="proj-name">Lab / Playground</div>
|
|
</div>
|
|
<div class="proj-icon">△</div>
|
|
</div>
|
|
<p class="proj-desc">Ein Bereich für Prototypen, visuelle Versuche und technische Experimente. Dort probiere ich Ideen aus, bevor sie in etwas Größeres einfließen.</p>
|
|
<div class="proj-tags">
|
|
<span class="tag tag-dim">Prototyping</span>
|
|
<span class="tag tag-dim">Designstudien</span>
|
|
<span class="tag tag-gold">Lernsystem</span>
|
|
</div>
|
|
<ul class="proj-pts">
|
|
<li>Hier sieht man eher meinen Prozess als eine fertige Fassade.</li>
|
|
<li>Genau dort treffen Neugier, Stilgefühl und Technik am direktesten aufeinander.</li>
|
|
</ul>
|
|
<div class="proj-foot">
|
|
<div class="proj-status"><span class="dot dot-plan"></span>Geplant</div>
|
|
<span class="proj-link">In Vorbereitung ↗</span>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="project">
|
|
<div class="proj-top">
|
|
<div>
|
|
<div class="proj-eyebrow">Infrastruktur</div>
|
|
<div class="proj-name">noctura.dev Infrastruktur</div>
|
|
</div>
|
|
<div class="proj-icon">▣</div>
|
|
</div>
|
|
<p class="proj-desc">Ein selbst verwalteter VPS mit echten Services, Sicherheitsmaßnahmen und einer Umgebung, die mehr ist als nur Webspace für statische Dateien.</p>
|
|
<div class="proj-tags">
|
|
<span class="tag tag-dim">VPS</span>
|
|
<span class="tag tag-teal">Deployment</span>
|
|
<span class="tag tag-dim">Security</span>
|
|
</div>
|
|
<ul class="proj-pts">
|
|
<li>Zeigt, dass mich nicht nur die Oberfläche interessiert, sondern auch das, was dahinter zuverlässig laufen muss.</li>
|
|
<li>Für mich ist das einer der ehrlichsten Teile des Portfolios, weil hier viel Eigeninitiative drinsteckt.</li>
|
|
</ul>
|
|
<div class="proj-foot">
|
|
<div class="proj-status"><span class="dot dot-live"></span>Live</div>
|
|
<span class="proj-link">Produktiv im Einsatz ↗</span>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
<div class="proof-band">
|
|
<div class="proof-item">
|
|
<div class="proof-label">Warum diese Auswahl</div>
|
|
<p class="proof-copy">Die Projekte stehen nicht hier, um die Seite zu füllen, sondern weil sie etwas Reales über meine Arbeitsweise erzählen.</p>
|
|
</div>
|
|
<div class="proof-item" style="border-left:1px solid var(--ink-border)">
|
|
<div class="proof-label">Was man daran erkennt</div>
|
|
<p class="proof-copy">Jedes Projekt beleuchtet einen anderen Teil dessen, was mich an Webentwicklung wirklich interessiert.</p>
|
|
</div>
|
|
<div class="proof-item" style="border-left:1px solid var(--ink-border)">
|
|
<div class="proof-label">Worüber ich gern spreche</div>
|
|
<p class="proof-copy">Die Inhalte sind so gewählt, dass daraus echte Gespräche über Entscheidungen, Technik und Arbeitsweise entstehen können.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<!-- SNAPSHOT -->
|
|
<div class="container">
|
|
<section id="snapshot">
|
|
<div class="reveal">
|
|
<div class="s-label">// Profil</div>
|
|
<h2 class="s-title">Die kurze Version — für einen<br><em>schnellen Eindruck.</em></h2>
|
|
<p class="s-subtitle">Vier Punkte, die für mich den Kern ganz gut zusammenfassen.</p>
|
|
</div>
|
|
<div class="snapshot-grid reveal">
|
|
<div class="snap">
|
|
<div class="snap-kicker">Arbeitsweise</div>
|
|
<div class="snap-val">Hands-on</div>
|
|
<p class="snap-desc">Ich lerne am meisten über echte Umsetzung, sauberes Nacharbeiten und das Lösen konkreter Probleme.</p>
|
|
</div>
|
|
<div class="snap">
|
|
<div class="snap-kicker">Stärke</div>
|
|
<div class="snap-val">Frontend plus Betrieb</div>
|
|
<p class="snap-desc">Ich denke ungern nur in einzelnen Screens, sondern lieber in vollständigen Lösungen vom Interface bis zum Deployment.</p>
|
|
</div>
|
|
<div class="snap">
|
|
<div class="snap-kicker">Motivation</div>
|
|
<div class="snap-val">Systeme wirklich verstehen</div>
|
|
<p class="snap-desc">Am spannendsten ist Technik für mich dann, wenn ich sie selbst aufbauen, anpassen und betreiben kann.</p>
|
|
</div>
|
|
<div class="snap">
|
|
<div class="snap-kicker">Eindruck</div>
|
|
<div class="snap-val">Substanz vor Buzzwords</div>
|
|
<p class="snap-desc">Mir ist wichtiger, nachvollziehbar zu wirken als besonders laut oder überinszeniert.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<!-- CONTACT -->
|
|
<div class="container">
|
|
<section id="contact">
|
|
<div class="contact-box reveal">
|
|
<h2>Kontakt für <em>Bewerbungen,</em><br>Zusammenarbeit und technische Gespräche</h2>
|
|
<p>Wenn du jemanden suchst, der Gestaltung ernst nimmt, technisch sauber arbeitet und sich auch für das Dahinter interessiert, kannst du mir gern direkt schreiben.</p>
|
|
<a href="mailto:kontakt@noctura.dev" class="btn btn-gold">kontakt@noctura.dev</a>
|
|
<span class="contact-email">noctura.dev — persönliches Portfolio</span>
|
|
</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>
|
|
// Particle canvas
|
|
(function(){
|
|
const canvas=document.getElementById('c');
|
|
const ctx=canvas.getContext('2d');
|
|
let W,H,stars=[];
|
|
const rm=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
function init(){
|
|
W=canvas.width=window.innerWidth;
|
|
H=canvas.height=window.innerHeight;
|
|
const n=Math.floor((W*H)/14000);
|
|
stars=Array.from({length:n},()=>({
|
|
x:Math.random()*W,
|
|
y:Math.random()*H,
|
|
r:Math.random()*1.1+0.15,
|
|
o:Math.random()*0.45+0.08,
|
|
s:Math.random()*0.4+0.05,
|
|
t:Math.random()*Math.PI*2
|
|
}));
|
|
}
|
|
|
|
function draw(){
|
|
ctx.clearRect(0,0,W,H);
|
|
stars.forEach(s=>{
|
|
s.t+=0.007*s.s;
|
|
const op=s.o*(0.55+0.45*Math.sin(s.t));
|
|
ctx.beginPath();
|
|
ctx.arc(s.x,s.y,s.r,0,Math.PI*2);
|
|
ctx.fillStyle=`rgba(240,237,232,${op})`;
|
|
ctx.fill();
|
|
});
|
|
requestAnimationFrame(draw);
|
|
}
|
|
|
|
window.addEventListener('resize',init);
|
|
init();
|
|
if(!rm) draw();
|
|
})();
|
|
|
|
// Reveal on scroll
|
|
(function(){
|
|
const els=document.querySelectorAll('.reveal');
|
|
const rm=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
if(rm){els.forEach(e=>e.classList.add('in'));return;}
|
|
const io=new IntersectionObserver((entries)=>{
|
|
entries.forEach((e,i)=>{
|
|
if(e.isIntersecting){
|
|
setTimeout(()=>e.target.classList.add('in'),i*80);
|
|
io.unobserve(e.target);
|
|
}
|
|
});
|
|
},{threshold:0.1});
|
|
els.forEach(e=>io.observe(e));
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|