2329 lines
89 KiB
HTML
2329 lines
89 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>NX9 — Next Generation 9 | Software people can own, understand, and control</title>
|
||
<meta
|
||
name="description"
|
||
content="NX9 is a philosophy-driven ecosystem of self-hosted, privacy-first Rust software by Sunil Thakare. No telemetry. No vendor lock-in. Software people can own, understand, and control."
|
||
/>
|
||
<meta name="color-scheme" content="light dark" />
|
||
|
||
<!-- Favicons & App Icons -->
|
||
<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png" />
|
||
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png" />
|
||
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png" />
|
||
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png" />
|
||
<link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png" />
|
||
<link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png" />
|
||
<link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png" />
|
||
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png" />
|
||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png" />
|
||
<link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png" />
|
||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png" />
|
||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||
<link rel="manifest" href="/manifest.json" />
|
||
<meta name="theme-color" content="#020617" />
|
||
|
||
<style>
|
||
/* == 1. DESIGN TOKENS == */
|
||
:root {
|
||
--bg: #ffffff;
|
||
--bg-raised: #ffffff;
|
||
--surface: #f5f6f9;
|
||
--surface-hover: #eceff4;
|
||
--border: #e1e4ea;
|
||
--border-strong: #cbd0da;
|
||
--text: #12151a;
|
||
--text-secondary: #4b5563;
|
||
--text-muted: #6b7280;
|
||
--accent: #6d5df6;
|
||
--accent-strong: #5643e0;
|
||
--accent-soft: #eeecff;
|
||
--accent-contrast: #ffffff;
|
||
--dot: rgba(109, 93, 246, 0.14);
|
||
--line: rgba(109, 93, 246, 0.08);
|
||
--shadow: 0 1px 2px rgba(16, 20, 26, 0.04), 0 4px 16px rgba(16, 20, 26, 0.05);
|
||
--shadow-hover: 0 4px 10px rgba(109, 93, 246, 0.12), 0 16px 36px rgba(16, 20, 26, 0.1);
|
||
--radius: 10px;
|
||
--radius-sm: 6px;
|
||
--font-ui: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell,
|
||
sans-serif;
|
||
--font-mono: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
|
||
--content-max: 1180px;
|
||
--transition-theme: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
|
||
|
||
/* Gradient palette — reused across icons, borders and glow shadows */
|
||
--grad-1: linear-gradient(135deg, #7c5cf9, #b18bfa);
|
||
--grad-2: linear-gradient(135deg, #06b6d4, #5eead4);
|
||
--grad-3: linear-gradient(135deg, #f59e0b, #fb923c);
|
||
--grad-4: linear-gradient(135deg, #ec4899, #fb7185);
|
||
--grad-5: linear-gradient(135deg, #10b981, #6ee7b7);
|
||
--grad-6: linear-gradient(135deg, #3b82f6, #7dd3fc);
|
||
--grad-7: linear-gradient(135deg, #ef4444, #f97316);
|
||
--glow-1: rgba(124, 92, 249, 0.35);
|
||
--glow-2: rgba(6, 182, 212, 0.35);
|
||
--glow-3: rgba(245, 158, 11, 0.35);
|
||
--glow-4: rgba(236, 72, 153, 0.35);
|
||
--glow-5: rgba(16, 185, 129, 0.35);
|
||
--glow-6: rgba(59, 130, 246, 0.35);
|
||
--glow-7: rgba(239, 68, 68, 0.35);
|
||
}
|
||
|
||
html[data-theme="dark"] {
|
||
--bg: #0a0c10;
|
||
--bg-raised: #12151b;
|
||
--surface: #161a21;
|
||
--surface-hover: #1d222b;
|
||
--border: #262c37;
|
||
--border-strong: #363e4b;
|
||
--text: #eceef2;
|
||
--text-secondary: #a7aec0;
|
||
--text-muted: #7c8497;
|
||
--accent: #9d8bff;
|
||
--accent-strong: #b6a7ff;
|
||
--accent-soft: #1c1a33;
|
||
--accent-contrast: #0a0c10;
|
||
--dot: rgba(157, 139, 255, 0.16);
|
||
--line: rgba(157, 139, 255, 0.08);
|
||
--shadow: 0 1px 2px rgba(0, 0, 0, 0.35), 0 4px 20px rgba(0, 0, 0, 0.4);
|
||
--shadow-hover: 0 4px 14px rgba(157, 139, 255, 0.18), 0 18px 40px rgba(0, 0, 0, 0.45);
|
||
}
|
||
|
||
/* == 2. RESET & BASE == */
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
box-sizing: border-box;
|
||
}
|
||
html {
|
||
scroll-behavior: smooth;
|
||
-webkit-text-size-adjust: 100%;
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
html {
|
||
scroll-behavior: auto;
|
||
}
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
animation-duration: 0.001ms !important;
|
||
animation-iteration-count: 1 !important;
|
||
transition-duration: 0.001ms !important;
|
||
scroll-behavior: auto !important;
|
||
}
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
font-family: var(--font-ui);
|
||
background-color: var(--bg);
|
||
color: var(--text);
|
||
line-height: 1.6;
|
||
transition: var(--transition-theme);
|
||
background-image: linear-gradient(var(--line) 1px, transparent 1px),
|
||
linear-gradient(90deg, var(--line) 1px, transparent 1px),
|
||
radial-gradient(var(--dot) 1px, transparent 1px);
|
||
background-size:
|
||
64px 64px,
|
||
64px 64px,
|
||
16px 16px;
|
||
background-position:
|
||
-1px -1px,
|
||
-1px -1px,
|
||
-1px -1px;
|
||
}
|
||
|
||
|
||
img {
|
||
max-width: 100%;
|
||
display: block;
|
||
}
|
||
a {
|
||
color: inherit;
|
||
}
|
||
ul {
|
||
list-style: none;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
h1,
|
||
h2,
|
||
h3,
|
||
h4,
|
||
p {
|
||
margin: 0;
|
||
}
|
||
button {
|
||
font-family: inherit;
|
||
}
|
||
table {
|
||
border-collapse: collapse;
|
||
width: 100%;
|
||
}
|
||
|
||
::selection {
|
||
background: var(--accent);
|
||
color: var(--accent-contrast);
|
||
}
|
||
|
||
a:focus-visible,
|
||
button:focus-visible,
|
||
summary:focus-visible {
|
||
outline: 2px solid var(--accent);
|
||
outline-offset: 3px;
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
|
||
.skip-link {
|
||
position: absolute;
|
||
left: 1rem;
|
||
top: -100px;
|
||
background: var(--accent);
|
||
color: var(--accent-contrast);
|
||
padding: 0.65rem 1.1rem;
|
||
border-radius: var(--radius-sm);
|
||
font-size: 0.9rem;
|
||
font-weight: 600;
|
||
z-index: 200;
|
||
transition: top 0.2s ease;
|
||
}
|
||
.skip-link:focus {
|
||
top: 1rem;
|
||
}
|
||
|
||
/* Hidden icon sprite sheet */
|
||
.icon-sprite {
|
||
position: absolute;
|
||
width: 0;
|
||
height: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.icon {
|
||
width: 20px;
|
||
height: 20px;
|
||
stroke: currentColor;
|
||
fill: none;
|
||
stroke-width: 1.8;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.icon-badge {
|
||
width: 46px;
|
||
height: 46px;
|
||
border-radius: var(--radius-sm);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #fff;
|
||
margin-bottom: 1rem;
|
||
box-shadow: var(--shadow);
|
||
}
|
||
.icon-badge .icon {
|
||
width: 24px;
|
||
height: 24px;
|
||
}
|
||
|
||
/* Gradient utility classes */
|
||
.grad-1 {
|
||
background: var(--grad-1);
|
||
}
|
||
.grad-2 {
|
||
background: var(--grad-2);
|
||
}
|
||
.grad-3 {
|
||
background: var(--grad-3);
|
||
}
|
||
.grad-4 {
|
||
background: var(--grad-4);
|
||
}
|
||
.grad-5 {
|
||
background: var(--grad-5);
|
||
}
|
||
.grad-6 {
|
||
background: var(--grad-6);
|
||
}
|
||
.grad-7 {
|
||
background: var(--grad-7);
|
||
}
|
||
|
||
/* == 3. LAYOUT PRIMITIVES == */
|
||
.wrap {
|
||
max-width: var(--content-max);
|
||
margin-inline: auto;
|
||
padding-inline: 1.5rem;
|
||
}
|
||
section {
|
||
padding-block: clamp(3.5rem, 7vw, 6.5rem);
|
||
}
|
||
.section-head {
|
||
max-width: 680px;
|
||
margin-bottom: clamp(2rem, 4vw, 3rem);
|
||
}
|
||
.eyebrow {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
font-family: var(--font-mono);
|
||
font-size: 0.75rem;
|
||
letter-spacing: 0.14em;
|
||
text-transform: uppercase;
|
||
background: linear-gradient(90deg, var(--accent), #ec4899);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
margin-bottom: 0.75rem;
|
||
font-weight: 700;
|
||
}
|
||
.section-title {
|
||
font-size: clamp(1.6rem, 3.2vw, 2.25rem);
|
||
font-weight: 800;
|
||
letter-spacing: -0.01em;
|
||
margin-bottom: 0.75rem;
|
||
}
|
||
.section-sub {
|
||
color: var(--text-secondary);
|
||
font-size: 1.05rem;
|
||
max-width: 65ch;
|
||
}
|
||
|
||
/* == 4. NAVIGATION == */
|
||
.nav-logo {
|
||
width: 32px;
|
||
height: 32px;
|
||
flex: 0 0 32px;
|
||
display: block;
|
||
}
|
||
.brand-name {
|
||
color: #0a0a0a;
|
||
}
|
||
html[data-theme="dark"] .brand-name {
|
||
color: #fafafa;
|
||
}
|
||
@media (max-width: 600px) {
|
||
.nav-logo {
|
||
width: 28px;
|
||
height: 28px;
|
||
flex-basis: 28px;
|
||
}
|
||
}
|
||
.site-header {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
background-color: color-mix(in srgb, var(--bg) 85%, transparent);
|
||
backdrop-filter: saturate(160%) blur(10px);
|
||
-webkit-backdrop-filter: saturate(160%) blur(10px);
|
||
border-bottom: 1px solid var(--border);
|
||
transition: var(--transition-theme);
|
||
}
|
||
.nav-inner {
|
||
max-width: var(--content-max);
|
||
margin-inline: auto;
|
||
padding: 0.85rem 1.5rem;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 1rem;
|
||
}
|
||
.brand {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
font-weight: 800;
|
||
font-size: 1.15rem;
|
||
letter-spacing: -0.01em;
|
||
text-decoration: none;
|
||
}
|
||
.nav-icon {
|
||
width: 31px;
|
||
height: 26px;
|
||
flex: 0 0 31px;
|
||
}
|
||
.nav-links {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.15rem;
|
||
}
|
||
.nav-links a {
|
||
text-decoration: none;
|
||
font-size: 0.9rem;
|
||
font-weight: 500;
|
||
color: var(--text-secondary);
|
||
padding: 0.5rem 0.65rem;
|
||
border-radius: var(--radius-sm);
|
||
transition:
|
||
color 0.15s ease,
|
||
background-color 0.15s ease;
|
||
}
|
||
.nav-links a:hover {
|
||
color: var(--text);
|
||
background-color: var(--surface);
|
||
}
|
||
.nav-links a.is-active {
|
||
color: var(--accent);
|
||
}
|
||
.nav-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.theme-toggle {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
color: var(--text);
|
||
border-radius: var(--radius);
|
||
padding: 0.45rem 0.7rem;
|
||
font-size: 0.82rem;
|
||
font-family: var(--font-mono);
|
||
cursor: pointer;
|
||
transition:
|
||
background-color 0.15s ease,
|
||
border-color 0.15s ease;
|
||
}
|
||
.theme-toggle:hover {
|
||
background: var(--surface-hover);
|
||
border-color: var(--border-strong);
|
||
}
|
||
|
||
.hamburger {
|
||
display: none;
|
||
background: transparent;
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-sm);
|
||
width: 40px;
|
||
height: 40px;
|
||
cursor: pointer;
|
||
color: var(--text);
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.hamburger span,
|
||
.hamburger span::before,
|
||
.hamburger span::after {
|
||
content: "";
|
||
display: block;
|
||
width: 18px;
|
||
height: 2px;
|
||
background: currentColor;
|
||
position: relative;
|
||
transition:
|
||
transform 0.2s ease,
|
||
opacity 0.2s ease;
|
||
}
|
||
.hamburger span::before {
|
||
position: absolute;
|
||
top: -6px;
|
||
}
|
||
.hamburger span::after {
|
||
position: absolute;
|
||
top: 6px;
|
||
}
|
||
.hamburger[aria-expanded="true"] span {
|
||
background: transparent;
|
||
}
|
||
.hamburger[aria-expanded="true"] span::before {
|
||
transform: translateY(6px) rotate(45deg);
|
||
}
|
||
.hamburger[aria-expanded="true"] span::after {
|
||
transform: translateY(-6px) rotate(-45deg);
|
||
}
|
||
|
||
@media (max-width: 860px) {
|
||
.hamburger {
|
||
display: inline-flex;
|
||
}
|
||
.nav-links {
|
||
position: fixed;
|
||
inset: 61px 0 auto 0;
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
background: var(--bg-raised);
|
||
border-bottom: 1px solid var(--border);
|
||
padding: 0.5rem;
|
||
gap: 0;
|
||
transform: translateY(-8px);
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition:
|
||
transform 0.18s ease,
|
||
opacity 0.18s ease;
|
||
max-height: 80vh;
|
||
overflow-y: auto;
|
||
}
|
||
.nav-links.is-open {
|
||
transform: translateY(0);
|
||
opacity: 1;
|
||
pointer-events: auto;
|
||
}
|
||
.nav-links a {
|
||
padding: 0.85rem 1rem;
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
}
|
||
|
||
/* == 5. HERO == */
|
||
.hero {
|
||
padding-block: clamp(4rem, 10vw, 7.5rem) clamp(3rem, 6vw, 5rem);
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.hero::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: -20%;
|
||
right: -10%;
|
||
width: 560px;
|
||
height: 560px;
|
||
background: radial-gradient(circle, var(--glow-1), transparent 70%);
|
||
filter: blur(10px);
|
||
pointer-events: none;
|
||
opacity: 0.55;
|
||
z-index: 0;
|
||
}
|
||
.hero::after {
|
||
content: "";
|
||
position: absolute;
|
||
bottom: -30%;
|
||
left: -10%;
|
||
width: 480px;
|
||
height: 480px;
|
||
background: radial-gradient(circle, var(--glow-2), transparent 70%);
|
||
filter: blur(10px);
|
||
pointer-events: none;
|
||
opacity: 0.4;
|
||
z-index: 0;
|
||
}
|
||
.hero .wrap {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
.hero-kicker {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.8rem;
|
||
letter-spacing: 0.16em;
|
||
text-transform: uppercase;
|
||
color: var(--text-muted);
|
||
margin-bottom: 1.25rem;
|
||
}
|
||
.hero-kicker::before {
|
||
content: "$ ";
|
||
color: var(--accent);
|
||
}
|
||
.hero-logo {
|
||
max-width: 600px;
|
||
width: 100%;
|
||
height: auto;
|
||
margin-bottom: 1rem;
|
||
filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.3));
|
||
}
|
||
.hero h2 {
|
||
font-size: clamp(1.1rem, 2.6vw, 1.5rem);
|
||
font-weight: 500;
|
||
color: var(--text-secondary);
|
||
margin-top: 0.6rem;
|
||
letter-spacing: -0.005em;
|
||
}
|
||
.hero blockquote {
|
||
margin: 1.75rem 0 1.5rem;
|
||
padding-left: 1.1rem;
|
||
border-left: 3px solid transparent;
|
||
border-image: linear-gradient(180deg, var(--accent), #ec4899) 1;
|
||
font-size: clamp(1.05rem, 2vw, 1.3rem);
|
||
font-weight: 600;
|
||
max-width: 46ch;
|
||
}
|
||
.hero p.lede {
|
||
max-width: 64ch;
|
||
color: var(--text-secondary);
|
||
font-size: 1.05rem;
|
||
margin-bottom: 1.25rem;
|
||
}
|
||
.hero-byline {
|
||
font-size: 0.9rem;
|
||
color: var(--text-muted);
|
||
margin-bottom: 2rem;
|
||
}
|
||
.hero-byline strong {
|
||
color: var(--text-secondary);
|
||
}
|
||
.hero-ctas {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.85rem;
|
||
}
|
||
|
||
.btn {
|
||
position: relative;
|
||
overflow: hidden;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
font-weight: 600;
|
||
font-size: 0.95rem;
|
||
padding: 0.75rem 1.4rem;
|
||
border-radius: var(--radius);
|
||
text-decoration: none;
|
||
cursor: pointer;
|
||
border: 1px solid transparent;
|
||
transition:
|
||
transform 0.15s ease,
|
||
box-shadow 0.15s ease,
|
||
background-color 0.15s ease,
|
||
border-color 0.15s ease;
|
||
}
|
||
.btn:active {
|
||
transform: translateY(1px);
|
||
}
|
||
.btn-primary {
|
||
background: linear-gradient(135deg, var(--accent), #ec4899);
|
||
color: #fff;
|
||
}
|
||
.btn-primary:hover {
|
||
box-shadow: 0 10px 24px var(--glow-1);
|
||
transform: translateY(-1px);
|
||
}
|
||
.btn-outline {
|
||
background: transparent;
|
||
color: var(--text);
|
||
border-color: var(--border-strong);
|
||
}
|
||
.btn-outline:hover {
|
||
background: var(--surface);
|
||
border-color: var(--accent);
|
||
}
|
||
.btn-sm {
|
||
padding: 0.5rem 0.9rem;
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.btn .ripple {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.5);
|
||
transform: scale(0);
|
||
pointer-events: none;
|
||
animation: ripple 0.6s ease-out;
|
||
}
|
||
html[data-theme="dark"] .btn-outline .ripple {
|
||
background: rgba(255, 255, 255, 0.18);
|
||
}
|
||
@keyframes ripple {
|
||
to {
|
||
transform: scale(3);
|
||
opacity: 0;
|
||
}
|
||
}
|
||
|
||
/* == 6. ABOUT == */
|
||
.about-panel {
|
||
background: linear-gradient(135deg, var(--accent-soft), var(--surface));
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: clamp(1.5rem, 4vw, 2.5rem);
|
||
font-size: 1.1rem;
|
||
color: var(--text-secondary);
|
||
line-height: 1.75;
|
||
}
|
||
.about-panel strong {
|
||
color: var(--text);
|
||
}
|
||
|
||
/* == 7. COLORFUL CARD GRIDS == */
|
||
.card-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
|
||
gap: 1.15rem;
|
||
}
|
||
|
||
.card {
|
||
background: var(--bg-raised);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: 1.6rem;
|
||
position: relative;
|
||
overflow: hidden;
|
||
transition:
|
||
transform 0.2s ease,
|
||
box-shadow 0.2s ease,
|
||
border-color 0.2s ease;
|
||
}
|
||
.card::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 4px;
|
||
background: var(--card-grad, var(--grad-1));
|
||
}
|
||
.card:hover {
|
||
transform: translateY(-4px);
|
||
box-shadow: 0 14px 34px var(--card-glow, var(--glow-1));
|
||
border-color: var(--border-strong);
|
||
}
|
||
.card .icon-badge {
|
||
background: var(--card-grad, var(--grad-1));
|
||
}
|
||
.card h3 {
|
||
font-size: 1.08rem;
|
||
font-weight: 700;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
.card p {
|
||
color: var(--text-secondary);
|
||
font-size: 0.94rem;
|
||
}
|
||
.card ul {
|
||
margin-top: 0.6rem;
|
||
}
|
||
.card li {
|
||
color: var(--text-secondary);
|
||
font-size: 0.9rem;
|
||
position: relative;
|
||
padding-left: 1.1rem;
|
||
margin-top: 0.3rem;
|
||
}
|
||
.card li::before {
|
||
content: "●";
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0.05em;
|
||
font-size: 0.55rem;
|
||
color: var(--accent);
|
||
}
|
||
.card .card-tag {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.68rem;
|
||
letter-spacing: 0.04em;
|
||
text-transform: uppercase;
|
||
color: var(--text-muted);
|
||
display: block;
|
||
margin-top: 0.9rem;
|
||
}
|
||
|
||
/* == 8. PROJECTS == */
|
||
.callout {
|
||
display: flex;
|
||
gap: 0.85rem;
|
||
align-items: flex-start;
|
||
background: var(--accent-soft);
|
||
border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
|
||
border-radius: var(--radius);
|
||
padding: 1.1rem 1.3rem;
|
||
margin-bottom: 2rem;
|
||
font-size: 0.95rem;
|
||
color: var(--text-secondary);
|
||
}
|
||
.callout strong {
|
||
color: var(--text);
|
||
}
|
||
.callout .icon {
|
||
color: var(--accent);
|
||
margin-top: 0.15rem;
|
||
}
|
||
|
||
.project-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 1.15rem;
|
||
}
|
||
@media (max-width: 780px) {
|
||
.project-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
.project-card {
|
||
background: var(--bg-raised);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: 1.6rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.9rem;
|
||
position: relative;
|
||
overflow: hidden;
|
||
transition:
|
||
transform 0.2s ease,
|
||
box-shadow 0.2s ease,
|
||
border-color 0.2s ease;
|
||
}
|
||
.project-card::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 4px;
|
||
background: var(--card-grad, var(--grad-1));
|
||
}
|
||
.project-card:hover {
|
||
transform: translateY(-4px);
|
||
box-shadow: 0 14px 34px var(--card-glow, var(--glow-1));
|
||
border-color: var(--border-strong);
|
||
}
|
||
.project-card-head {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
gap: 0.75rem;
|
||
}
|
||
.project-title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.65rem;
|
||
}
|
||
.project-title .icon-badge {
|
||
width: 38px;
|
||
height: 38px;
|
||
margin-bottom: 0;
|
||
border-radius: var(--radius-sm);
|
||
background: var(--card-grad, var(--grad-1));
|
||
}
|
||
.project-title .icon-badge .icon {
|
||
width: 19px;
|
||
height: 19px;
|
||
}
|
||
.project-card h3 {
|
||
font-family: var(--font-mono);
|
||
font-size: 1.02rem;
|
||
font-weight: 700;
|
||
}
|
||
.status-badge {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.66rem;
|
||
letter-spacing: 0.06em;
|
||
text-transform: uppercase;
|
||
padding: 0.22rem 0.55rem;
|
||
border-radius: 999px;
|
||
white-space: nowrap;
|
||
color: #fff;
|
||
align-self: flex-start;
|
||
}
|
||
.project-card p.desc {
|
||
color: var(--text-secondary);
|
||
font-size: 0.93rem;
|
||
}
|
||
.tech-badges {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.45rem;
|
||
margin-top: 0.5rem;
|
||
}
|
||
.tech-badge {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.72rem;
|
||
color: #fff;
|
||
border-radius: var(--radius-sm);
|
||
padding: 0.22rem 0.55rem;
|
||
background: var(--card-grad, var(--grad-1));
|
||
opacity: 0.92;
|
||
}
|
||
.project-links {
|
||
display: flex;
|
||
gap: 0.6rem;
|
||
margin-top: auto;
|
||
padding-top: 0.5rem;
|
||
}
|
||
|
||
/* == 9. STATS == */
|
||
.stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||
gap: 1rem;
|
||
text-align: center;
|
||
}
|
||
.stat {
|
||
background: var(--bg-raised);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: 1.75rem 1rem;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.stat::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 3px;
|
||
background: var(--card-grad, var(--grad-1));
|
||
}
|
||
.stat .num {
|
||
font-family: var(--font-mono);
|
||
font-size: clamp(1.8rem, 4vw, 2.5rem);
|
||
font-weight: 700;
|
||
display: block;
|
||
background: var(--card-grad, var(--grad-1));
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
}
|
||
.stat .label {
|
||
color: var(--text-secondary);
|
||
font-size: 0.85rem;
|
||
margin-top: 0.35rem;
|
||
}
|
||
|
||
/* == 10. POSITIONING TABLE == */
|
||
.positioning {
|
||
overflow-x: auto;
|
||
border-radius: var(--radius);
|
||
border: 1px solid var(--border);
|
||
}
|
||
.positioning table {
|
||
min-width: 560px;
|
||
}
|
||
.positioning th,
|
||
.positioning td {
|
||
text-align: left;
|
||
padding: 0.9rem 1.2rem;
|
||
font-size: 0.92rem;
|
||
}
|
||
.positioning thead th {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.72rem;
|
||
letter-spacing: 0.06em;
|
||
text-transform: uppercase;
|
||
color: #fff;
|
||
padding-block: 1rem;
|
||
}
|
||
.positioning thead th:first-child {
|
||
background: var(--grad-7);
|
||
}
|
||
.positioning thead th:last-child {
|
||
background: var(--grad-5);
|
||
}
|
||
.positioning tbody tr {
|
||
border-top: 1px solid var(--border);
|
||
background: var(--bg-raised);
|
||
}
|
||
.positioning tbody tr:nth-child(even) {
|
||
background: var(--surface);
|
||
}
|
||
.positioning td:first-child {
|
||
color: var(--text-muted);
|
||
position: relative;
|
||
padding-left: 2.2rem;
|
||
}
|
||
.positioning td:first-child::before {
|
||
content: "✕";
|
||
position: absolute;
|
||
left: 1.2rem;
|
||
color: #ef4444;
|
||
font-weight: 700;
|
||
font-size: 0.8rem;
|
||
}
|
||
.positioning td:last-child {
|
||
color: var(--text);
|
||
font-weight: 600;
|
||
position: relative;
|
||
padding-left: 2.2rem;
|
||
}
|
||
.positioning td:last-child::before {
|
||
content: "✓";
|
||
position: absolute;
|
||
left: 1.2rem;
|
||
color: #10b981;
|
||
font-weight: 700;
|
||
font-size: 0.8rem;
|
||
}
|
||
|
||
/* == 11. VISION == */
|
||
.vision-panel {
|
||
position: relative;
|
||
overflow: hidden;
|
||
background: linear-gradient(135deg, var(--accent-soft), var(--surface));
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: clamp(1.75rem, 5vw, 3rem);
|
||
}
|
||
.vision-panel::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: var(--radius);
|
||
padding: 1px;
|
||
background: linear-gradient(135deg, var(--accent), #ec4899, #06b6d4);
|
||
-webkit-mask:
|
||
linear-gradient(#000 0 0) content-box,
|
||
linear-gradient(#000 0 0);
|
||
-webkit-mask-composite: xor;
|
||
mask-composite: exclude;
|
||
opacity: 0.5;
|
||
pointer-events: none;
|
||
}
|
||
.vision-panel p {
|
||
font-size: clamp(1.1rem, 2.4vw, 1.4rem);
|
||
font-weight: 500;
|
||
letter-spacing: -0.005em;
|
||
color: var(--text);
|
||
max-width: 62ch;
|
||
position: relative;
|
||
}
|
||
.vision-panel p + p {
|
||
margin-top: 1.1rem;
|
||
color: var(--text-secondary);
|
||
font-weight: 400;
|
||
font-size: clamp(1rem, 2vw, 1.15rem);
|
||
}
|
||
|
||
/* == 12. VALUES == */
|
||
.value-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(155px, 1fr));
|
||
gap: 0.8rem;
|
||
}
|
||
.value-chip {
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: 1.2rem 0.9rem;
|
||
text-align: center;
|
||
background: var(--bg-raised);
|
||
position: relative;
|
||
overflow: hidden;
|
||
transition:
|
||
transform 0.2s ease,
|
||
border-color 0.2s ease,
|
||
box-shadow 0.2s ease;
|
||
}
|
||
.value-chip::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 3px;
|
||
background: var(--card-grad, var(--grad-1));
|
||
}
|
||
.value-chip:hover {
|
||
transform: translateY(-3px);
|
||
box-shadow: 0 10px 24px var(--card-glow, var(--glow-1));
|
||
}
|
||
.value-chip .n {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.7rem;
|
||
display: block;
|
||
margin-bottom: 0.5rem;
|
||
font-weight: 700;
|
||
background: var(--card-grad, var(--grad-1));
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
}
|
||
.value-chip .t {
|
||
font-weight: 600;
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
/* == 13. ROADMAP == */
|
||
.roadmap-intro {
|
||
color: var(--text-secondary);
|
||
max-width: 70ch;
|
||
margin-bottom: 2.5rem;
|
||
font-size: 1rem;
|
||
}
|
||
.roadmap-intro strong {
|
||
color: var(--text);
|
||
}
|
||
|
||
.circuit {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
overflow-x: auto;
|
||
padding-block: 1rem 0.5rem;
|
||
scrollbar-width: thin;
|
||
}
|
||
.node {
|
||
flex: 1 0 100px;
|
||
min-width: 100px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
text-align: center;
|
||
position: relative;
|
||
padding-top: 2.75rem;
|
||
}
|
||
.node::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 12px;
|
||
left: -50%;
|
||
width: 100%;
|
||
height: 2px;
|
||
background: repeating-linear-gradient(90deg, var(--border-strong) 0 6px, transparent 6px 11px);
|
||
z-index: 0;
|
||
}
|
||
.node:first-child::before {
|
||
display: none;
|
||
}
|
||
.node.is-active::before {
|
||
background: repeating-linear-gradient(90deg, var(--accent) 0 6px, transparent 6px 11px);
|
||
}
|
||
.node .pad {
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: 50%;
|
||
border: 2px solid var(--border-strong);
|
||
background: var(--bg-raised);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-family: var(--font-mono);
|
||
font-size: 0.72rem;
|
||
font-weight: 700;
|
||
color: var(--text-muted);
|
||
position: absolute;
|
||
top: 0;
|
||
z-index: 1;
|
||
transition:
|
||
transform 0.18s ease,
|
||
border-color 0.18s ease,
|
||
box-shadow 0.18s ease;
|
||
}
|
||
.node.is-active .pad {
|
||
border-color: transparent;
|
||
background: var(--card-grad, var(--grad-1));
|
||
color: #fff;
|
||
box-shadow: 0 0 0 4px var(--card-glow, var(--glow-1));
|
||
}
|
||
.node:hover .pad {
|
||
transform: scale(1.12);
|
||
}
|
||
.node .name {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.82rem;
|
||
font-weight: 700;
|
||
margin-top: 0.4rem;
|
||
}
|
||
.node .state {
|
||
font-size: 0.72rem;
|
||
color: var(--text-muted);
|
||
margin-top: 0.15rem;
|
||
}
|
||
.node.is-active .state {
|
||
color: var(--accent);
|
||
font-weight: 600;
|
||
}
|
||
|
||
@media (max-width: 720px) {
|
||
.circuit {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
overflow-x: visible;
|
||
}
|
||
.node {
|
||
flex-direction: row;
|
||
text-align: left;
|
||
padding: 0 0 1.75rem 2.9rem;
|
||
min-width: 0;
|
||
align-items: flex-start;
|
||
}
|
||
.node::before {
|
||
top: 0;
|
||
left: 13px;
|
||
width: 2px;
|
||
height: 100%;
|
||
background: repeating-linear-gradient(180deg, var(--border-strong) 0 6px, transparent 6px 11px);
|
||
}
|
||
.node.is-active::before {
|
||
background: repeating-linear-gradient(180deg, var(--accent) 0 6px, transparent 6px 11px);
|
||
}
|
||
.node .pad {
|
||
top: 0;
|
||
left: 0;
|
||
}
|
||
.node .name {
|
||
margin-top: 0;
|
||
margin-left: 0.15rem;
|
||
}
|
||
.node .text {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
}
|
||
|
||
.roadmap-footnote {
|
||
margin-top: 2rem;
|
||
font-size: 0.95rem;
|
||
color: var(--text-secondary);
|
||
border-top: 1px solid var(--border);
|
||
padding-top: 1.5rem;
|
||
}
|
||
.roadmap-footnote strong {
|
||
color: var(--text);
|
||
}
|
||
|
||
/* == 14. REVEAL ANIMATION == */
|
||
.reveal {
|
||
opacity: 0;
|
||
transform: translateY(14px);
|
||
transition:
|
||
opacity 0.5s ease,
|
||
transform 0.5s ease;
|
||
}
|
||
.reveal.is-visible {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.reveal {
|
||
opacity: 1;
|
||
transform: none;
|
||
transition: none;
|
||
}
|
||
}
|
||
|
||
/* == 15. FOOTER == */
|
||
.site-footer {
|
||
border-top: 1px solid var(--border);
|
||
padding-block: 3rem 2rem;
|
||
margin-top: 2rem;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.site-footer::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 3px;
|
||
background: linear-gradient(
|
||
90deg,
|
||
var(--grad-1),
|
||
var(--grad-2),
|
||
var(--grad-3),
|
||
var(--grad-4),
|
||
var(--grad-5)
|
||
);
|
||
}
|
||
.footer-grid {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: space-between;
|
||
gap: 2rem;
|
||
}
|
||
.footer-brand .mark {
|
||
font-family: var(--font-mono);
|
||
font-weight: 800;
|
||
font-size: 1.3rem;
|
||
background: linear-gradient(135deg, var(--accent), #ec4899);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
}
|
||
.footer-logo {
|
||
max-width: 300px;
|
||
width: 100%;
|
||
height: auto;
|
||
opacity: 0.5;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
.footer-brand .sub {
|
||
color: var(--text-muted);
|
||
font-size: 0.85rem;
|
||
margin-top: 0.2rem;
|
||
}
|
||
.footer-motto {
|
||
font-size: 0.95rem;
|
||
color: var(--text-secondary);
|
||
line-height: 1.7;
|
||
}
|
||
.footer-links {
|
||
display: flex;
|
||
gap: 1.5rem;
|
||
}
|
||
.footer-links a {
|
||
text-decoration: none;
|
||
color: var(--text-secondary);
|
||
font-size: 0.9rem;
|
||
font-weight: 600;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
}
|
||
.footer-links a:hover {
|
||
color: var(--accent);
|
||
}
|
||
.footer-bottom {
|
||
margin-top: 2.5rem;
|
||
padding-top: 1.5rem;
|
||
border-top: 1px solid var(--border);
|
||
font-family: var(--font-mono);
|
||
font-size: 0.78rem;
|
||
color: var(--text-muted);
|
||
text-align: center;
|
||
letter-spacing: 0.02em;
|
||
}
|
||
|
||
@media print {
|
||
.site-header,
|
||
.theme-toggle,
|
||
.hamburger,
|
||
.hero-ctas,
|
||
.btn,
|
||
.project-links,
|
||
.circuit {
|
||
display: none !important;
|
||
}
|
||
body {
|
||
background-image: none;
|
||
color: #000;
|
||
}
|
||
section {
|
||
padding-block: 1rem;
|
||
}
|
||
a {
|
||
color: #000;
|
||
text-decoration: underline;
|
||
}
|
||
.card::before,
|
||
.project-card::before,
|
||
.stat::before,
|
||
.value-chip::before {
|
||
display: none;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<a href="#main" class="skip-link">Skip to content</a>
|
||
|
||
<!-- ICON SPRITE -->
|
||
<svg class="icon-sprite" aria-hidden="true">
|
||
<defs>
|
||
<symbol id="i-key" viewBox="0 0 24 24">
|
||
<circle cx="8" cy="15" r="4" />
|
||
<path d="M11 12l9-9M17 6l3 3M14 9l2 2" />
|
||
</symbol>
|
||
<symbol id="i-server" viewBox="0 0 24 24">
|
||
<rect x="3" y="4" width="18" height="6" rx="1.5" />
|
||
<rect x="3" y="14" width="18" height="6" rx="1.5" />
|
||
<circle cx="7" cy="7" r="1" fill="currentColor" stroke="none" />
|
||
<circle cx="7" cy="17" r="1" fill="currentColor" stroke="none" />
|
||
</symbol>
|
||
<symbol id="i-gauge" viewBox="0 0 24 24">
|
||
<path d="M4 15a8 8 0 1116 0" />
|
||
<path d="M12 15l4-5" />
|
||
<circle cx="12" cy="15" r="1" fill="currentColor" stroke="none" />
|
||
</symbol>
|
||
<symbol id="i-lock" viewBox="0 0 24 24">
|
||
<rect x="5" y="11" width="14" height="9" rx="2" />
|
||
<path d="M8 11V7a4 4 0 018 0v4" />
|
||
</symbol>
|
||
<symbol id="i-shield-check" viewBox="0 0 24 24">
|
||
<path d="M12 3l7 3v6c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6l7-3z" />
|
||
<path d="M9 12l2 2 4-4" />
|
||
</symbol>
|
||
<symbol id="i-wrench" viewBox="0 0 24 24">
|
||
<path d="M14.7 6.3a4 4 0 00-5.4 5.4L4 17v3h3l5.3-5.3a4 4 0 005.4-5.4l-2.5 2.5-2-2 2.5-2.5z" />
|
||
</symbol>
|
||
<symbol id="i-clock" viewBox="0 0 24 24">
|
||
<circle cx="12" cy="12" r="8.5" />
|
||
<path d="M12 7v5l3.5 2" />
|
||
</symbol>
|
||
<symbol id="i-cpu" viewBox="0 0 24 24">
|
||
<rect x="6" y="6" width="12" height="12" rx="1.5" />
|
||
<path d="M9 3v3M15 3v3M9 18v3M15 18v3M3 9h3M3 15h3M18 9h3M18 15h3" />
|
||
</symbol>
|
||
<symbol id="i-box" viewBox="0 0 24 24">
|
||
<path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3z" />
|
||
<path d="M4.5 7.5L12 12l7.5-4.5M12 12v9" />
|
||
</symbol>
|
||
<symbol id="i-database" viewBox="0 0 24 24">
|
||
<ellipse cx="12" cy="6" rx="7" ry="3" />
|
||
<path d="M5 6v6c0 1.7 3.1 3 7 3s7-1.3 7-3V6" />
|
||
<path d="M5 12v6c0 1.7 3.1 3 7 3s7-1.3 7-3v-6" />
|
||
</symbol>
|
||
<symbol id="i-bolt" viewBox="0 0 24 24"><path d="M13 2L4 14h6l-1 8 9-12h-6l1-8z" /></symbol>
|
||
<symbol id="i-route" viewBox="0 0 24 24">
|
||
<circle cx="5" cy="6" r="2.3" />
|
||
<circle cx="19" cy="18" r="2.3" />
|
||
<path d="M5 8.3v3a4 4 0 004 4h6a4 4 0 004 4" />
|
||
</symbol>
|
||
<symbol id="i-layers" viewBox="0 0 24 24">
|
||
<path d="M12 3l9 5-9 5-9-5 9-5z" />
|
||
<path d="M3 13l9 5 9-5M3 8l9 5 9-5" />
|
||
</symbol>
|
||
<symbol id="i-terminal" viewBox="0 0 24 24">
|
||
<rect x="3" y="4" width="18" height="16" rx="2" />
|
||
<path d="M7 9l4 3-4 3M13 15h4" />
|
||
</symbol>
|
||
<symbol id="i-monitor" viewBox="0 0 24 24">
|
||
<rect x="3" y="4" width="18" height="12" rx="1.5" />
|
||
<path d="M8 20h8M12 16v4" />
|
||
<path d="M6 12l3-3 2 2 4-4" />
|
||
</symbol>
|
||
<symbol id="i-infinity" viewBox="0 0 24 24">
|
||
<path
|
||
d="M7 9a3.5 3.5 0 100 7 3.5 3.5 0 002.9-1.5L12 12l2.1 2.5A3.5 3.5 0 1017 9a3.5 3.5 0 00-2.9 1.5L12 13l-2.1-2.5A3.5 3.5 0 007 9z"
|
||
/>
|
||
</symbol>
|
||
<symbol id="i-chart" viewBox="0 0 24 24"><path d="M4 20V10M10 20V4M16 20v-7M22 20H2" /></symbol>
|
||
<symbol id="i-shield" viewBox="0 0 24 24">
|
||
<path d="M12 3l7 3v6c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6l7-3z" />
|
||
</symbol>
|
||
<symbol id="i-link" viewBox="0 0 24 24">
|
||
<path d="M9 15l6-6" />
|
||
<path d="M11 6l1-1a4 4 0 015.5 5.5l-2 2" />
|
||
<path d="M13 18l-1 1a4 4 0 01-5.5-5.5l2-2" />
|
||
</symbol>
|
||
<symbol id="i-globe" viewBox="0 0 24 24">
|
||
<circle cx="12" cy="12" r="8.5" />
|
||
<path
|
||
d="M3.5 12h17M12 3.5c2.5 2.3 4 5.3 4 8.5s-1.5 6.2-4 8.5c-2.5-2.3-4-5.3-4-8.5s1.5-6.2 4-8.5z"
|
||
/>
|
||
</symbol>
|
||
<symbol id="i-flag" viewBox="0 0 24 24">
|
||
<path d="M5 3v18" />
|
||
<path d="M5 4h13l-3 4 3 4H5" />
|
||
</symbol>
|
||
<symbol id="i-info" viewBox="0 0 24 24">
|
||
<circle cx="12" cy="12" r="8.5" />
|
||
<path d="M12 11v5.5M12 8v.01" />
|
||
</symbol>
|
||
<symbol id="i-git" viewBox="0 0 24 24">
|
||
<circle cx="6" cy="6" r="2.2" />
|
||
<circle cx="6" cy="18" r="2.2" />
|
||
<circle cx="18" cy="12" r="2.2" />
|
||
<path d="M6 8.2v7.6M6 8.2c0 4 3 5.8 6 5.8h4" />
|
||
</symbol>
|
||
</defs>
|
||
</svg>
|
||
|
||
<header class="site-header">
|
||
<div class="nav-inner">
|
||
<a href="#home" class="brand" aria-label="NX9 — Host Yourself">
|
||
<svg
|
||
class="nav-logo"
|
||
viewBox="0 0 335.05563 357.12827"
|
||
preserveAspectRatio="xMidYMid meet"
|
||
aria-hidden="true"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
>
|
||
<g id="layer1" transform="matrix(3.7795276,0,0,3.7795276,-26.765107,-97.222608)">
|
||
<g
|
||
id="g19"
|
||
transform="matrix(0.36886531,0,0,0.35629784,-228.21758,-224.7539)"
|
||
style="fill: #ff0000"
|
||
>
|
||
<path
|
||
d="m 705.5,704.4 c -4.1,1.8 -8.3,6.9 -9,10.9 -0.4,1.8 -0.4,11.8 -0.1,22.2 0.3,10.5 0.5,20.8 0.5,23 -0.2,5.7 -0.2,43.3 -0.1,47.5 0.1,1.9 -0.1,10.1 -0.4,18.2 L 695.9,841 H 712 v -24 h 132 v 16 h 16.2 l -0.6,-10.8 c -0.4,-5.9 -0.6,-12.3 -0.5,-14.2 0.1,-1.9 0.2,-12.6 0.2,-23.8 -0.1,-25.1 -0.1,-24.3 0.1,-49.9 0.1,-23.6 0,-24 -7.4,-29.1 l -3.3,-2.2 h -70.1 c -56,0.1 -70.7,0.3 -73.1,1.4 M 844,734.5 V 752 H 712 v -35 h 132 z m 0,49.5 v 17 H 712 v -34 h 132 z"
|
||
style="fill: #ff0000; stroke-width: 0"
|
||
/>
|
||
<path
|
||
d="m 721,734.5 v 7.5 h 15 v -15 h -15 z m 24.7,-6.8 c -0.4,0.3 -0.7,3.7 -0.7,7.5 v 6.8 h 33 v -15 h -15.8 c -8.7,0 -16.2,0.3 -16.5,0.7 M 721,784.5 v 7.5 h 15 v -15 h -15 z m 24,0 v 7.5 h 33 v -15 h -33 z m -24,49 v 7.5 h 15 v -15 h -15 z m 24,0 v 7.5 h 33 v -15 h -33 z m -104,20.3 -3.1,3.1 0.3,51.5 0.3,51.5 2.3,2.3 c 2.1,2.2 3.1,2.3 19.5,2.6 10.3,0.2 18.6,-0.1 20.8,-0.7 4.3,-1.3 5.9,-4.3 5.9,-11.3 0,-4.4 0.2,-4.9 1.7,-4.3 1,0.3 14.5,4.9 30,10.1 26.1,8.9 28.8,9.6 36,9.6 9.3,0 18.3,-2.7 25.4,-7.5 9.2,-6.2 90.9,-72.9 93.5,-76.2 6.6,-8.6 6.1,-19.1 -1.2,-26.6 -5.1,-5.2 -10.8,-7.3 -18.2,-6.6 -7.8,0.7 -14.3,3 -40.7,14.7 -12.5,5.5 -23,10 -23.5,10 -0.4,0 -1.3,-1.3 -2,-2.9 -1.6,-3.8 -7.3,-9.5 -11.9,-11.8 -3.2,-1.6 -6.6,-1.8 -34.1,-1.8 -29.5,0 -30.7,0.1 -37,2.3 -3.6,1.3 -9,4.1 -12.2,6.2 l -5.6,3.7 -1.7,-4.4 c -2.2,-5.7 -6.7,-10.8 -11.9,-13.6 -3.4,-1.8 -6.2,-2.2 -16.8,-2.5 L 644,850.8 Z m 27.5,14.7 2.5,2.4 V 950 h -17 v -84 h 6 c 5.1,0 6.5,0.4 8.5,2.5 m 192.7,-0.8 c 2.1,1.9 2.2,3.2 0.6,6.8 -1.3,3 -87.5,72.8 -94.2,76.3 -2.5,1.4 -6.9,2.6 -10.3,2.9 -5.4,0.4 -8.1,-0.3 -37.8,-10.5 l -32,-10.9 v -16.4 c 0,-15.6 0.1,-16.7 2.6,-21.9 3.6,-7.7 7.7,-12.1 15.1,-16.1 l 6.3,-3.4 28.8,-0.3 28.7,-0.3 3,3 c 3.8,3.8 3.9,7.8 0.4,12 l -2.6,3.1 H 737 v 15 h 15.8 c 8.6,0 17.5,-0.5 19.7,-1.1 5.1,-1.4 12,-6.2 14.1,-9.8 1.3,-2.3 6.4,-4.9 27.2,-14.1 14,-6.3 28.3,-12.4 31.6,-13.6 7.3,-2.8 13.3,-3 15.8,-0.7"
|
||
style="fill: #ff0000; stroke-width: 0"
|
||
/>
|
||
</g>
|
||
</g>
|
||
</svg>
|
||
<span class="brand-name">NX9</span>
|
||
</a>
|
||
<nav class="nav-links" id="navLinks" aria-label="Primary">
|
||
<a href="#home" data-nav="home">Home</a> <a href="#philosophy" data-nav="philosophy">Philosophy</a>
|
||
<a href="#architecture" data-nav="architecture">Architecture</a>
|
||
<a href="#projects" data-nav="projects">Projects</a> <a href="#vision" data-nav="vision">Vision</a>
|
||
<a href="#values" data-nav="values">Values</a> <a href="#roadmap" data-nav="roadmap">Roadmap</a>
|
||
<a href="case-study.html" target="_self">Case Study</a>
|
||
</nav>
|
||
<div class="nav-right">
|
||
<button class="theme-toggle" id="themeToggle" type="button" aria-label="Toggle color theme">
|
||
<span id="themeIcon" aria-hidden="true">◐</span> <span id="themeLabel">Theme</span>
|
||
</button>
|
||
<button
|
||
class="hamburger"
|
||
id="hamburger"
|
||
type="button"
|
||
aria-label="Toggle navigation menu"
|
||
aria-expanded="false"
|
||
aria-controls="navLinks"
|
||
>
|
||
<span></span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main id="main">
|
||
<section class="hero" id="home">
|
||
<div class="wrap">
|
||
<p class="hero-kicker">nx9 --version</p>
|
||
|
||
<!-- Change logo color as per the theme -->
|
||
<img
|
||
id="heroLogo"
|
||
src="logo-dark-main.svg"
|
||
alt="NX9 Logo"
|
||
class="hero-logo reveal"
|
||
/>
|
||
|
||
<h2>Next Generation 9</h2>
|
||
<blockquote>Software people can own, understand, and control.</blockquote>
|
||
<p class="lede">
|
||
NX9 is a philosophy-driven ecosystem of independent, self-hosted, privacy-first infrastructure
|
||
software — single-binary Rust applications built for people and organizations who would rather
|
||
run their own infrastructure than rent someone else's. No telemetry. No subscriptions. No
|
||
mandatory cloud.
|
||
</p>
|
||
<p class="hero-byline">
|
||
Built and maintained by <strong>Sunil Thakare</strong> (<span
|
||
style="font-family: var(--font-mono)"
|
||
>@thakares</span
|
||
>)
|
||
</p>
|
||
<div class="hero-ctas">
|
||
<a href="#projects" class="btn btn-primary">View Projects</a>
|
||
<a href="#philosophy" class="btn btn-outline">Read Philosophy</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="about" aria-labelledby="about-heading">
|
||
<div class="wrap">
|
||
<div class="about-panel reveal">
|
||
<p id="about-heading">
|
||
<strong>NX9</strong> is not a framework, and it is not a cloud product that happens to
|
||
support self-hosting. It is a collection of carefully engineered, single-binary Rust
|
||
applications — designed for individuals and organizations that value ownership, simplicity,
|
||
and independence, and built to run equally well on a Raspberry Pi, a mini PC, a VPS, or
|
||
air-gapped government infrastructure.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="philosophy" aria-labelledby="philosophy-title">
|
||
<div class="wrap">
|
||
<div class="section-head reveal">
|
||
<p class="eyebrow">
|
||
<svg class="icon" style="width: 14px; height: 14px"><use href="#i-flag" /></svg> 01 — Design
|
||
Philosophy
|
||
</p>
|
||
<h2 class="section-title" id="philosophy-title">Principles That Don't Change Per Project</h2>
|
||
<p class="section-sub">
|
||
Nine commitments that stay constant across every NX9 application, regardless of what it
|
||
does.
|
||
</p>
|
||
</div>
|
||
<div class="card-grid" id="philosophyGrid"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="architecture" aria-labelledby="architecture-title">
|
||
<div class="wrap">
|
||
<div class="section-head reveal">
|
||
<p class="eyebrow">
|
||
<svg class="icon" style="width: 14px; height: 14px"><use href="#i-layers" /></svg> 02 —
|
||
Architecture
|
||
</p>
|
||
<h2 class="section-title" id="architecture-title">Core Architectural Pillars</h2>
|
||
<p class="section-sub">
|
||
Every NX9 application is built on the same nine foundations — the same reason a BZOD
|
||
deployment and a ChronoSeal deployment feel like they came from the same shop.
|
||
</p>
|
||
</div>
|
||
<div class="card-grid" id="architectureGrid"></div>
|
||
|
||
<div class="section-head reveal" style="margin-top: 3.5rem">
|
||
<p class="eyebrow">
|
||
<svg class="icon" style="width: 14px; height: 14px"><use href="#i-shield-check" /></svg>
|
||
Security Stack
|
||
</p>
|
||
<h2 class="section-title">Embedded, Not Bolted On</h2>
|
||
<p class="section-sub">
|
||
Modern cryptographic primitives and hardened defaults, standardized across the whole
|
||
ecosystem.
|
||
</p>
|
||
</div>
|
||
<div class="card-grid" id="securityGrid"></div>
|
||
|
||
<div class="section-head reveal" style="margin-top: 3.5rem">
|
||
<p class="eyebrow">
|
||
<svg class="icon" style="width: 14px; height: 14px"><use href="#i-chart" /></svg>
|
||
Positioning
|
||
</p>
|
||
<h2 class="section-title">The NX9 Trade-off, Made Explicit</h2>
|
||
</div>
|
||
<div class="positioning reveal">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Traditional Stack</th>
|
||
<th>NX9</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="positioningBody"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="projects" aria-labelledby="projects-title">
|
||
<div class="wrap">
|
||
<div class="section-head reveal">
|
||
<p class="eyebrow">
|
||
<svg class="icon" style="width: 14px; height: 14px"><use href="#i-box" /></svg> 03 —
|
||
Ecosystem
|
||
</p>
|
||
<h2 class="section-title" id="projects-title">Current Projects</h2>
|
||
<p class="section-sub">
|
||
Four projects are currently available. The NX9 ecosystem is designed to grow into a family
|
||
of nine focused, self-hosted applications.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="callout reveal">
|
||
<svg class="icon"><use href="#i-info" /></svg>
|
||
<p>
|
||
<strong>Codeberg is the canonical home of NX9.</strong> GitHub repositories are maintained
|
||
as mirrors to improve discoverability and make adoption easier.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="project-grid" id="projectGrid"></div>
|
||
|
||
<div class="stats-grid" id="statsGrid" style="margin-top: 3rem"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="vision" aria-labelledby="vision-title">
|
||
<div class="wrap">
|
||
<div class="section-head reveal">
|
||
<p class="eyebrow">
|
||
<svg class="icon" style="width: 14px; height: 14px"><use href="#i-globe" /></svg> 04 —
|
||
Vision
|
||
</p>
|
||
<h2 class="section-title" id="vision-title">Why NX9 Exists</h2>
|
||
</div>
|
||
<div class="vision-panel reveal">
|
||
<p>
|
||
In an era of cloud lock-in, subscriptions, and heavy dependencies, NX9 builds software that
|
||
serves humanity — not platforms.
|
||
</p>
|
||
<p>Technology should empower people to own their infrastructure, data, and future.</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="values" aria-labelledby="values-title">
|
||
<div class="wrap">
|
||
<div class="section-head reveal">
|
||
<p class="eyebrow">
|
||
<svg class="icon" style="width: 14px; height: 14px"><use href="#i-key" /></svg> 05 — Values
|
||
</p>
|
||
<h2 class="section-title" id="values-title">Core Values</h2>
|
||
<p class="section-sub">The twelve commitments every NX9 decision is measured against.</p>
|
||
</div>
|
||
<div class="value-grid" id="valueGrid"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="roadmap" aria-labelledby="roadmap-title">
|
||
<div class="wrap">
|
||
<div class="section-head reveal">
|
||
<p class="eyebrow">
|
||
<svg class="icon" style="width: 14px; height: 14px"><use href="#i-route" /></svg> 06 —
|
||
Roadmap
|
||
</p>
|
||
<h2 class="section-title" id="roadmap-title">Roadmap to Nine</h2>
|
||
</div>
|
||
<p class="roadmap-intro reveal">
|
||
<strong
|
||
>NX9 is not a single application — it is an ecosystem of nine focused, interoperable
|
||
tools</strong
|
||
>
|
||
built around ownership, privacy, simplicity, and open standards. Four projects are already
|
||
available, with five more planned to complete the vision.
|
||
</p>
|
||
|
||
<div
|
||
class="circuit reveal"
|
||
id="circuit"
|
||
role="list"
|
||
aria-label="NX9 ecosystem roadmap, four of nine milestones complete"
|
||
></div>
|
||
|
||
<p class="roadmap-footnote reveal">
|
||
Nodes are ordered by ship date, not ambition —
|
||
<strong>chronoseal, dns-server, auth,</strong> and <strong>url-shortener</strong> shipped in
|
||
that sequence. Five more applications are planned to complete the family of nine, reusing the
|
||
same Tokio · Axum · SQLite · Argon2 · Ed25519 · BLAKE3 foundation.
|
||
</p>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<footer class="site-footer">
|
||
<div class="wrap">
|
||
<div class="footer-grid">
|
||
<div class="footer-brand">
|
||
<img id="footerLogo" src="logo-dark-main.svg" alt="NX9 Logo" class="footer-logo" />
|
||
<div class="sub">Next Generation 9</div>
|
||
</div>
|
||
<p class="footer-motto">
|
||
Software people can own,<br />understand,<br />and control.<br /><br /><strong
|
||
>Always Free. Always Open. Always Yours.</strong
|
||
>
|
||
</p>
|
||
<nav class="footer-links" aria-label="Repository links">
|
||
<a href="https://codeberg.org/thakares" target="_blank" rel="noopener noreferrer"
|
||
><svg class="icon" style="width: 16px; height: 16px"><use href="#i-git" /></svg> Codeberg</a
|
||
>
|
||
<a href="https://github.com/thakares?tab=repositories" target="_blank" rel="noopener noreferrer"
|
||
><svg class="icon" style="width: 16px; height: 16px"><use href="#i-link" /></svg> GitHub</a
|
||
>
|
||
</nav>
|
||
</div>
|
||
<div class="footer-bottom">
|
||
© <span id="year"></span> NX9 — an open-source ecosystem by Sunil Thakare. MIT / Apache-2.0.
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
<script>
|
||
(function () {
|
||
"use strict";
|
||
|
||
/* == THEME == */
|
||
const root = document.documentElement;
|
||
const themeToggle = document.getElementById("themeToggle");
|
||
const themeIcon = document.getElementById("themeIcon");
|
||
const themeLabel = document.getElementById("themeLabel");
|
||
const heroLogo = document.getElementById("heroLogo");
|
||
const footerLogo = document.getElementById("footerLogo");
|
||
const STORAGE_KEY = "nx9-theme";
|
||
|
||
function updateThemeLogos(theme) {
|
||
const logo =
|
||
theme === "dark"
|
||
? "logo-light-main.svg"
|
||
: "logo-dark-main.svg";
|
||
|
||
if (heroLogo) heroLogo.src = logo;
|
||
if (footerLogo) footerLogo.src = logo;
|
||
}
|
||
|
||
function applyTheme(theme) {
|
||
root.setAttribute("data-theme", theme);
|
||
updateThemeLogos(theme);
|
||
themeIcon.textContent = theme === "dark" ? "●" : "○";
|
||
themeLabel.textContent = theme === "dark" ? "Dark" : "Light";
|
||
themeToggle.setAttribute(
|
||
"aria-pressed",
|
||
theme === "dark" ? "true" : "false",
|
||
);
|
||
}
|
||
|
||
function initTheme() {
|
||
const stored = localStorage.getItem(STORAGE_KEY);
|
||
|
||
if (stored === "light" || stored === "dark") {
|
||
applyTheme(stored);
|
||
return;
|
||
}
|
||
|
||
const prefersDark = window.matchMedia(
|
||
"(prefers-color-scheme: dark)",
|
||
).matches;
|
||
|
||
applyTheme(prefersDark ? "dark" : "light");
|
||
}
|
||
|
||
themeToggle.addEventListener("click", function () {
|
||
const current = root.getAttribute("data-theme");
|
||
const next = current === "dark" ? "light" : "dark";
|
||
|
||
applyTheme(next);
|
||
localStorage.setItem(STORAGE_KEY, next);
|
||
});
|
||
|
||
window
|
||
.matchMedia("(prefers-color-scheme: dark)")
|
||
.addEventListener("change", function (e) {
|
||
if (!localStorage.getItem(STORAGE_KEY)) {
|
||
applyTheme(e.matches ? "dark" : "light");
|
||
}
|
||
});
|
||
|
||
initTheme();
|
||
|
||
/* == MOBILE NAV == */
|
||
const hamburger = document.getElementById("hamburger");
|
||
const navLinks = document.getElementById("navLinks");
|
||
|
||
hamburger.addEventListener("click", function () {
|
||
const isOpen = navLinks.classList.toggle("is-open");
|
||
hamburger.setAttribute(
|
||
"aria-expanded",
|
||
isOpen ? "true" : "false",
|
||
);
|
||
});
|
||
|
||
navLinks.querySelectorAll("a").forEach(function (link) {
|
||
link.addEventListener("click", function () {
|
||
navLinks.classList.remove("is-open");
|
||
hamburger.setAttribute("aria-expanded", "false");
|
||
});
|
||
});
|
||
|
||
/* == ICON HELPER == */
|
||
function iconSvg(id) {
|
||
return '<svg class="icon"><use href="#' + id + '"/></svg>';
|
||
}
|
||
|
||
/* == DATA: DESIGN PHILOSOPHY == */
|
||
const philosophy = [
|
||
{
|
||
icon: "i-key",
|
||
grad: 1,
|
||
glow: "--glow-1",
|
||
title: "Operator Ownership",
|
||
body: "The operator owns the binaries, the configuration, the databases, the backups, and the encryption keys. No service depends on proprietary APIs or cloud-hosted control planes.",
|
||
},
|
||
{
|
||
icon: "i-server",
|
||
grad: 6,
|
||
glow: "--glow-6",
|
||
title: "Self-Hosting First",
|
||
body: "Every decision begins with one question: “Can this be deployed and operated by a single administrator?” If it needs Kubernetes or a managed database, the design is reconsidered.",
|
||
},
|
||
{
|
||
icon: "i-gauge",
|
||
grad: 3,
|
||
glow: "--glow-3",
|
||
title: "Simplicity Over Complexity",
|
||
body: "One binary. One configuration. One SQLite database. One administrator. Simple systems are easier to understand, secure, and recover.",
|
||
},
|
||
{
|
||
icon: "i-lock",
|
||
grad: 4,
|
||
glow: "--glow-4",
|
||
title: "Privacy by Default",
|
||
body: "Applications never assume cloud connectivity, analytics collection, telemetry uploads, or third-party tracking. Users decide what information leaves their infrastructure.",
|
||
},
|
||
{
|
||
icon: "i-shield-check",
|
||
grad: 5,
|
||
glow: "--glow-5",
|
||
title: "Security by Design",
|
||
body: "Argon2id, Ed25519, BLAKE3, RBAC, CSRF protection, and audit logs are embedded throughout the stack — not added later.",
|
||
},
|
||
{
|
||
icon: "i-wrench",
|
||
grad: 2,
|
||
glow: "--glow-2",
|
||
title: "Operational Excellence",
|
||
body: "Diagnostics, backups, restore procedures, migration tools, CLI administration, and documentation, in every project, from day one.",
|
||
},
|
||
{
|
||
icon: "i-clock",
|
||
grad: 7,
|
||
glow: "--glow-7",
|
||
title: "Long-Term Stability",
|
||
body: "NX9 intentionally avoids dependency churn. The goal is software that remains understandable and maintainable years into the future.",
|
||
},
|
||
{
|
||
icon: "i-git",
|
||
grad: 4,
|
||
glow: "--glow-4",
|
||
title: "Open Source First",
|
||
body: "Every NX9 codebase is 100% open source under permissive licenses. You have the fundamental right to inspect, build, and modify the software.",
|
||
},
|
||
{
|
||
icon: "i-infinity",
|
||
grad: 5,
|
||
glow: "--glow-5",
|
||
title: "Zero Vendor Lock-In",
|
||
body: "All data is stored in standard SQLite files, configurations are plain text, and architectures strictly avoid proprietary integrations.",
|
||
},
|
||
];
|
||
|
||
const philosophyGrid = document.getElementById("philosophyGrid");
|
||
|
||
philosophy.forEach(function (p) {
|
||
const card = document.createElement("article");
|
||
|
||
card.className = "card reveal";
|
||
card.style.setProperty(
|
||
"--card-grad",
|
||
"var(--grad-" + p.grad + ")",
|
||
);
|
||
card.style.setProperty(
|
||
"--card-glow",
|
||
"var(" + p.glow + ")",
|
||
);
|
||
|
||
card.innerHTML =
|
||
'<div class="icon-badge">' +
|
||
iconSvg(p.icon) +
|
||
"</div>" +
|
||
"<h3>" +
|
||
p.title +
|
||
"</h3>" +
|
||
"<p>" +
|
||
p.body +
|
||
"</p>";
|
||
|
||
philosophyGrid.appendChild(card);
|
||
});
|
||
|
||
/* == DATA: ARCHITECTURAL PILLARS == */
|
||
const architecture = [
|
||
{
|
||
icon: "i-cpu",
|
||
grad: 1,
|
||
glow: "--glow-1",
|
||
title: "Pure Rust",
|
||
body: "Memory safety, zero-cost abstractions, and fearless concurrency. Rust 2021 Edition, release-mode optimization, no runtime interpreter.",
|
||
tag: "~10–12 MB per binary",
|
||
},
|
||
{
|
||
icon: "i-box",
|
||
grad: 6,
|
||
glow: "--glow-6",
|
||
title: "Single Binary Deployment",
|
||
body: "One executable contains the HTTP server, business logic, auth, migrations, CLI, and templates. No JVM, no Node.js, no Python, no app server.",
|
||
tag: "cargo build --release",
|
||
},
|
||
{
|
||
icon: "i-database",
|
||
grad: 5,
|
||
glow: "--glow-5",
|
||
title: "SQLite First",
|
||
body: "ACID transactions, WAL concurrency, zero administration, and portable files. Several projects isolate data across multiple databases for tenant isolation.",
|
||
tag: "users.db · system.db · content.db",
|
||
},
|
||
{
|
||
icon: "i-bolt",
|
||
grad: 3,
|
||
glow: "--glow-3",
|
||
title: "Tokio Async Runtime",
|
||
body: "Asynchronous I/O and lightweight tasks power web servers, DNS resolution, and background workers with high concurrency.",
|
||
tag: "async / await",
|
||
},
|
||
{
|
||
icon: "i-route",
|
||
grad: 4,
|
||
glow: "--glow-4",
|
||
title: "Axum Web Layer",
|
||
body: "Routing, middleware, REST APIs, HTML rendering, authentication, and sessions — integrated naturally with Tokio and Rust's type system.",
|
||
tag: "HTTP · middleware · sessions",
|
||
},
|
||
{
|
||
icon: "i-layers",
|
||
grad: 2,
|
||
glow: "--glow-2",
|
||
title: "Layered Architecture",
|
||
body: "auth / cli / db / handlers / jobs / services / templates / utils / web — each layer owns one responsibility, for easier testing and lower coupling.",
|
||
tag: "src/ layout",
|
||
},
|
||
{
|
||
icon: "i-terminal",
|
||
grad: 7,
|
||
glow: "--glow-7",
|
||
title: "CLI-First Operations",
|
||
body: "serve · doctor · backup · restore · migrate · create-admin · init — every service is administrable headless, over SSH, from a script.",
|
||
tag: "automation-friendly",
|
||
},
|
||
{
|
||
icon: "i-shield",
|
||
grad: 1,
|
||
glow: "--glow-1",
|
||
title: "Security Stack",
|
||
body: "Argon2id password hashing, Ed25519 signatures, BLAKE3 hashing, CSRF protection, RBAC, and hardened compiler flags — RELRO, PIE, least privilege.",
|
||
tag: "defense in depth",
|
||
},
|
||
{
|
||
icon: "i-monitor",
|
||
grad: 6,
|
||
glow: "--glow-6",
|
||
title: "Operational Tooling",
|
||
body: "Health checks, migration verification, automatic backups, restore tools, Docker support, systemd units, and structured logging, out of the box.",
|
||
tag: "diagnostics · systemd · docker",
|
||
},
|
||
];
|
||
|
||
const architectureGrid =
|
||
document.getElementById("architectureGrid");
|
||
|
||
architecture.forEach(function (a) {
|
||
const card = document.createElement("article");
|
||
|
||
card.className = "card reveal";
|
||
card.style.setProperty(
|
||
"--card-grad",
|
||
"var(--grad-" + a.grad + ")",
|
||
);
|
||
card.style.setProperty(
|
||
"--card-glow",
|
||
"var(" + a.glow + ")",
|
||
);
|
||
|
||
card.innerHTML =
|
||
'<div class="icon-badge">' +
|
||
iconSvg(a.icon) +
|
||
"</div>" +
|
||
"<h3>" +
|
||
a.title +
|
||
"</h3>" +
|
||
"<p>" +
|
||
a.body +
|
||
"</p>" +
|
||
'<span class="card-tag">' +
|
||
a.tag +
|
||
"</span>";
|
||
|
||
architectureGrid.appendChild(card);
|
||
});
|
||
|
||
/* == DATA: SECURITY == */
|
||
const security = [
|
||
{
|
||
icon: "i-shield-check",
|
||
grad: 4,
|
||
glow: "--glow-4",
|
||
title: "Argon2id Hashing",
|
||
body: "Memory-hard, CPU-hard password hashing by default for all user credentials.",
|
||
},
|
||
{
|
||
icon: "i-key",
|
||
grad: 1,
|
||
glow: "--glow-1",
|
||
title: "Ed25519 Signatures",
|
||
body: "Fast, secure public-key cryptography for tokens and inter-service authentication.",
|
||
},
|
||
{
|
||
icon: "i-lock",
|
||
grad: 6,
|
||
glow: "--glow-6",
|
||
title: "Strict RBAC",
|
||
body: "Role-Based Access Control enforced at the middleware layer before business logic executes.",
|
||
},
|
||
{
|
||
icon: "i-shield",
|
||
grad: 5,
|
||
glow: "--glow-5",
|
||
title: "CSRF & Security Headers",
|
||
body: "Double-submit cookies, strict transport security, and hardened Content Security Policies built-in.",
|
||
},
|
||
];
|
||
|
||
const securityGrid =
|
||
document.getElementById("securityGrid");
|
||
|
||
security.forEach(function (s) {
|
||
const card = document.createElement("article");
|
||
|
||
card.className = "card reveal";
|
||
card.style.setProperty(
|
||
"--card-grad",
|
||
"var(--grad-" + s.grad + ")",
|
||
);
|
||
card.style.setProperty(
|
||
"--card-glow",
|
||
"var(" + s.glow + ")",
|
||
);
|
||
|
||
card.innerHTML =
|
||
'<div class="icon-badge">' +
|
||
iconSvg(s.icon) +
|
||
"</div>" +
|
||
"<h3>" +
|
||
s.title +
|
||
"</h3>" +
|
||
"<p>" +
|
||
s.body +
|
||
"</p>";
|
||
|
||
securityGrid.appendChild(card);
|
||
});
|
||
|
||
/* == DATA: POSITIONING == */
|
||
const positioningBody =
|
||
document.getElementById("positioningBody");
|
||
|
||
const posData = [
|
||
{
|
||
bad: "Requires Kubernetes & Helm",
|
||
good: "Deployed via a single binary or systemd",
|
||
},
|
||
{
|
||
bad: "Hidden telemetry and usage analytics",
|
||
good: "Zero tracking, completely air-gapped capable",
|
||
},
|
||
{
|
||
bad: "1GB+ RAM for a 'Hello World' microservice",
|
||
good: "10-20MB RAM for a high-traffic production service",
|
||
},
|
||
{
|
||
bad: "Forced cloud subscriptions",
|
||
good: "Your hardware, your data, your rules",
|
||
},
|
||
{
|
||
bad: "Complex web of dependencies",
|
||
good: "Static binaries with SQLite built-in",
|
||
},
|
||
];
|
||
|
||
posData.forEach((p) => {
|
||
positioningBody.innerHTML += `<tr><td>${p.bad}</td><td>${p.good}</td></tr>`;
|
||
});
|
||
|
||
/* == DATA: PROJECTS == */
|
||
const projectGrid =
|
||
document.getElementById("projectGrid");
|
||
|
||
const projects = [
|
||
{
|
||
title: "nx9-url-shortener",
|
||
desc: "A lightweight, self-hosted URL management platform. Combines URL shortening, analytics, QR codes, password protection, and API automation with zero external dependencies.",
|
||
status: "STABLE",
|
||
icon: "i-link",
|
||
tech: ["Rust", "SQLite", "Axum", "Askama"],
|
||
grad: 2,
|
||
glow: "--glow-2",
|
||
link: "https://codeberg.org/thakares/nx9-url-shortener",
|
||
github: "https://github.com/thakares/nx9-url-shortener",
|
||
},
|
||
{
|
||
title: "nx9-auth",
|
||
desc: "Identity and Access Management (IAM) service. Provides authentication, authorization, session management, and RBAC in a single incredibly fast deployable binary.",
|
||
status: "BETA",
|
||
icon: "i-lock",
|
||
tech: ["Rust", "SQLite", "Security"],
|
||
grad: 4,
|
||
glow: "--glow-4",
|
||
link: "https://codeberg.org/thakares/nx9-auth",
|
||
github: "https://github.com/thakares/nx9-auth",
|
||
},
|
||
{
|
||
title: "nx9-dns-server",
|
||
desc: "High-performance, fully RFC-compliant authoritative DNS server leveraging modern async networking and a robust SQLite backend.",
|
||
status: "ALPHA",
|
||
icon: "i-globe",
|
||
tech: ["Rust", "DNS", "Async"],
|
||
grad: 6,
|
||
glow: "--glow-6",
|
||
link: "https://codeberg.org/thakares/nx9-dns-server",
|
||
github: "https://github.com/thakares/nx9-dns-server",
|
||
},
|
||
{
|
||
title: "nx9-chronoseal-rs",
|
||
desc: "Privacy-first browser attestation framework for anti-bot and anti-AI scraping. Uses Ed25519 heartbeat chains and WASM attestation without tracking users.",
|
||
status: "STABLE",
|
||
icon: "i-shield",
|
||
tech: ["Rust", "WASM", "Ed25519"],
|
||
grad: 5,
|
||
glow: "--glow-5",
|
||
link: "https://codeberg.org/thakares/nx9-chronoseal-rs",
|
||
github: "https://github.com/thakares/nx9-chronoseal-rs",
|
||
},
|
||
];
|
||
|
||
projects.forEach((p) => {
|
||
projectGrid.innerHTML += `
|
||
<div
|
||
class="project-card reveal"
|
||
style="--card-grad: var(--grad-${p.grad}); --card-glow: var(${p.glow})"
|
||
>
|
||
<div class="project-card-head">
|
||
<div class="project-title">
|
||
<div class="icon-badge">${iconSvg(p.icon)}</div>
|
||
<h3>${p.title}</h3>
|
||
</div>
|
||
<span
|
||
class="status-badge"
|
||
style="background: var(--grad-${
|
||
p.grad === 5
|
||
? 5
|
||
: p.grad === 4
|
||
? 4
|
||
: p.grad === 6
|
||
? 6
|
||
: 2
|
||
})"
|
||
>
|
||
${p.status}
|
||
</span>
|
||
</div>
|
||
|
||
<p class="desc">${p.desc}</p>
|
||
|
||
<div class="tech-badges">
|
||
${p.tech
|
||
.map(
|
||
(t) =>
|
||
`<span class="tech-badge" style="background: var(--grad-${p.grad})">${t}</span>`,
|
||
)
|
||
.join("")}
|
||
</div>
|
||
|
||
<div class="project-links">
|
||
<a
|
||
href="${p.link}"
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
class="btn btn-sm btn-outline"
|
||
>
|
||
<svg class="icon" style="width:14px;height:14px">
|
||
<use href="#i-git"/>
|
||
</svg>
|
||
Codeberg
|
||
</a>
|
||
|
||
<a
|
||
href="${p.github}"
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
class="btn btn-sm btn-outline"
|
||
>
|
||
<svg class="icon" style="width:14px;height:14px">
|
||
<use href="#i-link"/>
|
||
</svg>
|
||
GitHub
|
||
</a>
|
||
</div>
|
||
</div>
|
||
`;
|
||
});
|
||
|
||
/* == DATA: STATS == */
|
||
const statsGrid = document.getElementById("statsGrid");
|
||
|
||
const stats = [
|
||
{
|
||
num: "0",
|
||
label: "External Dependencies",
|
||
grad: 1,
|
||
},
|
||
{
|
||
num: "1",
|
||
label: "Binary to Deploy",
|
||
grad: 6,
|
||
},
|
||
{
|
||
num: "9",
|
||
label: "Core Projects",
|
||
grad: 4,
|
||
},
|
||
{
|
||
num: "<15MB",
|
||
label: "RAM per Service",
|
||
grad: 5,
|
||
},
|
||
];
|
||
|
||
stats.forEach((s) => {
|
||
statsGrid.innerHTML += `
|
||
<div
|
||
class="stat reveal"
|
||
style="--card-grad: var(--grad-${s.grad})"
|
||
>
|
||
<span class="num">${s.num}</span>
|
||
<span class="label">${s.label}</span>
|
||
</div>
|
||
`;
|
||
});
|
||
|
||
/* == DATA: VALUES == */
|
||
const valueGrid = document.getElementById("valueGrid");
|
||
|
||
const values = [
|
||
{ num: "01", text: "User Ownership", grad: 1, glow: "--glow-1" },
|
||
{ num: "02", text: "Absolute Privacy", grad: 2, glow: "--glow-2" },
|
||
{ num: "03", text: "Open Source", grad: 3, glow: "--glow-3" },
|
||
{ num: "04", text: "Simplicity First", grad: 4, glow: "--glow-4" },
|
||
{ num: "05", text: "CLI Automation", grad: 5, glow: "--glow-5" },
|
||
{ num: "06", text: "Open Standards", grad: 6, glow: "--glow-6" },
|
||
{ num: "07", text: "Long-term Stability", grad: 7, glow: "--glow-7" },
|
||
{ num: "08", text: "Linux Native", grad: 1, glow: "--glow-1" },
|
||
{ num: "09", text: "Zero Tracking", grad: 2, glow: "--glow-2" },
|
||
{ num: "10", text: "No Vendor Lock", grad: 3, glow: "--glow-3" },
|
||
{ num: "11", text: "Performant", grad: 4, glow: "--glow-4" },
|
||
{ num: "12", text: "Understandable", grad: 5, glow: "--glow-5" },
|
||
];
|
||
|
||
values.forEach((v) => {
|
||
valueGrid.innerHTML += `
|
||
<div
|
||
class="value-chip reveal"
|
||
style="--card-grad: var(--grad-${v.grad}); --card-glow: var(${v.glow})"
|
||
>
|
||
<span class="n">${v.num}</span>
|
||
<span class="t">${v.text}</span>
|
||
</div>
|
||
`;
|
||
});
|
||
|
||
/* == DATA: ROADMAP == */
|
||
const circuit = document.getElementById("circuit");
|
||
|
||
const roadmap = [
|
||
{ num: "01", name: "ChronoSeal", state: "STABLE", active: true },
|
||
{ num: "02", name: "DNS Server", state: "ALPHA", active: true },
|
||
{ num: "03", name: "Auth", state: "BETA", active: true },
|
||
{ num: "04", name: "URL Shortener", state: "STABLE", active: true },
|
||
{ num: "05", name: "Project 5", state: "PLANNED", active: false },
|
||
{ num: "06", name: "Project 6", state: "PLANNED", active: false },
|
||
{ num: "07", name: "Project 7", state: "PLANNED", active: false },
|
||
{ num: "08", name: "Project 8", state: "PLANNED", active: false },
|
||
{ num: "09", name: "Project 9", state: "PLANNED", active: false },
|
||
];
|
||
|
||
roadmap.forEach((r) => {
|
||
circuit.innerHTML += `
|
||
<div class="node ${r.active ? "is-active" : ""} reveal">
|
||
<div class="pad">${r.num}</div>
|
||
<div class="text">
|
||
<div class="name">${r.name}</div>
|
||
<div class="state">${r.state}</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
});
|
||
|
||
/* == REVEAL ANIMATIONS == */
|
||
const observerOptions = {
|
||
root: null,
|
||
rootMargin: "0px",
|
||
threshold: 0.1,
|
||
};
|
||
|
||
const observer = new IntersectionObserver(
|
||
(entries, observer) => {
|
||
entries.forEach((entry) => {
|
||
if (entry.isIntersecting) {
|
||
entry.target.classList.add("is-visible");
|
||
observer.unobserve(entry.target);
|
||
}
|
||
});
|
||
},
|
||
observerOptions,
|
||
);
|
||
|
||
document
|
||
.querySelectorAll(".reveal")
|
||
.forEach((el) => observer.observe(el));
|
||
|
||
// Set copyright year
|
||
document.getElementById("year").textContent =
|
||
new Date().getFullYear();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|