Self-Hosting Everything: A Complete Guide
+How I migrated away from cloud services and built a fully self-hosted infrastructure stack...
+ +diff --git a/README.md b/README.md index d54f8d9..d39a697 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,78 @@ -# jaeswift-website +# JAESWIFT.XYZ -Personal website for jaeswift.xyz - Sci-fi dashboard aesthetic \ No newline at end of file +> Sci-fi dashboard-inspired personal website + + + + +## Overview + +A cyberpunk/sci-fi themed personal website inspired by satellite monitoring dashboards. Built with vanilla HTML, CSS, and JavaScript — no frameworks, no bloat. + +## Features + +- **HUD-style navigation** with dropdown menus and live clock +- **Particle system** with mouse interaction and connection lines +- **Glitch text effect** on hero title +- **Typing animation** cycling through descriptions +- **Scroll-reveal animations** for content sections +- **Animated skill bars** with glow effects +- **Live terminal emulator** with typed commands +- **Panel hover glow tracking** (follows cursor) +- **Scanline overlay** and grid background +- **HUD data flickers** for authentic dashboard feel +- **Signal strength animation** in footer +- **Fully responsive** — mobile hamburger menu with accordion dropdowns + +## Sections + +| # | Section | Description | +|---|---------|-------------| +| 00 | Hero | Animated HUD frame with glitch title, typing subtitle, status readouts | +| 01 | About | Operator profile panel + animated skill matrix bars | +| 02 | Blog | Card grid for blog posts with hover animations | +| 03 | Development | Project cards with tech tags and status indicators | +| 04 | Links | External links grid (Gitea, GitLab, Reddit, Email) | +| 05 | Contact | Transmission form + signal info + live terminal emulator | + +## Tech Stack + +- **HTML5** — Semantic markup +- **CSS3** — Custom properties, grid, flexbox, animations, backdrop-filter +- **Vanilla JS** — Particle system, IntersectionObserver, typing effect +- **Google Fonts** — JetBrains Mono, Orbitron, Share Tech Mono + +## Palette + +| Colour | Hex | Usage | +|--------|-----|-------| +| Background | `#060608` | Primary background | +| Panel | `#0c1018` | Card/panel backgrounds | +| Accent | `#00ffc8` | Primary accent (cyan/teal) | +| Text | `#c8d6e5` | Primary text | +| Muted | `#5a6a7a` | Secondary text | +| Border | `#1a2a3a` | Panel borders | +| Danger | `#ff3a5c` | Glitch/error accent | + +## Local Development + +```bash +# Clone +git clone https://git.jaeswift.xyz/jae/jaeswift-website.git +cd jaeswift-website + +# Serve (any static server works) +python3 -m http.server 8080 +# or +npx serve . +``` + +Open `http://localhost:8080` in your browser. + +## Deployment + +Static files — deploy anywhere: Nginx, Apache, Caddy, Netlify, Cloudflare Pages, etc. + +## License + +© 2026 jae — All rights reserved. diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..9f48bc4 --- /dev/null +++ b/css/style.css @@ -0,0 +1,1135 @@ +/* =================================================== + JAESWIFT.XYZ — Sci-Fi Dashboard Theme + Palette: #0a0a0f (bg), #00ffc8 (accent), #0d1117 (panels) + =================================================== */ + +/* --- Reset & Base --- */ +*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } + +:root { + --bg-primary: #060608; + --bg-secondary: #0a0e14; + --bg-panel: #0c1018; + --bg-panel-hover: #101820; + --accent: #00ffc8; + --accent-dim: #00ffc840; + --accent-glow: #00ffc880; + --accent-subtle: #00ffc815; + --text-primary: #c8d6e5; + --text-secondary: #5a6a7a; + --text-muted: #2a3a4a; + --border: #1a2a3a; + --border-accent: #00ffc830; + --danger: #ff3a5c; + --warning: #ffaa00; + --font-mono: 'JetBrains Mono', 'Share Tech Mono', 'Courier New', monospace; + --font-display: 'Orbitron', sans-serif; + --nav-height: 60px; +} + +html { + scroll-behavior: smooth; + scrollbar-width: thin; + scrollbar-color: var(--accent-dim) var(--bg-primary); +} + +html::-webkit-scrollbar { width: 6px; } +html::-webkit-scrollbar-track { background: var(--bg-primary); } +html::-webkit-scrollbar-thumb { background: var(--accent-dim); border-radius: 3px; } +html::-webkit-scrollbar-thumb:hover { background: var(--accent); } + +body { + font-family: var(--font-mono); + background: var(--bg-primary); + color: var(--text-primary); + line-height: 1.6; + overflow-x: hidden; + -webkit-font-smoothing: antialiased; +} + +a { color: var(--accent); text-decoration: none; transition: all 0.3s ease; } +a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); } + +.accent { color: var(--accent); } + +/* --- Scanline Overlay --- */ +.scanline-overlay { + position: fixed; + top: 0; left: 0; + width: 100%; height: 100%; + pointer-events: none; + z-index: 9999; + background: repeating-linear-gradient( + 0deg, + transparent, + transparent 2px, + rgba(0, 255, 200, 0.008) 2px, + rgba(0, 255, 200, 0.008) 4px + ); +} + +/* --- Grid Background --- */ +.grid-bg { + position: fixed; + top: 0; left: 0; + width: 100%; height: 100%; + pointer-events: none; + z-index: -2; + background-image: + linear-gradient(var(--accent-subtle) 1px, transparent 1px), + linear-gradient(90deg, var(--accent-subtle) 1px, transparent 1px); + background-size: 60px 60px; + opacity: 0.3; +} + +/* --- Particle Canvas --- */ +#particles { + position: fixed; + top: 0; left: 0; + width: 100%; height: 100%; + pointer-events: none; + z-index: -1; +} + +/* === NAVIGATION === */ +.nav-main { + position: fixed; + top: 0; left: 0; + width: 100%; + height: var(--nav-height); + background: rgba(6, 6, 8, 0.92); + backdrop-filter: blur(20px); + border-bottom: 1px solid var(--border); + z-index: 1000; + transition: all 0.3s ease; +} + +.nav-main.scrolled { + background: rgba(6, 6, 8, 0.98); + border-bottom-color: var(--accent-dim); + box-shadow: 0 4px 30px rgba(0, 255, 200, 0.05); +} + +.nav-container { + max-width: 1400px; + margin: 0 auto; + padding: 0 2rem; + height: 100%; + display: flex; + align-items: center; + justify-content: space-between; +} + +.nav-logo { + display: flex; + align-items: center; + gap: 0.15rem; + font-family: var(--font-display); + font-size: 0.9rem; + font-weight: 700; + color: var(--text-primary); + letter-spacing: 2px; + text-decoration: none; +} + +.nav-logo:hover { color: var(--text-primary); text-shadow: none; } +.logo-bracket { color: var(--accent); font-weight: 300; } +.logo-accent { color: var(--accent); } +.logo-status { + font-size: 0.55rem; + color: var(--accent); + margin-left: 0.75rem; + animation: pulse-status 2s ease-in-out infinite; +} + +@keyframes pulse-status { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.4; } +} + +/* Nav Menu */ +.nav-menu { + display: flex; + list-style: none; + gap: 0; + align-items: center; +} + +.nav-item { + position: relative; +} + +.nav-link { + display: block; + padding: 0 1.25rem; + height: var(--nav-height); + line-height: var(--nav-height); + font-family: var(--font-display); + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 2px; + color: var(--text-secondary); + transition: all 0.3s ease; + position: relative; +} + +.nav-link::after { + content: ''; + position: absolute; + bottom: 0; left: 50%; + transform: translateX(-50%); + width: 0; + height: 2px; + background: var(--accent); + transition: width 0.3s ease; + box-shadow: 0 0 10px var(--accent-glow); +} + +.nav-link:hover, .nav-link.active { + color: var(--accent); + text-shadow: 0 0 15px var(--accent-glow); +} + +.nav-link:hover::after, .nav-link.active::after { + width: 100%; +} + +/* Dropdown */ +.dropdown { + position: absolute; + top: 100%; + left: 0; + min-width: 200px; + background: rgba(10, 14, 20, 0.98); + border: 1px solid var(--border); + border-top: 2px solid var(--accent); + list-style: none; + opacity: 0; + visibility: hidden; + transform: translateY(-10px); + transition: all 0.3s ease; + backdrop-filter: blur(20px); + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); +} + +.nav-item:hover > .dropdown { + opacity: 1; + visibility: visible; + transform: translateY(0); +} + +.dropdown li a { + display: block; + padding: 0.75rem 1.25rem; + font-size: 0.7rem; + font-family: var(--font-mono); + color: var(--text-secondary); + letter-spacing: 1px; + border-bottom: 1px solid var(--border); + transition: all 0.2s ease; +} + +.dropdown li:last-child a { border-bottom: none; } + +.dropdown li a:hover { + background: var(--accent-subtle); + color: var(--accent); + padding-left: 1.5rem; + text-shadow: 0 0 10px var(--accent-glow); +} + +.dropdown li a::before { + content: '> '; + opacity: 0; + transition: opacity 0.2s ease; +} + +.dropdown li a:hover::before { opacity: 1; } + +/* Nav Status */ +.nav-status { + display: flex; + align-items: center; + gap: 1rem; + font-size: 0.65rem; + color: var(--text-secondary); +} + +.nav-time { + font-family: var(--font-mono); + color: var(--accent); + letter-spacing: 2px; +} + +.nav-signal { + color: var(--accent); + letter-spacing: 1px; + font-size: 0.55rem; +} + +/* Mobile Toggle */ +.nav-toggle { + display: none; + flex-direction: column; + gap: 5px; + background: none; + border: none; + cursor: pointer; + padding: 5px; +} + +.nav-toggle span { + display: block; + width: 24px; + height: 2px; + background: var(--accent); + transition: all 0.3s ease; +} + +/* === HERO SECTION === */ +.hero { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: calc(var(--nav-height) + 2rem) 2rem 2rem; + position: relative; +} + +.hero-hud { + position: relative; + width: 100%; + max-width: 800px; + padding: 4rem; + border: 1px solid var(--border); + background: rgba(10, 14, 20, 0.5); +} + +/* HUD Corners */ +.hud-corner { + position: absolute; + width: 20px; + height: 20px; +} + +.hud-tl { top: -1px; left: -1px; border-top: 2px solid var(--accent); border-left: 2px solid var(--accent); } +.hud-tr { top: -1px; right: -1px; border-top: 2px solid var(--accent); border-right: 2px solid var(--accent); } +.hud-bl { bottom: -1px; left: -1px; border-bottom: 2px solid var(--accent); border-left: 2px solid var(--accent); } +.hud-br { bottom: -1px; right: -1px; border-bottom: 2px solid var(--accent); border-right: 2px solid var(--accent); } + +.hero-content { + text-align: center; +} + +.hero-label { + font-family: var(--font-mono); + font-size: 0.65rem; + letter-spacing: 4px; + color: var(--text-secondary); + margin-bottom: 1.5rem; + animation: fadeInDown 1s ease 0.2s both; +} + +/* Glitch Effect */ +.hero-title { + font-family: var(--font-display); + font-size: clamp(2.5rem, 8vw, 5rem); + font-weight: 900; + letter-spacing: 8px; + margin-bottom: 1.5rem; + animation: fadeInUp 1s ease 0.4s both; +} + +.glitch { + position: relative; + color: var(--text-primary); + display: inline-block; +} + +.glitch::before, +.glitch::after { + content: attr(data-text); + position: absolute; + top: 0; left: 0; + width: 100%; height: 100%; + opacity: 0; +} + +.glitch::before { + color: var(--accent); + animation: glitch-1 4s infinite linear; +} + +.glitch::after { + color: var(--danger); + animation: glitch-2 4s infinite linear; +} + +@keyframes glitch-1 { + 0%, 90%, 100% { opacity: 0; transform: none; } + 91% { opacity: 0.8; transform: translate(-2px, -1px); clip-path: inset(20% 0 60% 0); } + 93% { opacity: 0.8; transform: translate(2px, 1px); clip-path: inset(50% 0 10% 0); } + 95% { opacity: 0; } +} + +@keyframes glitch-2 { + 0%, 92%, 100% { opacity: 0; transform: none; } + 93% { opacity: 0.6; transform: translate(2px, 2px); clip-path: inset(10% 0 70% 0); } + 95% { opacity: 0.6; transform: translate(-1px, -2px); clip-path: inset(40% 0 20% 0); } + 97% { opacity: 0; } +} + +/* Typing Effect */ +.hero-subtitle { + font-family: var(--font-mono); + font-size: 1rem; + color: var(--accent); + margin-bottom: 3rem; + animation: fadeIn 1s ease 0.8s both; +} + +.typing-prefix { color: var(--text-secondary); } +.typing-cursor { + animation: blink-cursor 0.8s step-end infinite; + color: var(--accent); +} + +@keyframes blink-cursor { + 0%, 100% { opacity: 1; } + 50% { opacity: 0; } +} + +/* Hero Stats */ +.hero-stats { + display: flex; + justify-content: center; + gap: 3rem; + animation: fadeInUp 1s ease 1s both; +} + +.stat-item { + text-align: center; +} + +.stat-label { + display: block; + font-size: 0.55rem; + letter-spacing: 3px; + color: var(--text-secondary); + margin-bottom: 0.4rem; +} + +.stat-value { + font-size: 0.75rem; + letter-spacing: 1px; + color: var(--text-primary); +} + +.stat-online { color: var(--accent); } + +/* Scan Line Animation */ +.scan-line { + position: absolute; + top: 0; left: 0; + width: 100%; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent), transparent); + opacity: 0.6; + animation: scan 4s linear infinite; +} + +@keyframes scan { + 0% { top: 0; opacity: 0; } + 10% { opacity: 0.6; } + 90% { opacity: 0.6; } + 100% { top: 100%; opacity: 0; } +} + +/* === SECTIONS === */ +.section { + padding: 6rem 2rem; + position: relative; +} + +.section-container { + max-width: 1200px; + margin: 0 auto; +} + +.section-header { + display: flex; + align-items: center; + gap: 1.5rem; + margin-bottom: 3rem; +} + +.section-tag { + font-family: var(--font-display); + font-size: 0.7rem; + color: var(--accent); + letter-spacing: 2px; + padding: 0.3rem 0.6rem; + border: 1px solid var(--accent-dim); +} + +.section-title { + font-family: var(--font-display); + font-size: clamp(1.2rem, 3vw, 1.6rem); + font-weight: 700; + letter-spacing: 4px; + color: var(--text-primary); + white-space: nowrap; +} + +.section-line { + flex: 1; + height: 1px; + background: linear-gradient(90deg, var(--border-accent), transparent); +} + +/* === PANELS === */ +.panel { + background: var(--bg-panel); + border: 1px solid var(--border); + position: relative; + overflow: hidden; + transition: all 0.4s ease; +} + +.panel::before { + content: ''; + position: absolute; + top: 0; left: 0; + width: 100%; height: 100%; + background: linear-gradient(135deg, var(--accent-subtle), transparent); + opacity: 0; + transition: opacity 0.4s ease; +} + +.panel:hover { border-color: var(--accent-dim); } +.panel:hover::before { opacity: 1; } + +.panel-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 1.25rem; + border-bottom: 1px solid var(--border); + background: rgba(0, 255, 200, 0.02); +} + +.panel-title { + font-family: var(--font-display); + font-size: 0.65rem; + letter-spacing: 2px; + color: var(--text-secondary); +} + +.panel-icon { + color: var(--accent); + font-size: 0.8rem; +} + +.panel-content { + padding: 1.5rem 1.25rem; +} + +.panel-content p { + font-size: 0.8rem; + color: var(--text-secondary); + margin-bottom: 1rem; + line-height: 1.8; +} + +/* Panel Data Rows */ +.panel-data { margin-top: 1.5rem; } + +.data-row { + display: flex; + justify-content: space-between; + padding: 0.6rem 0; + border-bottom: 1px solid var(--border); + font-size: 0.7rem; +} + +.data-key { color: var(--text-secondary); letter-spacing: 2px; } +.data-val { color: var(--accent); font-weight: 500; } + +/* === ABOUT: Panels Grid === */ +.panels-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1.5rem; +} + +/* === SKILL BARS === */ +.skill-bar { + display: grid; + grid-template-columns: 140px 1fr 40px; + align-items: center; + gap: 1rem; + margin-bottom: 1rem; +} + +.skill-name { + font-size: 0.6rem; + letter-spacing: 1px; + color: var(--text-secondary); +} + +.bar-track { + height: 4px; + background: var(--bg-primary); + border-radius: 2px; + overflow: hidden; + position: relative; +} + +.bar-fill { + height: 100%; + width: 0; + background: linear-gradient(90deg, var(--accent), var(--accent-dim)); + border-radius: 2px; + transition: width 1.5s ease; + position: relative; + box-shadow: 0 0 10px var(--accent-glow); +} + +.bar-fill.animated { width: var(--target-width); } + +.skill-pct { + font-size: 0.65rem; + color: var(--accent); + text-align: right; +} + +/* === BLOG GRID === */ +.blog-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1.5rem; +} + +.blog-card { + background: var(--bg-panel); + border: 1px solid var(--border); + padding: 1.5rem; + transition: all 0.4s ease; + position: relative; + overflow: hidden; +} + +.blog-card::after { + content: ''; + position: absolute; + top: 0; left: 0; + width: 100%; height: 2px; + background: var(--accent); + transform: scaleX(0); + transform-origin: left; + transition: transform 0.4s ease; +} + +.blog-card:hover { + border-color: var(--accent-dim); + transform: translateY(-4px); + box-shadow: 0 8px 30px rgba(0, 255, 200, 0.08); +} + +.blog-card:hover::after { transform: scaleX(1); } + +.blog-card-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +.blog-date { + font-size: 0.6rem; + color: var(--text-secondary); + letter-spacing: 2px; +} + +.blog-tag { + font-size: 0.55rem; + letter-spacing: 1px; + color: var(--accent); + padding: 0.2rem 0.5rem; + border: 1px solid var(--accent-dim); +} + +.blog-title { + font-family: var(--font-mono); + font-size: 0.9rem; + font-weight: 600; + color: var(--text-primary); + margin-bottom: 0.75rem; + line-height: 1.4; +} + +.blog-excerpt { + font-size: 0.75rem; + color: var(--text-secondary); + line-height: 1.7; + margin-bottom: 1.5rem; +} + +.blog-footer { + display: flex; + justify-content: space-between; + align-items: center; + padding-top: 1rem; + border-top: 1px solid var(--border); +} + +.blog-read-time { + font-size: 0.6rem; + color: var(--text-muted); +} + +.blog-link { + font-size: 0.65rem; + font-family: var(--font-display); + letter-spacing: 2px; + color: var(--accent); +} + +.blog-link:hover { + text-shadow: 0 0 15px var(--accent-glow); +} + +/* === DEVELOPMENT GRID === */ +.dev-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1.5rem; +} + +.dev-card { + background: var(--bg-panel); + border: 1px solid var(--border); + padding: 1.75rem; + transition: all 0.4s ease; + position: relative; +} + +.dev-card::before { + content: ''; + position: absolute; + top: 0; left: 0; + width: 3px; height: 0; + background: var(--accent); + transition: height 0.4s ease; +} + +.dev-card:hover { + border-color: var(--accent-dim); + transform: translateY(-4px); + box-shadow: 0 8px 30px rgba(0, 255, 200, 0.06); +} + +.dev-card:hover::before { height: 100%; } + +.dev-card-top { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.25rem; +} + +.dev-icon { + font-size: 1.5rem; + color: var(--accent); +} + +.dev-status { + font-size: 0.55rem; + letter-spacing: 1px; + color: var(--accent); +} + +.status-dev { color: var(--warning); } + +.dev-title { + font-family: var(--font-display); + font-size: 0.85rem; + font-weight: 600; + letter-spacing: 1px; + color: var(--text-primary); + margin-bottom: 0.75rem; +} + +.dev-desc { + font-size: 0.75rem; + color: var(--text-secondary); + line-height: 1.7; + margin-bottom: 1.25rem; +} + +.dev-tech { + display: flex; + gap: 0.5rem; + flex-wrap: wrap; + margin-bottom: 1.25rem; +} + +.tech-tag { + font-size: 0.55rem; + letter-spacing: 1px; + padding: 0.25rem 0.6rem; + border: 1px solid var(--border); + color: var(--text-secondary); + transition: all 0.3s ease; +} + +.dev-card:hover .tech-tag { + border-color: var(--accent-dim); + color: var(--accent); +} + +.dev-link { + font-size: 0.65rem; + font-family: var(--font-display); + letter-spacing: 2px; +} + +/* === LINKS GRID === */ +.links-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1rem; +} + +.link-card { + display: flex; + align-items: center; + gap: 1.25rem; + padding: 1.5rem; + background: var(--bg-panel); + border: 1px solid var(--border); + transition: all 0.4s ease; + text-decoration: none; +} + +.link-card:hover { + border-color: var(--accent-dim); + background: var(--bg-panel-hover); + transform: translateX(8px); + text-shadow: none; +} + +.link-icon { + font-size: 1.5rem; + color: var(--accent); + width: 40px; + text-align: center; +} + +.link-info { flex: 1; } + +.link-name { + display: block; + font-family: var(--font-display); + font-size: 0.7rem; + letter-spacing: 2px; + color: var(--text-primary); + margin-bottom: 0.2rem; +} + +.link-url { + font-size: 0.65rem; + color: var(--text-secondary); +} + +.link-arrow { + font-size: 1.2rem; + color: var(--text-muted); + transition: all 0.3s ease; +} + +.link-card:hover .link-arrow { + color: var(--accent); + transform: translateX(4px); +} + +/* === CONTACT === */ +.contact-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1.5rem; +} + +.contact-info { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +/* Form */ +.contact-form { + padding: 1.5rem 1.25rem; +} + +.form-group { margin-bottom: 1.25rem; } + +.form-label { + display: block; + font-size: 0.55rem; + letter-spacing: 2px; + color: var(--text-secondary); + margin-bottom: 0.5rem; +} + +.form-input { + width: 100%; + padding: 0.75rem 1rem; + background: var(--bg-primary); + border: 1px solid var(--border); + color: var(--text-primary); + font-family: var(--font-mono); + font-size: 0.75rem; + transition: all 0.3s ease; + outline: none; +} + +.form-input:focus { + border-color: var(--accent); + box-shadow: 0 0 0 1px var(--accent-dim), 0 0 20px rgba(0, 255, 200, 0.05); +} + +.form-input::placeholder { color: var(--text-muted); } + +.form-textarea { resize: vertical; min-height: 120px; } + +.form-submit { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.85rem 2rem; + background: transparent; + border: 1px solid var(--accent); + color: var(--accent); + font-family: var(--font-display); + font-size: 0.7rem; + letter-spacing: 3px; + cursor: pointer; + transition: all 0.3s ease; + position: relative; + overflow: hidden; +} + +.form-submit::before { + content: ''; + position: absolute; + top: 0; left: -100%; + width: 100%; height: 100%; + background: var(--accent); + transition: left 0.3s ease; + z-index: -1; +} + +.form-submit:hover { + color: var(--bg-primary); + box-shadow: 0 0 30px var(--accent-glow); +} + +.form-submit:hover::before { left: 0; } + +.submit-icon { + font-size: 0.6rem; + transition: transform 0.3s ease; +} + +.form-submit:hover .submit-icon { transform: translateX(4px); } + +/* Info Blocks */ +.info-block { + padding: 1rem 0; + border-bottom: 1px solid var(--border); +} + +.info-block:last-child { border-bottom: none; } + +.info-label { + display: block; + font-size: 0.55rem; + letter-spacing: 2px; + color: var(--text-muted); + margin-bottom: 0.3rem; +} + +.info-value { + font-size: 0.8rem; + color: var(--accent); +} + +/* Terminal */ +.terminal-panel { + flex: 1; +} + +.terminal-content { + padding: 1rem 1.25rem; + font-size: 0.7rem; + line-height: 1.8; +} + +.term-line { white-space: nowrap; } +.term-prompt { color: var(--accent); } +.term-cmd { color: var(--text-primary); } +.term-output { color: var(--text-secondary); padding-left: 0; } +.term-cursor { animation: blink-cursor 0.8s step-end infinite; color: var(--accent); } + +/* === FOOTER === */ +.footer { + padding: 2rem; + border-top: 1px solid var(--border); + background: rgba(6, 6, 8, 0.8); +} + +.footer-container { + max-width: 1200px; + margin: 0 auto; + display: flex; + justify-content: space-between; + align-items: center; +} + +.footer-left, .footer-right { + display: flex; + align-items: center; + gap: 2rem; +} + +.footer-logo { + font-family: var(--font-display); + font-size: 0.75rem; + letter-spacing: 2px; + color: var(--text-primary); +} + +.footer-copy { + font-size: 0.6rem; + color: var(--text-muted); + letter-spacing: 1px; +} + +.footer-coords { + font-size: 0.6rem; + color: var(--text-muted); + letter-spacing: 1px; +} + +.footer-signal { + font-size: 0.6rem; + color: var(--accent); + letter-spacing: 1px; +} + +.footer-bar { + margin-top: 1.5rem; + height: 1px; + background: linear-gradient(90deg, transparent, var(--accent-dim), transparent); +} + +/* === ANIMATIONS === */ +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes fadeInUp { + from { opacity: 0; transform: translateY(30px); } + to { opacity: 1; transform: translateY(0); } +} + +@keyframes fadeInDown { + from { opacity: 0; transform: translateY(-20px); } + to { opacity: 1; transform: translateY(0); } +} + +/* Scroll reveal */ +[data-animate] { + opacity: 0; + transform: translateY(40px); + transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1); +} + +[data-animate].visible { + opacity: 1; + transform: translateY(0); +} + +/* === RESPONSIVE === */ +@media (max-width: 1024px) { + .blog-grid, .dev-grid { grid-template-columns: repeat(2, 1fr); } + .panels-grid { grid-template-columns: 1fr; } + .contact-grid { grid-template-columns: 1fr; } +} + +@media (max-width: 768px) { + .nav-toggle { display: flex; } + .nav-status { display: none; } + + .nav-menu { + position: fixed; + top: var(--nav-height); + left: 0; + width: 100%; + flex-direction: column; + background: rgba(6, 6, 8, 0.98); + backdrop-filter: blur(20px); + border-bottom: 1px solid var(--border); + padding: 1rem 0; + transform: translateY(-100%); + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + } + + .nav-menu.active { + transform: translateY(0); + opacity: 1; + visibility: visible; + } + + .nav-link { + height: auto; + line-height: 1; + padding: 1rem 2rem; + } + + .nav-link::after { display: none; } + + .dropdown { + position: static; + border: none; + border-top: none; + background: rgba(0, 0, 0, 0.3); + max-height: 0; + overflow: hidden; + opacity: 1; + visibility: visible; + transform: none; + transition: max-height 0.3s ease; + } + + .nav-item.active .dropdown { max-height: 300px; } + + .hero-hud { padding: 2rem; } + .hero-stats { flex-direction: column; gap: 1rem; } + .blog-grid, .dev-grid { grid-template-columns: 1fr; } + .links-grid { grid-template-columns: 1fr; } + .skill-bar { grid-template-columns: 1fr; gap: 0.3rem; } + .skill-name { margin-bottom: 0; } + .section { padding: 4rem 1rem; } + .footer-container { flex-direction: column; gap: 1rem; text-align: center; } + .footer-left, .footer-right { flex-direction: column; gap: 0.5rem; } +} + +@media (max-width: 480px) { + .hero-title { letter-spacing: 4px; } + .section-header { flex-direction: column; align-items: flex-start; gap: 0.75rem; } + .section-line { display: none; } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..dae07b8 --- /dev/null +++ b/index.html @@ -0,0 +1,443 @@ + + +
+ + +Developer, tinkerer, and digital architect. I build things that live on the internet — from self-hosted infrastructure to custom web applications.
+Passionate about open source, cybersecurity, and making technology work the way it should.
+How I migrated away from cloud services and built a fully self-hosted infrastructure stack...
+ +Essential security configurations that most tutorials skip — from kernel parameters to network isolation...
+ +My journey deploying Agent Zero and customising autonomous AI assistants for real-world tasks...
+ +Custom AI agent framework deployment with autonomous task execution capabilities.
+Self-hosted services including Gitea, monitoring, reverse proxies, and automated deployments.
+This website — a sci-fi dashboard-inspired personal hub with custom animations and HUD elements.
+