add website and GitHub Pages deployment

This commit is contained in:
Astral
2026-09-01 11:23:34 +02:00
parent cb1da62339
commit da28f784a8
48 changed files with 3392 additions and 0 deletions
+433
View File
@@ -0,0 +1,433 @@
/* Keru OS website — dark, modern, animated.
Reference: Gentoo's confident tech look, modernized. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;700&display=swap');
:root {
--bg: #0a0e14; /* near-black blue */
--bg-2: #0f1520; /* raised surface */
--bg-3: #161e2e; /* cards */
--border: #22304a;
--text: #d7e0ee;
--text-dim: #8b9bb4;
--text-bright: #ffffff;
--accent: #8b5cf6; /* keru violet */
--accent-2: #22d3ee; /* cyan secondary */
--accent-3: #34d399; /* green success */
--warn: #f59e0b; /* amber */
--danger: #ef4444;
--code-bg: #0d1220;
--mono: 'JetBrains Mono', ui-monospace, monospace;
--sans: 'Inter', system-ui, -apple-system, sans-serif;
--grad: linear-gradient(135deg, var(--accent), var(--accent-2));
--shadow: 0 8px 30px rgba(0,0,0,.4);
--radius: 12px;
--nav-h: 64px;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
background: var(--bg);
color: var(--text);
font-family: var(--sans);
line-height: 1.65;
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
}
/* subtle animated grid backdrop */
body::before {
content: "";
position: fixed;
inset: 0;
z-index: -1;
background:
radial-gradient(circle at 20% -10%, rgba(139,92,246,.12), transparent 45%),
radial-gradient(circle at 90% 10%, rgba(34,211,238,.08), transparent 40%),
repeating-linear-gradient(0deg, transparent 0 39px, rgba(255,255,255,.02) 39px 40px);
pointer-events: none;
}
a { color: var(--accent-2); text-decoration: none; }
a:hover { text-decoration: underline; }
::selection { background: var(--accent); color: #fff; }
/* ---------- top nav ---------- */
nav.top {
position: sticky;
top: 0;
z-index: 100;
height: var(--nav-h);
background: rgba(10,14,20,.82);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
padding: 0 28px;
gap: 8px;
}
.brand {
font-family: var(--mono);
font-weight: 700;
color: var(--text-bright);
font-size: 1.05rem;
letter-spacing: .02em;
margin-right: auto;
display: flex;
align-items: center;
gap: 8px;
}
.brand .kanji { color: var(--accent); }
.brand:hover { text-decoration: none; }
nav.top a.navlink {
color: var(--text-dim);
font-size: .92rem;
font-weight: 500;
padding: 6px 10px;
border-radius: 6px;
transition: color .15s, background .15s;
}
nav.top a.navlink:hover { color: var(--text-bright); background: var(--bg-3); text-decoration: none; }
.menu-toggle { display: none; }
/* ---------- hero ---------- */
.hero {
padding: 96px 28px 64px;
text-align: center;
animation: fadeUp .7s ease both;
}
.kicker {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: var(--mono);
color: var(--accent-2);
border: 1px solid var(--border);
background: var(--bg-2);
padding: 4px 12px;
border-radius: 999px;
font-size: .8rem;
letter-spacing: .08em;
text-transform: uppercase;
}
.kicker .dot {
width: 7px; height: 7px; border-radius: 50%;
background: var(--accent-3);
animation: pulse 2s infinite;
}
.hero h1 {
font-size: clamp(2.6rem, 6vw, 4.6rem);
font-weight: 800;
line-height: 1.05;
color: var(--text-bright);
margin: 22px auto 18px;
max-width: 900px;
letter-spacing: -.02em;
}
.hero h1 .grad {
background: var(--grad);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.hero p.sub {
max-width: 640px;
margin: 0 auto 30px;
color: var(--text-dim);
font-size: 1.12rem;
}
.cta-row { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: var(--mono);
font-weight: 500;
padding: 12px 22px;
border-radius: 10px;
font-size: .95rem;
transition: transform .15s, box-shadow .15s, background .15s;
}
.btn:hover { text-decoration: none; transform: translateY(-2px); }
.btn-primary { background: var(--grad); color: #0a0e14; box-shadow: 0 4px 20px rgba(139,92,246,.4); }
.btn-primary:hover { box-shadow: 0 8px 28px rgba(139,92,246,.55); }
.btn-ghost { background: var(--bg-3); color: var(--text); border: 1px solid var(--border); }
.btn-ghost:hover { background: var(--bg-2); }
/* ---------- sections ---------- */
section { padding: 56px 28px; }
.wrap { max-width: 1080px; margin: 0 auto; }
.section-title {
font-family: var(--mono);
text-transform: uppercase;
letter-spacing: .12em;
font-size: .82rem;
color: var(--accent-2);
margin-bottom: 10px;
}
h2.head { font-size: clamp(1.6rem, 3.5vw, 2.4rem); color: var(--text-bright); font-weight: 700; margin-bottom: 14px; letter-spacing: -.01em; }
.lead { color: var(--text-dim); font-size: 1.05rem; max-width: 720px; margin-bottom: 30px; }
.grid { display: grid; gap: 22px; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.card {
background: var(--bg-3);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 22px;
transition: transform .2s, border-color .2s, box-shadow .2s;
animation: fadeUp .6s ease both;
}
.card:hover { transform: translateY(-4px); border-color: var(--accent); box-shadow: var(--shadow); }
.card.h { font-family: var(--mono); font-size: 1.05rem; color: var(--text-bright); margin-bottom: 8px; }
.card p { color: var(--text-dim); font-size: .95rem; }
.card .num {
font-family: var(--mono);
font-size: .75rem;
color: var(--accent-2);
border: 1px solid var(--border);
padding: 2px 8px;
border-radius: 6px;
display: inline-block;
margin-bottom: 10px;
}
/* ---------- terminal/snippet ---------- */
.terminal {
background: #05080d;
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
box-shadow: var(--shadow);
text-align: left;
margin: 0 auto;
max-width: 640px;
}
.terminal .tbar {
background: var(--bg-2);
padding: 10px 14px;
display: flex;
gap: 6px;
align-items: center;
border-bottom: 1px solid var(--border);
}
.terminal .tbar span.dot { width: 11px; height: 11px; border-radius: 50%; display: inline-block; }
.terminal .tbar .r { background: var(--danger); }
.terminal .tbar .y { background: var(--warn); }
.terminal .tbar .g { background: var(--accent-3); }
.terminal .tbar .t { margin-left: 8px; font-family: var(--mono); font-size: .75rem; color: var(--text-dim); }
.terminal pre {
padding: 18px;
overflow-x: auto;
font-family: var(--mono);
font-size: .85rem;
line-height: 1.7;
color: var(--text);
}
.terminal .c { color: var(--accent-2); }
.terminal .k { color: var(--accent-3); }
.terminal .p { color: var(--text-dim); }
/* ---------- code blocks ---------- */
pre, code, kbd {
font-family: var(--mono);
}
.code-block {
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 10px;
padding: 18px;
overflow-x: auto;
margin: 18px 0;
font-size: .85rem;
line-height: 1.7;
color: var(--text);
}
code:not(.code-block) {
background: var(--bg-3);
border: 1px solid var(--border);
border-radius: 5px;
padding: 2px 6px;
font-size: .85em;
color: var(--accent-2);
}
kbd {
background: var(--bg-3);
border: 1px solid var(--border);
border-bottom-width: 2px;
border-radius: 5px;
padding: 1px 6px;
font-size: .8em;
}
/* ---------- lists / prose ---------- */
.prose { max-width: 760px; margin: 0 auto; }
.prose h3 {
color: var(--text-bright);
font-size: 1.25rem;
margin: 34px 0 10px;
font-weight: 700;
}
.prose h4 { color: var(--accent-2); margin: 22px 0 8px; font-size: 1.05rem; }
.prose p { margin: 12px 0; color: var(--text); }
.prose ul, .prose ol { margin: 12px 0 12px 24px; }
.prose li { margin: 6px 0; color: var(--text); }
.prose li::marker { color: var(--accent); }
.prose blockquote {
border-left: 3px solid var(--accent);
background: var(--bg-2);
padding: 14px 18px;
border-radius: 0 8px 8px 0;
margin: 18px 0;
color: var(--text-dim);
}
.prose blockquote strong { color: var(--text-bright); }
.prose hr { border: none; border-top: 1px solid var(--border); margin: 30px 0; }
table { border-collapse: collapse; width: 100%; margin: 18px 0; font-size: .92rem; }
th, td { border: 1px solid var(--border); padding: 9px 12px; text-align: left; }
th { background: var(--bg-2); color: var(--text-bright); font-family: var(--mono); font-size: .82rem; }
tr:nth-child(even) td { background: rgba(255,255,255,.015); }
/* tag chips */
.tag {
display: inline-block;
font-family: var(--mono);
font-size: .72rem;
letter-spacing: .05em;
text-transform: uppercase;
padding: 2px 9px;
border-radius: 999px;
border: 1px solid var(--border);
color: var(--accent-2);
margin: 2px 4px 2px 0;
}
.tag.warn { color: var(--warn); border-color: rgba(245,158,11,.4); }
.tag.danger { color: var(--danger); border-color: rgba(239,68,68,.4); }
.tag.ok { color: var(--accent-3); border-color: rgba(52,211,153,.4); }
/* pill callout */
.callout {
border: 1px solid var(--border);
border-left: 3px solid var(--accent);
background: var(--bg-2);
border-radius: 8px;
padding: 14px 18px;
margin: 18px 0;
}
.callout.warn { border-left-color: var(--warn); }
.callout.danger { border-left-color: var(--danger); }
.callout.ok { border-left-color: var(--accent-3); }
/* ---------- comparison tables / feature list ---------- */
.features { list-style: none; margin: 0; }
.features li { padding: 10px 0; border-bottom: 1px solid var(--border); display: flex; gap: 12px; }
.features li::before { content: "◆"; color: var(--accent); }
/* ---------- news ---------- */
.post-list { max-width: 820px; margin: 0 auto; }
.post-item {
display: block;
background: var(--bg-3);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 20px 24px;
margin-bottom: 16px;
transition: transform .15s, border-color .15s;
}
.post-item:hover { transform: translateX(4px); border-color: var(--accent); text-decoration: none; }
.post-item h3 { color: var(--text-bright); font-size: 1.2rem; margin-bottom: 6px; }
.post-item .meta { font-family: var(--mono); font-size: .78rem; color: var(--text-dim); margin-bottom: 6px; }
.post-item p { color: var(--text-dim); font-size: .95rem; }
/* ---------- footer ---------- */
footer {
border-top: 1px solid var(--border);
background: var(--bg-2);
padding: 40px 28px 32px;
margin-top: 40px;
}
footer .wrap { display: flex; gap: 40px; flex-wrap: wrap; justify-content: space-between; }
footer h4 { color: var(--text-bright); font-family: var(--mono); font-size: .85rem; text-transform: uppercase; letter-spacing: .1em; margin-bottom: 12px; }
footer ul { list-style: none; }
footer li { margin: 6px 0; }
footer a { color: var(--text-dim); }
footer a:hover { color: var(--text-bright); text-decoration: none; }
footer .foot {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid var(--border);
font-family: var(--mono);
font-size: .78rem;
color: var(--text-dim);
text-align: center;
}
footer .marks { font-family: var(--mono); color: var(--accent-2); }
/* ---------- animation utilities ---------- */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(18px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: .35; }
}
.reveal { animation: fadeUp .7s ease both; }
.d1 { animation-delay: .1s; }
.d2 { animation-delay: .2s; }
.d3 { animation-delay: .3s; }
.d4 { animation-delay: .4s; }
/* scrolling feature ticker on landing */
.ticker {
overflow: hidden;
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
padding: 14px 0;
background: var(--bg-2);
white-space: nowrap;
}
.ticker-inner {
display: inline-block;
animation: ticker 30s linear infinite;
font-family: var(--mono);
color: var(--text-dim);
}
.ticker-inner span { margin: 0 28px; }
.ticker-inner b { color: var(--accent-2); }
@keyframes ticker { from { transform: translateX(0); } to { transform: translateX(-50%); } }
/* stat blocks */
.stats { display: flex; gap: 28px; flex-wrap: wrap; justify-content: center; margin: 24px 0; }
.stat { text-align: center; }
.stat .big { font-family: var(--mono); font-size: 2.4rem; font-weight: 700; color: var(--text-bright); background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
.stat .lbl { color: var(--text-dim); font-size: .85rem; }
/* page header (non-hero pages) */
.pagehead { padding: 72px 28px 32px; text-align: center; }
.pagehead h1 { color: var(--text-bright); font-size: clamp(2rem, 5vw, 3.2rem); font-weight: 800; letter-spacing: -.02em; }
.pagehead p { color: var(--text-dim); max-width: 640px; margin: 14px auto 0; }
/* breadcrumb */
.crumbs { font-family: var(--mono); font-size: .78rem; color: var(--text-dim); max-width: 760px; margin: 20px auto 0; }
.crumbs a { color: var(--accent-2); }
/* responsive */
@media (max-width: 720px) {
nav.top { padding: 0 14px; }
nav.top a.navlink { display: none; }
.menu-toggle { display: inline-flex; }
.hero { padding: 64px 18px 40px; }
section { padding: 40px 18px; }
footer .wrap { gap: 24px; }
}
+41
View File
@@ -0,0 +1,41 @@
/* Keru website — inject shared nav + footer partials.
Usage:
<nav data-nav></nav>
<footer data-footer></footer>
<script src="assets/js/include.js" data-base="."></script>
data-base is the path prefix from this page to the web root.
All links inside the injected partials are resolved against that base. */
(function () {
var base = '.';
var scripts = document.querySelectorAll('script[src*="include.js"]');
for (var i = 0; i < scripts.length; i++) {
if (scripts[i].dataset.base) base = scripts[i].dataset.base;
}
var nav = document.querySelector('[data-nav]');
var footer = document.querySelector('[data-footer]');
function fill(el, url) {
if (!el) return;
fetch(base + '/' + url)
.then(function (r) { return r.text(); })
.then(function (t) {
// resolve links/asset refs in the partial against base
var div = document.createElement('div');
div.innerHTML = t;
['a', 'link', 'script', 'img'].forEach(function (sel) {
var nodes = div.querySelectorAll(sel + '[href], ' + sel + '[src]');
for (var j = 0; j < nodes.length; j++) {
var n = nodes[j];
var attr = n.hasAttribute('href') ? 'href' : 'src';
var val = n.getAttribute(attr);
if (val && val.indexOf('./') === 0) {
n.setAttribute(attr, base + '/' + val.replace(/^\.\//, ''));
}
}
});
el.innerHTML = div.innerHTML;
})
.catch(function () { /* offline / file:// — nav/footer stay empty */ });
}
fill(nav, '_includes/nav.html');
fill(footer, '_includes/footer.html');
})();