diff --git a/infra/backup-strategy/index.njk b/infra/backup-strategy/index.njk
index e1bb576..66affd2 100644
--- a/infra/backup-strategy/index.njk
+++ b/infra/backup-strategy/index.njk
@@ -1,7 +1,8 @@
---
title: "Backup Strategy"
section: "infra"
-parent: "/"
+tags: "infra"
+parent: "/infra/"
description: "Layered 3-2-1 backup strategy covering NAS snapshots, offsite copies, and cloud storage."
layout: base.njk
---
diff --git a/infra/dev-environment/index.njk b/infra/dev-environment/index.njk
index b40343c..78acbc3 100644
--- a/infra/dev-environment/index.njk
+++ b/infra/dev-environment/index.njk
@@ -1,7 +1,8 @@
---
title: "Xubuntu Dev VM"
section: "infra"
-parent: "/"
+tags: "infra"
+parent: "/infra/"
description: "A disposable, daily-backed-up Xubuntu VM for AI-assisted, remote development via SSH and Chrome Remote Desktop."
layout: base.njk
---
diff --git a/infra/docker/index.njk b/infra/docker/index.njk
index d095e4c..f1e53f2 100644
--- a/infra/docker/index.njk
+++ b/infra/docker/index.njk
@@ -1,7 +1,8 @@
---
title: "Docker Container Strategy"
section: "infra"
-parent: "/"
+tags: "infra"
+parent: "/infra/"
description: "How self-hosted services are organized across three Docker hosts on Proxmox and Synology, using Docker Compose as the single source of truth."
layout: base.njk
---
diff --git a/infra/eleventy.config.js b/infra/eleventy.config.js
deleted file mode 100644
index c46e7ac..0000000
--- a/infra/eleventy.config.js
+++ /dev/null
@@ -1,20 +0,0 @@
-module.exports = function (eleventyConfig) {
- eleventyConfig.addGlobalData("site", { url: "https://www.moonweb.org", pathPrefix: "/infra" });
- eleventyConfig.addFilter("date", (d) => d.toISOString());
- eleventyConfig.addPassthroughCopy({ "shared/theme-infra.css": "theme.css" });
- eleventyConfig.addPassthroughCopy({ "shared/base.css": "shared-base.css" });
- eleventyConfig.addPassthroughCopy({ "shared/favicon/infra.svg": "favicon.svg" });
- eleventyConfig.addPassthroughCopy({ "infra/robots.txt": "robots.txt" });
-
- return {
- dir: {
- input: "infra",
- includes: "../shared/_includes",
- output: "dist/infra"
- },
- serverOptions: {
- host: "0.0.0.0",
- port: 8082
- }
- };
-};
diff --git a/infra/index.njk b/infra/index.njk
index f743915..173211b 100644
--- a/infra/index.njk
+++ b/infra/index.njk
@@ -1,6 +1,7 @@
---
title: "Homelab Infrastructure — Proxmox, Docker & Networking | moonweb"
section: "infra"
+tags: "infra"
description: "Homelab infrastructure overview: Proxmox hosts, Synology NAS, Docker VMs and Setup-Guides."
layout: base.njk
sections:
diff --git a/infra/lxc/index.njk b/infra/lxc/index.njk
index 76853cf..8bebac4 100644
--- a/infra/lxc/index.njk
+++ b/infra/lxc/index.njk
@@ -1,7 +1,8 @@
---
title: "LXC Container Strategy"
section: "infra"
-parent: "/"
+tags: "infra"
+parent: "/infra/"
description: "Overview of the lightweight LXC containers running on the main Proxmox host, and why they are LXC instead of Docker."
layout: base.njk
---
diff --git a/infra/monitoring/index.njk b/infra/monitoring/index.njk
index 7f29ed7..1657d75 100644
--- a/infra/monitoring/index.njk
+++ b/infra/monitoring/index.njk
@@ -1,7 +1,8 @@
---
title: "Monitoring"
section: "infra"
-parent: "/"
+tags: "infra"
+parent: "/infra/"
description: "Prometheus and Grafana monitoring stack for hosts, containers, and hardware metrics."
layout: base.njk
---
diff --git a/infra/openwrt/index.njk b/infra/openwrt/index.njk
index 3990d01..dddbb8a 100644
--- a/infra/openwrt/index.njk
+++ b/infra/openwrt/index.njk
@@ -1,7 +1,8 @@
---
title: "OpenWrt Multi-WAN Router"
section: "infra"
-parent: "/"
+tags: "infra"
+parent: "/infra/"
description: "Multi-WAN OpenWrt router in the study with WiFi and Powerline failover, plus VLAN 189 for IoT isolation."
layout: base.njk
---
diff --git a/infra/proxmox/index.njk b/infra/proxmox/index.njk
index 0548872..3853fbb 100644
--- a/infra/proxmox/index.njk
+++ b/infra/proxmox/index.njk
@@ -1,7 +1,8 @@
---
title: "Proxmox Virtualization"
section: "infra"
-parent: "/"
+tags: "infra"
+parent: "/infra/"
description: "What Proxmox VE is, the hardware it runs on in my homelab, its key advantages, and a short setup walkthrough."
layout: base.njk
---
diff --git a/infra/sitemap.xml.njk b/infra/sitemap.xml.njk
index 7cbc214..10e9710 100644
--- a/infra/sitemap.xml.njk
+++ b/infra/sitemap.xml.njk
@@ -1,5 +1,6 @@
---
-permalink: /sitemap.xml
+permalink: /infra/sitemap.xml
+sitemapCollection: "infra"
eleventyExcludeFromCollections: true
---
{% include "sitemap.njk" %}
diff --git a/infra/synology/index.njk b/infra/synology/index.njk
index 2bad928..41601f2 100644
--- a/infra/synology/index.njk
+++ b/infra/synology/index.njk
@@ -1,7 +1,8 @@
---
title: "Synology NAS"
section: "infra"
-parent: "/"
+tags: "infra"
+parent: "/infra/"
description: "Model, storage setup and current role of the Synology NAS in the homelab after the late-2025 cleanup."
layout: base.njk
---
diff --git a/package.json b/package.json
index 2699bcc..efaf23e 100644
--- a/package.json
+++ b/package.json
@@ -4,24 +4,13 @@
"private": true,
"description": "Monorepo for hub/infra/smarthome/code/retro/timecapsule (Eleventy, static, deployed to IONOS SFTP)",
"scripts": {
- "dev:hub": "npx @11ty/eleventy --config=hub/eleventy.config.js --serve --port=8081",
- "dev:infra": "npx @11ty/eleventy --config=infra/eleventy.config.js --serve --port=8082",
- "dev:smarthome": "npx @11ty/eleventy --config=smarthome/eleventy.config.js --serve --port=8083",
- "dev:code": "npx @11ty/eleventy --config=code/eleventy.config.js --serve --port=8084",
- "dev:retro": "npx @11ty/eleventy --config=retro/eleventy.config.js --serve --port=8085",
+ "dev": "npx @11ty/eleventy --serve --port=8081",
"dev:stefankoelle": "npx @11ty/eleventy --config=stefankoelle/eleventy.config.js --serve --port=8086",
"dev:timecapsule": "cd timecapsule && npx @11ty/eleventy --serve --port=8087",
- "dev": "npm run dev:hub & npm run dev:infra & npm run dev:smarthome & npm run dev:code & npm run dev:retro & npm run dev:stefankoelle & npm run dev:timecapsule",
- "build:hub": "npx @11ty/eleventy --config=hub/eleventy.config.js",
- "build:infra": "npx @11ty/eleventy --config=infra/eleventy.config.js",
- "build:smarthome": "npx @11ty/eleventy --config=smarthome/eleventy.config.js",
- "build:code": "npx @11ty/eleventy --config=code/eleventy.config.js",
- "build:retro": "npx @11ty/eleventy --config=retro/eleventy.config.js",
+ "build": "npx @11ty/eleventy",
"build:stefankoelle": "npx @11ty/eleventy --config=stefankoelle/eleventy.config.js",
"build:timecapsule": "cd timecapsule && npx @11ty/eleventy && mkdir -p ../../dist/timecapsule && cp -r _site/timecapsule/* ../../dist/timecapsule/",
- "build": "npm run build:hub && npm run build:infra && npm run build:smarthome && npm run build:code && npm run build:retro && npm run build:timecapsule && npm run build:stefankoelle",
- "build:moonweb": "npm run build:hub && npm run build:infra && npm run build:smarthome && npm run build:code && npm run build:retro && npm run build:timecapsule",
- "merge:moonweb": "bash scripts/merge-moonweb.sh",
+ "build:moonweb": "npm run build && npm run build:timecapsule",
"pdf:cv": "bash stefankoelle/pdf/build-pdf.sh",
"prebuild": "bash prebuild.sh"
},
diff --git a/retro/404.html b/retro/404.html
index 30ca8ac..8a321b7 100644
--- a/retro/404.html
+++ b/retro/404.html
@@ -1,9 +1,10 @@
---
title: "Page Not Found"
section: "retro"
+tags: "retro"
description: "The page you are looking for does not exist."
layout: base.njk
-permalink: /404.html
+permalink: /retro/404.html
---
404
diff --git a/retro/amiga-hardware-landscape/index.njk b/retro/amiga-hardware-landscape/index.njk
index 39790da..98fdb4b 100644
--- a/retro/amiga-hardware-landscape/index.njk
+++ b/retro/amiga-hardware-landscape/index.njk
@@ -1,9 +1,10 @@
---
title: "Running AmigaOS in 2026: MiSTer FPGA vs Amiberry on Pi"
section: "retro"
+tags: "retro"
description: "Two very different ways to get a fully working AmigaOS 3.2.3 desktop running today."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
Running AmigaOS in 2026: MiSTer FPGA vs Amiberry on Pi
diff --git a/retro/amiga-modern-platforms/index.njk b/retro/amiga-modern-platforms/index.njk
index 0fa568f..577e0a0 100644
--- a/retro/amiga-modern-platforms/index.njk
+++ b/retro/amiga-modern-platforms/index.njk
@@ -1,9 +1,10 @@
---
title: "Vampire V4, A600GS or MiSTer: Amiga Hardware Isn't a Simple Speed Race"
section: "retro"
+tags: "retro"
description: "Why raw benchmark numbers are actively misleading when comparing modern Amiga hardware options."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
Vampire V4, A600GS or MiSTer: Amiga Hardware Isn't a Simple Speed Race
diff --git a/retro/atari-mega-st-fleet/index.njk b/retro/atari-mega-st-fleet/index.njk
index acb3c81..bf242e1 100644
--- a/retro/atari-mega-st-fleet/index.njk
+++ b/retro/atari-mega-st-fleet/index.njk
@@ -1,9 +1,10 @@
---
title: "The Atari Mega ST Fleet: Three Machines, Three Jobs"
section: "retro"
+tags: "retro"
description: "How three Atari Mega ST computers ended up with completely different roles in a modern retro setup."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
The Atari Mega ST Fleet: Three Machines, Three Jobs
diff --git a/retro/atari-monitor-compatibility/index.njk b/retro/atari-monitor-compatibility/index.njk
index 21911b0..8e73d0a 100644
--- a/retro/atari-monitor-compatibility/index.njk
+++ b/retro/atari-monitor-compatibility/index.njk
@@ -1,9 +1,10 @@
---
title: "The 15kHz Problem: Finding a Monitor That Speaks Atari"
section: "retro"
+tags: "retro"
description: "Why most modern monitors refuse to display Atari ST colour modes, and which ones actually work."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
The 15kHz Problem: Finding a Monitor That Speaks Atari
diff --git a/retro/atari-networking-bbs/index.njk b/retro/atari-networking-bbs/index.njk
index 4ba1025..3f89807 100644
--- a/retro/atari-networking-bbs/index.njk
+++ b/retro/atari-networking-bbs/index.njk
@@ -1,9 +1,10 @@
---
title: "Getting a 40-Year-Old Computer Online: Atari ST Networking and BBS Access"
section: "retro"
+tags: "retro"
description: "Connecting an Atari ST to the modern internet and to dial-up-era bulletin board systems, warts and all."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
Getting a 40-Year-Old Computer Online: Atari ST Networking and BBS Access
diff --git a/retro/batocera-living-room/index.njk b/retro/batocera-living-room/index.njk
index b8ca972..36b6cf9 100644
--- a/retro/batocera-living-room/index.njk
+++ b/retro/batocera-living-room/index.njk
@@ -1,9 +1,10 @@
---
title: "Batocera in the Living Room: One Box, Every Retro System"
section: "retro"
+tags: "retro"
description: "Why the living room emulation station takes a completely different approach than the FPGA rigs upstairs."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
Batocera in the Living Room: One Box, Every Retro System
diff --git a/retro/dos-486-tower/index.njk b/retro/dos-486-tower/index.njk
index 156f3f2..858a834 100644
--- a/retro/dos-486-tower/index.njk
+++ b/retro/dos-486-tower/index.njk
@@ -1,9 +1,10 @@
---
title: "The 486 DX2-66: Rebuilding a DOS Era on MiSTer FPGA"
section: "retro"
+tags: "retro"
description: "Recreating a Vobis-Highscreen 486 DX2-66 setup on MiSTer FPGA, down to the original DOS configuration."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
The 486 DX2-66: Rebuilding a DOS Era on MiSTer FPGA
diff --git a/retro/eleventy.config.js b/retro/eleventy.config.js
deleted file mode 100644
index 434386e..0000000
--- a/retro/eleventy.config.js
+++ /dev/null
@@ -1,20 +0,0 @@
-module.exports = function (eleventyConfig) {
- eleventyConfig.addGlobalData("site", { url: "https://www.moonweb.org", pathPrefix: "/retro" });
- eleventyConfig.addFilter("date", (d) => d.toISOString());
- eleventyConfig.addPassthroughCopy({ "shared/theme-retro.css": "theme.css" });
- eleventyConfig.addPassthroughCopy({ "shared/base.css": "shared-base.css" });
- eleventyConfig.addPassthroughCopy({ "shared/favicon/retro.svg": "favicon.svg" });
- eleventyConfig.addPassthroughCopy({ "retro/robots.txt": "robots.txt" });
-
- return {
- dir: {
- input: "retro",
- includes: "../shared/_includes",
- output: "dist/retro"
- },
- serverOptions: {
- host: "0.0.0.0",
- port: 8085
- }
- };
-};
diff --git a/retro/et4000-experiment/index.njk b/retro/et4000-experiment/index.njk
index 3ec5ce3..5ed0dde 100644
--- a/retro/et4000-experiment/index.njk
+++ b/retro/et4000-experiment/index.njk
@@ -1,9 +1,10 @@
---
title: "Why an ET4000 Graphics Card and a Mega ST Don't Mix (Yet)"
section: "retro"
+tags: "retro"
description: "A cautionary tale about pushing 1980s power supplies past their limits with a modern-ish graphics card."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
Why an ET4000 Graphics Card and a Mega ST Don't Mix (Yet)
diff --git a/retro/index.njk b/retro/index.njk
index be06473..b241dd6 100644
--- a/retro/index.njk
+++ b/retro/index.njk
@@ -1,6 +1,7 @@
---
title: "Retro Computing — Vintage Hardware & FPGA | moonweb"
section: "retro"
+tags: "retro"
description: "Physical retro hardware collection — Raspberry Pi units, Pi 400, and vintage computing setups."
layout: base.njk
sections:
diff --git a/retro/mini-arcade-handheld-roundup/index.njk b/retro/mini-arcade-handheld-roundup/index.njk
index ab3d8ce..82457c9 100644
--- a/retro/mini-arcade-handheld-roundup/index.njk
+++ b/retro/mini-arcade-handheld-roundup/index.njk
@@ -1,9 +1,10 @@
---
title: "Mini Arcades and Handhelds: Sorting the Real Deal from the Bootlegs"
section: "retro"
+tags: "retro"
description: "A buyer's guide to compact retro gaming devices, and why the cheapest option is almost never the right one."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
Mini Arcades and Handhelds: Sorting the Real Deal from the Bootlegs
diff --git a/retro/mist-mister-fpga/index.njk b/retro/mist-mister-fpga/index.njk
index ba5b5c3..58a425c 100644
--- a/retro/mist-mister-fpga/index.njk
+++ b/retro/mist-mister-fpga/index.njk
@@ -1,9 +1,10 @@
---
title: "MiST and MiSTer: Two FPGA Boxes, Two Very Different Personalities"
section: "retro"
+tags: "retro"
description: "Why the newer, more powerful MiSTer isn't automatically the better choice for every retro system."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
MiST and MiSTer: Two FPGA Boxes, Two Very Different Personalities
diff --git a/retro/pimiga-journey/index.njk b/retro/pimiga-journey/index.njk
index 38000a7..4e21dba 100644
--- a/retro/pimiga-journey/index.njk
+++ b/retro/pimiga-journey/index.njk
@@ -1,9 +1,10 @@
---
title: "PiMiga 3 to 5: Chasing the Perfect Amiga-on-a-Pi Distro"
section: "retro"
+tags: "retro"
description: "Three generations of PiMiga later, here's what actually changed — and why newer isn't always better."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
PiMiga 3 to 5: Chasing the Perfect Amiga-on-a-Pi Distro
diff --git a/retro/retro-corner-snapshot/index.njk b/retro/retro-corner-snapshot/index.njk
index 82ea0f7..fee3a18 100644
--- a/retro/retro-corner-snapshot/index.njk
+++ b/retro/retro-corner-snapshot/index.njk
@@ -1,9 +1,10 @@
---
title: "The Retro Corner Today: A Snapshot of the Whole Setup"
section: "retro"
+tags: "retro"
description: "A tour through every retro system currently active across the home, room by room."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
The Retro Corner Today: A Snapshot of the Whole Setup
diff --git a/retro/sitemap.xml.njk b/retro/sitemap.xml.njk
index 7cbc214..5e87748 100644
--- a/retro/sitemap.xml.njk
+++ b/retro/sitemap.xml.njk
@@ -1,5 +1,6 @@
---
-permalink: /sitemap.xml
+permalink: /retro/sitemap.xml
+sitemapCollection: "retro"
eleventyExcludeFromCollections: true
---
{% include "sitemap.njk" %}
diff --git a/retro/the-a1200/index.njk b/retro/the-a1200/index.njk
index 601cd3c..0c100a7 100644
--- a/retro/the-a1200/index.njk
+++ b/retro/the-a1200/index.njk
@@ -1,9 +1,10 @@
---
title: "The A1200: What We Know Before It Ships"
section: "retro"
+tags: "retro"
description: "A close look at Retro Games Ltd.'s upcoming Amiga 1200 console, based on everything public so far."
layout: base.njk
-parent: "/"
+parent: "/retro/"
---
The A1200: What We Know Before It Ships
diff --git a/scripts/merge-moonweb.sh b/scripts/merge-moonweb.sh
deleted file mode 100755
index d2b50f8..0000000
--- a/scripts/merge-moonweb.sh
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/bash
-set -e
-
-echo "Merging moonweb sites for deployment..."
-
-# Clean previous merge
-rm -rf dist/root
-
-# Hub becomes root
-echo " hub → dist/ (root)"
-cp -r dist/hub dist/root
-rm -rf dist/hub
-
-# Copy timecapsule from its build output
-if [ -d "timecapsule/_site/timecapsule" ]; then
- echo " timecapsule → dist/root/timecapsule/"
- cp -r timecapsule/_site/timecapsule dist/root/timecapsule
-else
- echo " WARNING: timecapsule/_site/timecapsule not found, skipping"
-fi
-
-# Subdirectories
-for site in infra smarthome code retro; do
- if [ -d "dist/$site" ]; then
- echo " $site → dist/root/$site/"
- cp -r "dist/$site" "dist/root/$site"
- else
- echo " WARNING: dist/$site not found, skipping"
- fi
-done
-
-# Copy CSS to root (accessible from all subdirectories)
-echo " Copying shared CSS to root..."
-cp shared/base.css dist/root/shared-base.css
-cp shared/favicon/hub.svg dist/root/favicon.svg
-
-# Theme CSS files are already copied during build as theme.css
-# The root theme is hub's theme
-if [ -f "dist/root/theme.css" ]; then
- echo " Root theme.css already in place"
-fi
-
-echo ""
-echo "Merge complete. Final structure:"
-find dist/root -maxdepth 2 -type f | sort | head -50
-echo "..."
-echo ""
-echo "Total files:"
-find dist/root -type f | wc -l
diff --git a/shared/_includes/base.njk b/shared/_includes/base.njk
index 19e1840..70fe200 100644
--- a/shared/_includes/base.njk
+++ b/shared/_includes/base.njk
@@ -20,8 +20,8 @@
-
-
+
+