web-ui(wave 2): migrate home.html to new primitives

Swap stylesheet to /dist/app.css. Sidebar markup ported to wd-sidebar /
wd-nav-item / wd-sidebar-* primitives (active state = leading accent dot).
Logout button promoted to wd-btn--ghost--sm--icon.

Hero (portrait, wordmark, tagline) and the 10 illustrated cards keep
their bespoke design — they're a brand moment. Hardcoded oklch values
in the inline style replaced with var(--accent-bright), var(--signal-bad),
var(--bg-base), var(--accent-border), var(--overlay), etc. wherever the
brand palette already provides them.

All JS ids preserved (assetCount, projectCount, recorderCount,
containerCount, nodeCount, jobCount, ingestCount, captureStatus,
tokenBurn, userAvatar, userName, userRole, logoutBtn, systemBuild).
loadStats() poll cycle unchanged.
This commit is contained in:
Zac Gaetano 2026-05-21 13:19:16 -04:00
parent 16a34a2fad
commit e0cfe80a9e

View file

@ -5,9 +5,13 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<title>Home — Z-AMPP</title> <title>Home — Z-AMPP</title>
<link rel="stylesheet" href="css/common.css"> <link rel="stylesheet" href="/dist/app.css">
<style> <style>
/* AMPP-style landing — wide row of preview cards on a brand-blue gradient */ /* Page-only layout. Sidebar + all chrome is from /dist/app.css primitives.
Hero / cards / SVG art are bespoke to the home landing page. */
body { margin: 0; }
.wd-shell { display: flex; min-height: 100vh; }
.home-main { .home-main {
flex: 1; flex: 1;
overflow: auto; overflow: auto;
@ -16,7 +20,7 @@
radial-gradient(ellipse 70% 50% at 50% 0%, oklch(35% 0.16 266 / 0.55), transparent 65%), radial-gradient(ellipse 70% 50% at 50% 0%, oklch(35% 0.16 266 / 0.55), transparent 65%),
radial-gradient(ellipse 80% 60% at 30% 90%, oklch(40% 0.20 266 / 0.45), transparent 70%), radial-gradient(ellipse 80% 60% at 30% 90%, oklch(40% 0.20 266 / 0.45), transparent 70%),
radial-gradient(ellipse 60% 50% at 80% 80%, oklch(45% 0.18 240 / 0.30), transparent 65%), radial-gradient(ellipse 60% 50% at 80% 80%, oklch(45% 0.18 240 / 0.30), transparent 65%),
linear-gradient(135deg, oklch(20% 0.05 260), oklch(12% 0.025 250) 100%); linear-gradient(135deg, oklch(20% 0.05 260), var(--bg-base) 100%);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@ -40,8 +44,8 @@
overflow: hidden; position: relative; overflow: hidden; position: relative;
background: background:
radial-gradient(ellipse at 40% 30%, oklch(35% 0.18 266 / 0.4), transparent 65%), radial-gradient(ellipse at 40% 30%, oklch(35% 0.18 266 / 0.4), transparent 65%),
linear-gradient(135deg, oklch(20% 0.04 260), oklch(8% 0.015 250)); linear-gradient(135deg, var(--bg-surface), var(--bg-deep));
border: 2px solid oklch(55% 0.20 266 / 0.5); border: 2px solid var(--accent-border);
box-shadow: box-shadow:
0 20px 50px -10px oklch(45% 0.20 266 / 0.4), 0 20px 50px -10px oklch(45% 0.20 266 / 0.4),
inset 0 1px 0 oklch(100% 0 0 / 0.08); inset 0 1px 0 oklch(100% 0 0 / 0.08);
@ -55,34 +59,32 @@
.home-portrait-dot { .home-portrait-dot {
position: absolute; bottom: 4px; right: 4px; position: absolute; bottom: 4px; right: 4px;
width: 18px; height: 18px; width: 18px; height: 18px;
background: oklch(62% 0.22 25); background: var(--signal-bad);
border: 3px solid oklch(15% 0.025 250); border: 3px solid var(--bg-panel);
border-radius: 50%; border-radius: 50%;
box-shadow: 0 0 12px oklch(62% 0.22 25); box-shadow: 0 0 12px var(--signal-bad);
animation: live-pulse 1.6s ease-in-out infinite; animation: live-pulse 1.6s ease-in-out infinite;
} }
@keyframes live-pulse { @keyframes live-pulse {
0%, 100% { opacity: 0.85; transform: scale(1); } 0%, 100% { opacity: 0.85; transform: scale(1); }
50% { opacity: 1; transform: scale(1.1); } 50% { opacity: 1; transform: scale(1.1); }
} }
.home-wordmark-svg { width: min(380px, 70vw); height: auto; filter: drop-shadow(0 16px 30px oklch(35% 0.18 266 / 0.45)); margin-bottom: -10px; } .home-wordmark-svg {
.home-wordmark { width: min(380px, 70vw);
font-size: 36px; font-weight: 700; height: auto;
letter-spacing: -0.02em; filter: drop-shadow(0 16px 30px oklch(35% 0.18 266 / 0.45));
color: var(--text-primary); margin-bottom: -10px;
line-height: 1;
} }
.home-wordmark .accent { color: oklch(70% 0.18 266); }
.home-tagline { .home-tagline {
display: flex; align-items: center; gap: 12px; display: flex; align-items: center; gap: 12px;
font-size: 17px; font-weight: 500; font: 500 17px/1 var(--font);
color: oklch(75% 0.10 240); color: oklch(75% 0.10 240);
letter-spacing: 0.005em; letter-spacing: 0.005em;
} }
.home-tagline::before { .home-tagline::before {
content: ''; width: 3px; height: 18px; content: ''; width: 3px; height: 18px;
background: oklch(70% 0.18 266); background: var(--accent-bright);
border-radius: 2px; border-radius: 2px;
} }
@ -100,7 +102,7 @@
min-width: 200px; min-width: 200px;
max-width: 220px; max-width: 220px;
background: oklch(12% 0.020 250 / 0.85); background: oklch(12% 0.020 250 / 0.85);
border: 1px solid oklch(30% 0.04 260 / 0.5); border: 1px solid var(--border-faint);
border-radius: 10px; border-radius: 10px;
overflow: hidden; overflow: hidden;
text-decoration: none; text-decoration: none;
@ -109,26 +111,28 @@
flex-direction: column; flex-direction: column;
cursor: pointer; cursor: pointer;
backdrop-filter: blur(6px); backdrop-filter: blur(6px);
transition: transform 200ms ease, border-color 200ms ease, box-shadow 200ms ease; transition: transform var(--dur-slide) var(--ease-out-quart),
border-color var(--dur-slide) var(--ease-out-quart),
box-shadow var(--dur-slide) var(--ease-out-quart);
} }
.home-card:hover { .home-card:hover {
transform: translateY(-4px); transform: translateY(-4px);
border-color: oklch(55% 0.20 266 / 0.6); border-color: var(--accent-border);
box-shadow: 0 24px 50px -16px oklch(45% 0.20 266 / 0.4); box-shadow: 0 24px 50px -16px oklch(45% 0.20 266 / 0.4);
} }
.home-card-title { .home-card-title {
padding: 12px 16px 10px; padding: 12px 16px 10px;
font-size: 15px; font-weight: 500; font: 500 15px/1.2 var(--font);
letter-spacing: 0.005em; letter-spacing: 0.005em;
color: var(--text-primary); color: var(--text-primary);
} }
.home-card-preview { .home-card-preview {
position: relative; position: relative;
aspect-ratio: 16/10; aspect-ratio: 16/10;
background: linear-gradient(135deg, oklch(18% 0.030 260), oklch(10% 0.015 250)); background: linear-gradient(135deg, var(--bg-surface), var(--bg-base));
overflow: hidden; overflow: hidden;
border-top: 1px solid oklch(28% 0.04 260 / 0.4); border-top: 1px solid var(--border-faint);
border-bottom: 1px solid oklch(28% 0.04 260 / 0.4); border-bottom: 1px solid var(--border-faint);
} }
.home-card-preview svg.preview-art { .home-card-preview svg.preview-art {
position: absolute; inset: 0; position: absolute; inset: 0;
@ -137,12 +141,12 @@
.home-card-stats { .home-card-stats {
position: absolute; bottom: 8px; left: 10px; position: absolute; bottom: 8px; left: 10px;
display: inline-flex; align-items: center; gap: 6px; display: inline-flex; align-items: center; gap: 6px;
background: oklch(10% 0.015 250 / 0.8); background: var(--overlay);
backdrop-filter: blur(6px); backdrop-filter: blur(6px);
padding: 3px 8px; padding: 3px 8px;
border-radius: 999px; border-radius: 999px;
border: 1px solid oklch(28% 0.04 260 / 0.4); border: 1px solid var(--border-faint);
font-size: 10px; font-family: var(--font-mono); font: 400 10px/1 var(--font-mono);
letter-spacing: 0.04em; letter-spacing: 0.04em;
color: var(--text-secondary); color: var(--text-secondary);
} }
@ -153,7 +157,7 @@
} }
.home-card-desc { .home-card-desc {
padding: 12px 16px 16px; padding: 12px 16px 16px;
font-size: 11.5px; line-height: 1.5; font: 400 11.5px/1.5 var(--font);
color: var(--text-secondary); color: var(--text-secondary);
} }
@ -162,21 +166,22 @@
display: flex; align-items: center; gap: 10px; display: flex; align-items: center; gap: 10px;
justify-content: center; justify-content: center;
color: var(--text-tertiary); color: var(--text-tertiary);
font-size: 11px; letter-spacing: 0.08em; font: 400 11px/1 var(--font);
letter-spacing: 0.08em;
text-transform: uppercase; text-transform: uppercase;
} }
.home-footer-mark { .home-footer-mark {
display: inline-flex; align-items: center; gap: 8px; display: inline-flex; align-items: center; gap: 8px;
font-weight: 700; color: var(--text-secondary); font-weight: 700;
color: var(--text-secondary);
} }
.home-footer-mark-dot { .home-footer-mark-dot {
width: 6px; height: 6px; border-radius: 50%; width: 6px; height: 6px; border-radius: 50%;
background: oklch(70% 0.18 266); background: var(--accent-bright);
} }
@media (max-width: 900px) { @media (max-width: 900px) {
.home-stage { padding: 32px 16px; gap: 24px; } .home-stage { padding: 32px 16px; gap: 24px; }
.home-wordmark { font-size: 28px; }
.home-portrait { width: 96px; height: 96px; } .home-portrait { width: 96px; height: 96px; }
.home-cards { gap: 12px; padding: 0 12px; } .home-cards { gap: 12px; padding: 0 12px; }
.home-card { min-width: 150px; } .home-card { min-width: 150px; }
@ -185,82 +190,82 @@
</head> </head>
<body> <body>
<div class="shell"> <div class="wd-shell">
<nav class="sidebar" aria-label="Main navigation"> <nav class="wd-sidebar" aria-label="Main navigation">
<div class="sidebar-brand"> <div class="wd-sidebar-header">
<img src="img/dragon-logo.png?v=1" alt="Wild Dragon" class="sidebar-logo"> <img src="img/dragon-logo.png?v=1" alt="Wild Dragon" style="width:18px;height:18px;">
<span class="sidebar-brand-name">Z-AMPP</span> <span class="wd-sidebar-brand">Z-AMPP</span>
</div> </div>
<nav class="sidebar-nav"> <div class="wd-sidebar-nav">
<a href="home.html" class="nav-item active"> <a href="home.html" class="wd-nav-item is-active">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 7l6-5 6 5v7a1 1 0 0 1-1 1h-3v-5H6v5H3a1 1 0 0 1-1-1z"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 7l6-5 6 5v7a1 1 0 0 1-1 1h-3v-5H6v5H3a1 1 0 0 1-1-1z"/></svg>
Home Home
</a> </a>
<a href="index.html" class="nav-item"> <a href="index.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>
Library Library
</a> </a>
<a href="projects.html" class="nav-item"> <a href="projects.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M1 4a1 1 0 0 1 1-1h4l2 2h5a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1z"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M1 4a1 1 0 0 1 1-1h4l2 2h5a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1z"/></svg>
Projects Projects
</a> </a>
<a href="upload.html" class="nav-item"> <a href="upload.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M8 11V3M5 6l3-3 3 3"/><path d="M2 13h12"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M8 11V3M5 6l3-3 3 3"/><path d="M2 13h12"/></svg>
Ingest Ingest
</a> </a>
<a href="recorders.html" class="nav-item"> <a href="recorders.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="1" y="4" width="10" height="8" rx="1"/><path d="M11 7l4-2v6l-4-2"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="1" y="4" width="10" height="8" rx="1"/><path d="M11 7l4-2v6l-4-2"/></svg>
Recorders Recorders
</a> </a>
<a href="capture.html" class="nav-item"> <a href="capture.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="3"/><circle cx="8" cy="8" r="6.5"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="3"/><circle cx="8" cy="8" r="6.5"/></svg>
Capture Capture
</a> </a>
<a href="jobs.html" class="nav-item"> <a href="jobs.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 4h12M2 8h8M2 12h5"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 4h12M2 8h8M2 12h5"/></svg>
Jobs Jobs
</a> </a>
<a href="editor.html" class="nav-item"> <a href="editor.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 13l1.5-3.5L11 2l3 3-7.5 7.5L3 14zM10 3l3 3"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 13l1.5-3.5L11 2l3 3-7.5 7.5L3 14zM10 3l3 3"/></svg>
Editor Editor
</a> </a>
<div class="sidebar-section-label">Admin</div> <div class="wd-sidebar-section">Admin</div>
<a href="users.html" class="nav-item"> <a href="users.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="6" cy="5" r="2.5"/><path d="M1 13c0-2.8 2.2-5 5-5s5 2.2 5 5"/><circle cx="12" cy="5" r="2"/><path d="M15 12c0-1.9-1.3-3.5-3-4"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="6" cy="5" r="2.5"/><path d="M1 13c0-2.8 2.2-5 5-5s5 2.2 5 5"/><circle cx="12" cy="5" r="2"/><path d="M15 12c0-1.9-1.3-3.5-3-4"/></svg>
Users Users
</a> </a>
<a href="tokens.html" class="nav-item"> <a href="tokens.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="6" cy="10" r="3.5"/><path d="M8.7 7.3L13 3M11.5 3.5l1.5 1.5M13.5 2.5l1 1"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="6" cy="10" r="3.5"/><path d="M8.7 7.3L13 3M11.5 3.5l1.5 1.5M13.5 2.5l1 1"/></svg>
Tokens Tokens
</a> </a>
<a href="containers.html" class="nav-item"> <a href="containers.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="1" y="5" width="14" height="4" rx="1"/><rect x="1" y="10" width="14" height="4" rx="1"/><path d="M4 7h1M4 12h1"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="1" y="5" width="14" height="4" rx="1"/><rect x="1" y="10" width="14" height="4" rx="1"/><path d="M4 7h1M4 12h1"/></svg>
Containers Containers
</a> </a>
<a href="cluster.html" class="nav-item"> <a href="cluster.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="2"/><circle cx="2" cy="3" r="1.5"/><circle cx="14" cy="3" r="1.5"/><circle cx="2" cy="13" r="1.5"/><circle cx="14" cy="13" r="1.5"/><path d="M3.1 4.1L6.5 6.5M12.9 4.1L9.5 6.5M3.1 11.9L6.5 9.5M12.9 11.9L9.5 9.5"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="2"/><circle cx="2" cy="3" r="1.5"/><circle cx="14" cy="3" r="1.5"/><circle cx="2" cy="13" r="1.5"/><circle cx="14" cy="13" r="1.5"/><path d="M3.1 4.1L6.5 6.5M12.9 4.1L9.5 6.5M3.1 11.9L6.5 9.5M12.9 11.9L9.5 9.5"/></svg>
Cluster Cluster
</a> </a>
<a href="settings.html" class="nav-item"> <a href="settings.html" class="wd-nav-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="2.5"/><path d="M8 1v1.5M8 13.5V15M1 8h1.5M13.5 8H15M2.9 2.9l1.1 1.1M12 12l1.1 1.1M2.9 13.1L4 12M12 4l1.1-1.1"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="2.5"/><path d="M8 1v1.5M8 13.5V15M1 8h1.5M13.5 8H15M2.9 2.9l1.1 1.1M12 12l1.1 1.1M2.9 13.1L4 12M12 4l1.1-1.1"/></svg>
Settings Settings
</a> </a>
</nav> </div>
<div class="sidebar-footer"> <div class="wd-sidebar-footer">
<div class="sidebar-user"> <div class="wd-sidebar-user">
<div class="sidebar-user-avatar" id="userAvatar">?</div> <div class="wd-sidebar-user-avatar" id="userAvatar">?</div>
<div class="sidebar-user-info"> <div class="wd-sidebar-user-info">
<div class="sidebar-user-name" id="userName"></div> <div class="wd-sidebar-user-name" id="userName"></div>
<div class="sidebar-user-role" id="userRole"></div> <div class="wd-sidebar-user-role" id="userRole"></div>
</div> </div>
<button class="btn btn-ghost" id="logoutBtn" title="Sign out" style="padding:0;width:24px;height:24px;flex-shrink:0;"> <button class="wd-btn wd-btn--ghost wd-btn--sm wd-btn--icon wd-sidebar-user-logout" id="logoutBtn" title="Sign out">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" width="14" height="14"><path d="M10 8H3M6 5l-3 3 3 3"/><path d="M7 3h5a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H7"/></svg> <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" width="12" height="12"><path d="M10 8H3M6 5l-3 3 3 3"/><path d="M7 3h5a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H7"/></svg>
</button> </button>
</div> </div>
</div> </div>
</nav> </nav>
<div class="main home-main"> <div class="home-main">
<div class="home-stage"> <div class="home-stage">
<div class="home-brandmark"> <div class="home-brandmark">
<div class="home-portrait"> <div class="home-portrait">
@ -268,15 +273,15 @@
<span class="home-portrait-dot" title="On duty"></span> <span class="home-portrait-dot" title="On duty"></span>
</div> </div>
<svg class="home-wordmark-svg" viewBox="0 0 540 132" xmlns="http://www.w3.org/2000/svg" aria-label="Z-AMPP"> <svg class="home-wordmark-svg" viewBox="0 0 540 132" xmlns="http://www.w3.org/2000/svg" aria-label="Z-AMPP">
<defs> <defs>
<linearGradient id="zwm" x1="0" y1="0" x2="0" y2="1"> <linearGradient id="zwm" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="oklch(82% 0.14 220)"/> <stop offset="0" stop-color="oklch(82% 0.14 220)"/>
<stop offset="0.55" stop-color="oklch(58% 0.18 245)"/> <stop offset="0.55" stop-color="oklch(58% 0.18 245)"/>
<stop offset="1" stop-color="oklch(32% 0.16 265)"/> <stop offset="1" stop-color="oklch(32% 0.16 265)"/>
</linearGradient> </linearGradient>
</defs> </defs>
<text x="0" y="108" font-family="Inter, system-ui, sans-serif" font-weight="900" font-size="132" letter-spacing="-8" fill="url(#zwm)">Z-AMPP</text> <text x="0" y="108" font-family="Inter, system-ui, sans-serif" font-weight="900" font-size="132" letter-spacing="-8" fill="url(#zwm)">Z-AMPP</text>
</svg> </svg>
</div> </div>
<div class="home-tagline">Please select an option below to get started</div> <div class="home-tagline">Please select an option below to get started</div>
@ -344,7 +349,7 @@
</svg> </svg>
<span class="home-card-stats"><span class="home-card-stats-dot"></span><b id="ingestCount">--</b>&nbsp;processing</span> <span class="home-card-stats"><span class="home-card-stats-dot"></span><b id="ingestCount">--</b>&nbsp;processing</span>
</div> </div>
<div class="home-card-desc">Upload finished files. MOV, MP4, MXF, ProRes drop them, we proxy them.</div> <div class="home-card-desc">Upload finished files. MOV, MP4, MXF, ProRes, drop them, we proxy them.</div>
</a> </a>
<a href="recorders.html" class="home-card"> <a href="recorders.html" class="home-card">
@ -357,7 +362,7 @@
<path d="M140 62 L182 42 L182 82 Z" fill="oklch(20% 0.04 260)" stroke="oklch(45% 0.10 266 / 0.4)" stroke-width="0.5"/> <path d="M140 62 L182 42 L182 82 Z" fill="oklch(20% 0.04 260)" stroke="oklch(45% 0.10 266 / 0.4)" stroke-width="0.5"/>
<circle cx="160" cy="62" r="6" fill="oklch(62% 0.22 25)"><animate attributeName="opacity" values="1;0.5;1" dur="1.6s" repeatCount="indefinite"/></circle> <circle cx="160" cy="62" r="6" fill="oklch(62% 0.22 25)"><animate attributeName="opacity" values="1;0.5;1" dur="1.6s" repeatCount="indefinite"/></circle>
</svg> </svg>
<span class="home-card-stats"><span class="home-card-stats-dot" style="background:oklch(62% 0.22 25);box-shadow:0 0 6px oklch(62% 0.22 25)"></span><b id="recorderCount">--</b>&nbsp;live</span> <span class="home-card-stats"><span class="home-card-stats-dot" style="background:var(--signal-bad);box-shadow:0 0 6px var(--signal-bad)"></span><b id="recorderCount">--</b>&nbsp;live</span>
</div> </div>
<div class="home-card-desc">Pull SRT, RTMP, and SDI feeds straight to ProRes with a live HLS preview.</div> <div class="home-card-desc">Pull SRT, RTMP, and SDI feeds straight to ProRes with a live HLS preview.</div>
</a> </a>
@ -426,19 +431,16 @@
<div class="home-card-preview"> <div class="home-card-preview">
<svg class="preview-art" viewBox="0 0 200 125" xmlns="http://www.w3.org/2000/svg"> <svg class="preview-art" viewBox="0 0 200 125" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="200" height="125" fill="oklch(13% 0.02 250)"/> <rect x="0" y="0" width="200" height="125" fill="oklch(13% 0.02 250)"/>
<!-- stacked container boxes -->
<g fill="oklch(20% 0.04 260)" stroke="oklch(45% 0.10 266 / 0.45)" stroke-width="0.6"> <g fill="oklch(20% 0.04 260)" stroke="oklch(45% 0.10 266 / 0.45)" stroke-width="0.6">
<rect x="20" y="18" width="160" height="22" rx="3"/> <rect x="20" y="18" width="160" height="22" rx="3"/>
<rect x="20" y="46" width="160" height="22" rx="3"/> <rect x="20" y="46" width="160" height="22" rx="3"/>
<rect x="20" y="74" width="160" height="22" rx="3"/> <rect x="20" y="74" width="160" height="22" rx="3"/>
<rect x="20" y="102" width="160" height="16" rx="3"/> <rect x="20" y="102" width="160" height="16" rx="3"/>
</g> </g>
<!-- status dots -->
<circle cx="34" cy="29" r="3.5" fill="oklch(62% 0.22 145)"/> <circle cx="34" cy="29" r="3.5" fill="oklch(62% 0.22 145)"/>
<circle cx="34" cy="57" r="3.5" fill="oklch(62% 0.22 145)"/> <circle cx="34" cy="57" r="3.5" fill="oklch(62% 0.22 145)"/>
<circle cx="34" cy="85" r="3.5" fill="oklch(62% 0.22 145)"/> <circle cx="34" cy="85" r="3.5" fill="oklch(62% 0.22 145)"/>
<circle cx="34" cy="110" r="3.5" fill="oklch(62% 0.22 25)"/> <circle cx="34" cy="110" r="3.5" fill="oklch(62% 0.22 25)"/>
<!-- label bars -->
<rect x="46" y="25" width="60" height="5" rx="2" fill="oklch(50% 0.12 266 / 0.7)"/> <rect x="46" y="25" width="60" height="5" rx="2" fill="oklch(50% 0.12 266 / 0.7)"/>
<rect x="46" y="53" width="80" height="5" rx="2" fill="oklch(50% 0.12 266 / 0.7)"/> <rect x="46" y="53" width="80" height="5" rx="2" fill="oklch(50% 0.12 266 / 0.7)"/>
<rect x="46" y="81" width="50" height="5" rx="2" fill="oklch(50% 0.12 266 / 0.7)"/> <rect x="46" y="81" width="50" height="5" rx="2" fill="oklch(50% 0.12 266 / 0.7)"/>
@ -446,7 +448,7 @@
</svg> </svg>
<span class="home-card-stats"><span class="home-card-stats-dot"></span><b id="containerCount">--</b>&nbsp;running</span> <span class="home-card-stats"><span class="home-card-stats-dot"></span><b id="containerCount">--</b>&nbsp;running</span>
</div> </div>
<div class="home-card-desc">Manage Docker Compose services start, stop, and restart containers.</div> <div class="home-card-desc">Manage Docker Compose services, start, stop, and restart containers.</div>
</a> </a>
<a href="cluster.html" class="home-card"> <a href="cluster.html" class="home-card">
@ -454,22 +456,18 @@
<div class="home-card-preview"> <div class="home-card-preview">
<svg class="preview-art" viewBox="0 0 200 125" xmlns="http://www.w3.org/2000/svg"> <svg class="preview-art" viewBox="0 0 200 125" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="200" height="125" fill="oklch(13% 0.02 250)"/> <rect x="0" y="0" width="200" height="125" fill="oklch(13% 0.02 250)"/>
<!-- hub -->
<circle cx="100" cy="62" r="10" fill="oklch(20% 0.04 260)" stroke="oklch(55% 0.20 266 / 0.7)" stroke-width="1"/> <circle cx="100" cy="62" r="10" fill="oklch(20% 0.04 260)" stroke="oklch(55% 0.20 266 / 0.7)" stroke-width="1"/>
<circle cx="100" cy="62" r="4" fill="oklch(70% 0.18 266)"/> <circle cx="100" cy="62" r="4" fill="oklch(70% 0.18 266)"/>
<!-- spokes -->
<line x1="100" y1="62" x2="36" y2="22" stroke="oklch(45% 0.12 266 / 0.4)" stroke-width="1"/> <line x1="100" y1="62" x2="36" y2="22" stroke="oklch(45% 0.12 266 / 0.4)" stroke-width="1"/>
<line x1="100" y1="62" x2="164" y2="22" stroke="oklch(45% 0.12 266 / 0.4)" stroke-width="1"/> <line x1="100" y1="62" x2="164" y2="22" stroke="oklch(45% 0.12 266 / 0.4)" stroke-width="1"/>
<line x1="100" y1="62" x2="24" y2="80" stroke="oklch(45% 0.12 266 / 0.4)" stroke-width="1"/> <line x1="100" y1="62" x2="24" y2="80" stroke="oklch(45% 0.12 266 / 0.4)" stroke-width="1"/>
<line x1="100" y1="62" x2="176" y2="80" stroke="oklch(45% 0.12 266 / 0.4)" stroke-width="1"/> <line x1="100" y1="62" x2="176" y2="80" stroke="oklch(45% 0.12 266 / 0.4)" stroke-width="1"/>
<line x1="100" y1="62" x2="100" y2="108" stroke="oklch(45% 0.12 266 / 0.4)" stroke-width="1"/> <line x1="100" y1="62" x2="100" y2="108" stroke="oklch(45% 0.12 266 / 0.4)" stroke-width="1"/>
<!-- satellite nodes -->
<circle cx="36" cy="22" r="7" fill="oklch(18% 0.03 260)" stroke="oklch(45% 0.10 266 / 0.5)" stroke-width="0.6"/> <circle cx="36" cy="22" r="7" fill="oklch(18% 0.03 260)" stroke="oklch(45% 0.10 266 / 0.5)" stroke-width="0.6"/>
<circle cx="164" cy="22" r="7" fill="oklch(18% 0.03 260)" stroke="oklch(45% 0.10 266 / 0.5)" stroke-width="0.6"/> <circle cx="164" cy="22" r="7" fill="oklch(18% 0.03 260)" stroke="oklch(45% 0.10 266 / 0.5)" stroke-width="0.6"/>
<circle cx="24" cy="80" r="7" fill="oklch(18% 0.03 260)" stroke="oklch(45% 0.10 266 / 0.5)" stroke-width="0.6"/> <circle cx="24" cy="80" r="7" fill="oklch(18% 0.03 260)" stroke="oklch(45% 0.10 266 / 0.5)" stroke-width="0.6"/>
<circle cx="176" cy="80" r="7" fill="oklch(18% 0.03 260)" stroke="oklch(45% 0.10 266 / 0.5)" stroke-width="0.6"/> <circle cx="176" cy="80" r="7" fill="oklch(18% 0.03 260)" stroke="oklch(45% 0.10 266 / 0.5)" stroke-width="0.6"/>
<circle cx="100" cy="108" r="7" fill="oklch(18% 0.03 260)" stroke="oklch(45% 0.10 266 / 0.5)" stroke-width="0.6"/> <circle cx="100" cy="108" r="7" fill="oklch(18% 0.03 260)" stroke="oklch(45% 0.10 266 / 0.5)" stroke-width="0.6"/>
<!-- online dots -->
<circle cx="36" cy="22" r="2.5" fill="oklch(62% 0.22 145)"/> <circle cx="36" cy="22" r="2.5" fill="oklch(62% 0.22 145)"/>
<circle cx="164" cy="22" r="2.5" fill="oklch(62% 0.22 145)"/> <circle cx="164" cy="22" r="2.5" fill="oklch(62% 0.22 145)"/>
<circle cx="24" cy="80" r="2.5" fill="oklch(62% 0.22 145)"/> <circle cx="24" cy="80" r="2.5" fill="oklch(62% 0.22 145)"/>
@ -491,11 +489,11 @@
<polyline points="14,95 38,86 62,90 86,76 110,80 134,68 158,72 186,58" fill="none" stroke="oklch(62% 0.15 145)" stroke-width="2"/> <polyline points="14,95 38,86 62,90 86,76 110,80 134,68 158,72 186,58" fill="none" stroke="oklch(62% 0.15 145)" stroke-width="2"/>
<circle cx="186" cy="28" r="3" fill="oklch(62% 0.22 25)"/> <circle cx="186" cy="28" r="3" fill="oklch(62% 0.22 25)"/>
</svg> </svg>
<span class="home-card-stats"><span class="home-card-stats-dot" style="background:oklch(62% 0.22 25);box-shadow:0 0 6px oklch(62% 0.22 25)"></span><b id="tokenBurn"></b>&nbsp;burning</span> <span class="home-card-stats"><span class="home-card-stats-dot" style="background:var(--signal-bad);box-shadow:0 0 6px var(--signal-bad)"></span><b id="tokenBurn"></b>&nbsp;burning</span>
</div> </div>
<div class="home-card-desc">Token-metered pricing parody. Click for a giggle. (You actually pay $0.)</div> <div class="home-card-desc">Token-metered pricing parody. Click for a giggle. (You actually pay $0.)</div>
</a> </a>
</div> </div>
</div> </div>
<div class="home-footer"> <div class="home-footer">