diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..78eaa89
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.backup
+*.backup-*
+config/mail-status.json
diff --git a/config/services.json.backup-20260714-215555 b/config/services.json.backup-20260714-215555
deleted file mode 100644
index 76d0807..0000000
--- a/config/services.json.backup-20260714-215555
+++ /dev/null
@@ -1,121 +0,0 @@
-{
- "status": [
- {
- "name": "Edge01",
- "state": "online",
- "label": "Online",
- "value": "Reachable",
- "detail": "DreamHost VPS"
- },
- {
- "name": "Docker",
- "state": "online",
- "label": "Online",
- "value": "Running",
- "detail": "Container engine"
- },
- {
- "name": "Portainer",
- "state": "online",
- "label": "Online",
- "value": "Available",
- "detail": "portainer.zerafa.com"
- },
- {
- "name": "Gitea",
- "state": "online",
- "label": "Online",
- "value": "Available",
- "detail": "git.zerafa.com"
- },
- {
- "name": "TLS",
- "state": "online",
- "label": "Valid",
- "value": "Active",
- "detail": "Caddy certificates"
- },
- {
- "name": "Backups",
- "state": "warning",
- "label": "Review",
- "value": "Pending",
- "detail": "Restic + B2"
- },
- {
- "name": "Tunnel",
- "state": "warning",
- "label": "Pending",
- "value": "Not built",
- "detail": "Home network access"
- },
- {
- "name": "Monitoring",
- "state": "warning",
- "label": "Planned",
- "value": "Next phase",
- "detail": "Uptime Kuma"
- }
- ],
- "services": [
- {
- "name": "Portainer",
- "icon": "P",
- "description": "Docker containers, stacks, networks and volumes.",
- "url": "https://portainer.zerafa.com",
- "category": "Docker"
- },
- {
- "name": "Gitea",
- "icon": "G",
- "description": "Infrastructure repositories and documentation.",
- "url": "https://git.zerafa.com",
- "category": "Git"
- },
- {
- "name": "Edge01",
- "icon": "E",
- "description": "Primary VPS landing page and public edge host.",
- "url": "https://edge01.zerafa.com",
- "category": "Server"
- }
- ],
- "home": [
- {
- "name": "Home Assistant",
- "icon": "HA",
- "description": "Automation dashboards, devices and integrations.",
- "category": "Automation"
- },
- {
- "name": "Proxmox",
- "icon": "PX",
- "description": "Cluster, virtual machines and containers.",
- "category": "Virtualization"
- },
- {
- "name": "UniFi",
- "icon": "U",
- "description": "Gateways, switches, access points and clients.",
- "category": "Network"
- },
- {
- "name": "Pi-hole",
- "icon": "PH",
- "description": "DNS filtering and resolver statistics.",
- "category": "DNS"
- },
- {
- "name": "ADS-B",
- "icon": "AD",
- "description": "Aircraft tracking and feeder status.",
- "category": "Radio"
- },
- {
- "name": "NAS",
- "icon": "NAS",
- "description": "Storage, backups and private file services.",
- "category": "Storage"
- }
- ]
-}
\ No newline at end of file
diff --git a/css/voyager.css.backup-20260714-215555 b/css/voyager.css.backup-20260714-215555
deleted file mode 100644
index 2c1189c..0000000
--- a/css/voyager.css.backup-20260714-215555
+++ /dev/null
@@ -1,336 +0,0 @@
-:root {
- color-scheme: dark;
- --bg: #090d14;
- --sidebar: #0d131d;
- --panel: #131b27;
- --panel-hover: #192434;
- --text: #f4f6f8;
- --muted: #98a5b5;
- --line: #263244;
- --accent: #67d7c4;
- --online: #45d483;
- --warning: #e3b653;
- --offline: #ff6b6b;
-}
-
-* { box-sizing: border-box; }
-
-html { scroll-behavior: smooth; }
-
-body {
- margin: 0;
- background: var(--bg);
- color: var(--text);
- font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
-}
-
-a { color: inherit; }
-
-.app-shell {
- min-height: 100vh;
- display: grid;
- grid-template-columns: 250px 1fr;
-}
-
-.sidebar {
- position: sticky;
- top: 0;
- height: 100vh;
- padding: 24px 18px;
- border-right: 1px solid var(--line);
- background: var(--sidebar);
- display: flex;
- flex-direction: column;
-}
-
-.brand {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 4px 6px 28px;
-}
-
-.brand-mark {
- width: 42px;
- height: 42px;
- display: grid;
- place-items: center;
- border: 1px solid var(--line);
- border-radius: 10px;
- background: linear-gradient(145deg, rgba(103,215,196,.18), rgba(255,255,255,.03));
- font-weight: 900;
- color: var(--accent);
-}
-
-.brand-name {
- font-size: .95rem;
- font-weight: 900;
- letter-spacing: .14em;
-}
-
-.brand-node {
- margin-top: 3px;
- color: var(--muted);
- font-size: .82rem;
-}
-
-.nav {
- display: grid;
- gap: 6px;
-}
-
-.nav-link {
- padding: 11px 12px;
- border-radius: 9px;
- color: var(--muted);
- text-decoration: none;
- font-size: .92rem;
-}
-
-.nav-link:hover,
-.nav-link.active {
- background: rgba(103,215,196,.08);
- color: var(--text);
-}
-
-.sidebar-footer {
- margin-top: auto;
- padding: 12px;
- color: var(--muted);
- font-size: .8rem;
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.main {
- width: min(1240px, calc(100% - 48px));
- margin: 0 auto;
- padding: 36px 0 48px;
-}
-
-.topbar {
- display: flex;
- justify-content: space-between;
- gap: 24px;
- align-items: end;
- padding-bottom: 28px;
- border-bottom: 1px solid var(--line);
-}
-
-.eyebrow,
-.section-kicker {
- margin: 0 0 8px;
- color: var(--accent);
- font-size: .72rem;
- letter-spacing: .14em;
- text-transform: uppercase;
- font-weight: 800;
-}
-
-h1 {
- margin: 0;
- font-size: clamp(2.6rem, 6vw, 5.6rem);
- line-height: .92;
- letter-spacing: -.055em;
-}
-
-.node-label {
- margin: 10px 0 0;
- color: var(--muted);
- font-size: 1.1rem;
-}
-
-.topbar-meta {
- display: grid;
- gap: 5px;
- color: var(--muted);
- text-align: right;
- font-size: .86rem;
-}
-
-.section {
- padding-top: 34px;
-}
-
-.section-heading {
- display: flex;
- justify-content: space-between;
- align-items: end;
- gap: 20px;
- margin-bottom: 15px;
-}
-
-.section-heading h2 {
- margin: 0;
- font-size: 1.3rem;
-}
-
-.section-heading > p {
- margin: 0;
- color: var(--muted);
- font-size: .86rem;
-}
-
-.status-grid {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 12px;
-}
-
-.status-card,
-.service-card {
- border: 1px solid var(--line);
- border-radius: 14px;
- background: var(--panel);
-}
-
-.status-card {
- min-height: 130px;
- padding: 18px;
-}
-
-.status-top {
- display: flex;
- justify-content: space-between;
- gap: 12px;
-}
-
-.status-name {
- font-weight: 750;
-}
-
-.status-state {
- display: inline-flex;
- align-items: center;
- gap: 7px;
- font-size: .78rem;
- font-weight: 750;
-}
-
-.status-dot {
- width: 8px;
- height: 8px;
- border-radius: 50%;
- background: currentColor;
- display: inline-block;
-}
-
-.online { color: var(--online); }
-.warning { color: var(--warning); }
-.offline { color: var(--offline); }
-
-.status-value {
- margin-top: 28px;
- font-size: 1.5rem;
- font-weight: 800;
-}
-
-.status-detail {
- margin-top: 6px;
- color: var(--muted);
- font-size: .8rem;
-}
-
-.service-grid {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 12px;
-}
-
-.service-card {
- min-height: 160px;
- padding: 18px;
- position: relative;
- text-decoration: none;
- transition: transform .15s ease, border-color .15s ease, background .15s ease;
-}
-
-.service-card:hover {
- transform: translateY(-3px);
- border-color: var(--accent);
- background: var(--panel-hover);
-}
-
-.service-card.disabled {
- opacity: .5;
- pointer-events: none;
-}
-
-.service-icon {
- width: 38px;
- height: 38px;
- display: grid;
- place-items: center;
- border: 1px solid var(--line);
- border-radius: 9px;
- color: var(--accent);
- font-weight: 900;
- font-size: .82rem;
-}
-
-.service-card h3 {
- margin: 18px 0 6px;
- font-size: 1.05rem;
-}
-
-.service-card p {
- margin: 0;
- color: var(--muted);
- font-size: .87rem;
- line-height: 1.5;
-}
-
-.service-foot {
- position: absolute;
- left: 18px;
- right: 18px;
- bottom: 14px;
- display: flex;
- justify-content: space-between;
- color: var(--muted);
- font-size: .72rem;
- text-transform: uppercase;
- letter-spacing: .08em;
-}
-
-footer {
- margin-top: 38px;
- padding-top: 18px;
- border-top: 1px solid var(--line);
- display: flex;
- justify-content: space-between;
- gap: 16px;
- color: var(--muted);
- font-size: .8rem;
-}
-
-@media (max-width: 1050px) {
- .status-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
- .service-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
-}
-
-@media (max-width: 760px) {
- .app-shell { grid-template-columns: 1fr; }
- .sidebar {
- position: static;
- width: auto;
- height: auto;
- border-right: 0;
- border-bottom: 1px solid var(--line);
- }
- .nav {
- grid-template-columns: repeat(3, minmax(0, 1fr));
- }
- .sidebar-footer { display: none; }
- .main { width: min(100% - 24px, 1240px); padding-top: 24px; }
- .topbar,
- .section-heading { align-items: flex-start; flex-direction: column; }
- .topbar-meta { text-align: left; }
-}
-
-@media (max-width: 560px) {
- .status-grid,
- .service-grid { grid-template-columns: 1fr; }
- .nav { grid-template-columns: repeat(2, minmax(0, 1fr)); }
-}
diff --git a/index.html.backup b/index.html.backup
deleted file mode 100644
index 036dc71..0000000
--- a/index.html.backup
+++ /dev/null
@@ -1,238 +0,0 @@
-
-
-
-
-
- Zerafa Infrastructure Portal
-
-
-
-
-
-
-
-
-
-
- Home Lab
-
-
-
Home Assistant
-
Home automation dashboards, devices and integrations.
-
Tunnel Pending
-
-
-
-
Proxmox
-
Virtual machines, containers and cluster management.
-
Tunnel Pending
-
-
-
-
UniFi
-
Network gateways, switches, access points and clients.
-
Tunnel Pending
-
-
-
-
Pi-hole
-
DNS filtering, query statistics and resolver status.
-
Tunnel Pending
-
-
-
-
ADS-B
-
Aircraft tracking, receiver statistics and feeder links.
-
Tunnel Pending
-
-
-
-
Monitoring
-
Service uptime, alerts and infrastructure health.
-
Coming Soon
-
-
-
-
-
-
-
-
diff --git a/index.html.backup-20260714-215555 b/index.html.backup-20260714-215555
deleted file mode 100644
index 3685621..0000000
--- a/index.html.backup-20260714-215555
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
-
- VOYAGER · Edge01
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Overview
-
System sweep
-
-
Each system reports independently.
-
-
-
-
-
-
-
-
-
Services
-
Quick launch
-
-
Public services hosted on Edge01.
-
-
-
-
-
-
-
-
-
Private Network
-
Home lab
-
-
These activate after the secure tunnel is built.
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/js/voyager.js.backup-20260714-215555 b/js/voyager.js.backup-20260714-215555
deleted file mode 100644
index 528edb1..0000000
--- a/js/voyager.js.backup-20260714-215555
+++ /dev/null
@@ -1,53 +0,0 @@
-async function loadConfig() {
- const response = await fetch('config/services.json', { cache: 'no-store' });
- if (!response.ok) throw new Error(`Config load failed: ${response.status}`);
- return response.json();
-}
-
-function renderStatus(items) {
- const grid = document.getElementById('status-grid');
- grid.innerHTML = items.map(item => `
-
-
- ${item.name}
-
- ${item.label}
-
-
- ${item.value}
- ${item.detail}
-
- `).join('');
-}
-
-function renderServices(targetId, items, disabled = false) {
- const grid = document.getElementById(targetId);
- grid.innerHTML = items.map(item => {
- const classes = `service-card${disabled ? ' disabled' : ''}`;
- const tag = disabled ? 'div' : 'a';
- const href = disabled ? '' : ` href="${item.url}"`;
- return `
- <${tag} class="${classes}"${href}>
- ${item.icon}
- ${item.name}
- ${item.description}
-
- ${tag}>
- `;
- }).join('');
-}
-
-loadConfig()
- .then(config => {
- renderStatus(config.status);
- renderServices('service-grid', config.services);
- renderServices('home-grid', config.home, true);
- })
- .catch(error => {
- console.error(error);
- document.getElementById('status-grid').innerHTML =
- 'Configuration
Unavailable
Could not load services.json
';
- });