Index: src/routes/artists.js
===================================================================
--- src/routes/artists.js	(revision dd856db9b550c437921c0d7464ad5e7133aea91e)
+++ 	(revision )
@@ -1,70 +1,0 @@
-/**
- * Artists directory — hub mode only.
- *
- * GET /leden?q=&page=  -> searchable, paginated list of ALL
- * Klonkt sites. The hub home shows only a limited selection; this page
- * scales to hundreds/thousands of artists via search + pagination.
- *
- * In solo mode there is only one site -> next() (falls through to postsRoutes,
- * which handles 'artiesten' as an unknown slug).
- */
-
-import express from 'express';
-import db from '../config/database.js';
-import { renderPage } from '../middleware/render.js';
-import { getTenancy } from '../services/SettingsService.js';
-
-const router = express.Router();
-
-const PER_PAGE = 24;
-
-router.get('/', (req, res, next) => {
-  if (getTenancy() !== 'hub') return next();
-
-  const q = (req.query.q || '').toString().trim().slice(0, 80);
-  let page = parseInt(req.query.page, 10);
-  if (!Number.isFinite(page) || page < 1) page = 1;
-
-  // The main/label site (oldest) is not an artist -> exclude from the directory,
-  // consistent with the hub home which displays it separately.
-  const mainRow = db.prepare('SELECT id FROM sites ORDER BY created_at ASC LIMIT 1').get();
-  const mainId = mainRow ? mainRow.id : '';
-
-  // Search term against title/slug/tagline (case-insensitive via LIKE; SQLite LIKE is
-  // case-insensitive for ASCII by default). ESCAPE '\' makes %, _, and \
-  // in the search term literal (otherwise they would act as wildcards).
-  const like = '%' + q.replace(/[\\%_]/g, (m) => '\\' + m) + '%';
-  const conds = ['s.id != @mainId'];
-  if (q) conds.push("(s.title LIKE @like ESCAPE '\\' OR s.slug LIKE @like ESCAPE '\\' OR s.tagline LIKE @like ESCAPE '\\')");
-  const where = 'WHERE ' + conds.join(' AND ');
-  const params = q ? { mainId, like } : { mainId };
-
-  const total = db.prepare(`SELECT COUNT(*) AS c FROM sites s ${where}`)
-    .get(params).c;
-  const pages = Math.max(1, Math.ceil(total / PER_PAGE));
-  if (page > pages) page = pages;
-  const offset = (page - 1) * PER_PAGE;
-
-  const artists = db.prepare(`
-    SELECT s.slug, s.title, s.tagline, s.profile_photo, s.accent,
-           u.avatar_url AS owner_avatar,
-           (SELECT COUNT(*) FROM posts WHERE site_id = s.id AND status = 'published') AS post_count
-    FROM sites s
-    LEFT JOIN users u ON u.id = s.owner_id
-    ${where}
-    ORDER BY s.title COLLATE NOCASE ASC
-    LIMIT @limit OFFSET @offset
-  `).all({ ...params, limit: PER_PAGE, offset });
-
-  renderPage(req, res, 'pages/artists-directory', {
-    pageTitle: 'Leden',
-    bodyClass: 'on-hub',
-    q,
-    artists,
-    total,
-    page,
-    pages,
-  });
-});
-
-export default router;
Index: src/routes/hub.js
===================================================================
--- src/routes/hub.js	(revision dd856db9b550c437921c0d7464ad5e7133aea91e)
+++ 	(revision )
@@ -1,89 +1,0 @@
-/**
- * Hub home page — hub mode only. Instead of rendering the primary Klonkt site,
- * '/' renders a company overview here: the latest posts from ALL users combined
- * + a list of the Klonkt sites.
- *
- * In solo mode this does nothing (next()) and posts.js renders the single site.
- */
-
-import express from 'express';
-import db from '../config/database.js';
-import { renderPage } from '../middleware/render.js';
-import { getTenancy, getSetting } from '../services/SettingsService.js';
-
-const router = express.Router();
-
-router.get('/', (req, res, next) => {
-  if (getTenancy() !== 'hub') return next();
-  // If resolveSite addressed a specific site (/user/:slug or /sites/:slug),
-  // req.url was rewritten to '/' — do NOT show the overview but let posts.js
-  // render the site itself. siteUrlBase is set in that case.
-  if (res.locals.siteUrlBase) return next();
-
-  // Latest published posts across all sites.
-  const posts = db.prepare(`
-    SELECT p.title, p.slug, p.excerpt, p.published_at, p.created_at,
-           p.cover_image_url, p.type,
-           s.slug AS site_slug, s.title AS site_title, s.profile_photo AS site_photo,
-           u.username AS author_username
-    FROM posts p
-    JOIN sites s ON s.id = p.site_id
-    LEFT JOIN users u ON u.id = p.author_id
-    WHERE p.status = 'published'
-    ORDER BY COALESCE(p.published_at, p.created_at) DESC
-    LIMIT 24
-  `).all();
-
-  // The main/label site (the explicitly primary = the company/main account) is
-  // NOT an artist; we display it separately at the top, not in the Artists roster.
-  const mainSite = db.prepare(`
-    SELECT s.id, s.slug, s.title, s.tagline, s.profile_photo, s.accent,
-           u.avatar_url AS owner_avatar,
-           (SELECT COUNT(*) FROM posts WHERE site_id = s.id AND status = 'published') AS post_count
-    FROM sites s
-    LEFT JOIN users u ON u.id = s.owner_id
-    WHERE s.is_primary = 1
-    LIMIT 1
-  `).get() || null;
-  const mainId = mainSite ? mainSite.id : '';
-
-  // Featured Klonkt sites for the home roster: most active first (number of
-  // published posts), then newest. Excl. the main site. Capped at
-  // HOME_ROSTER_LIMIT so the home scales — full list is at /leden.
-  const HOME_ROSTER_LIMIT = 24;
-  const artists = db.prepare(`
-    SELECT s.slug, s.title, s.tagline, s.profile_photo, s.accent,
-           u.avatar_url AS owner_avatar,
-           (SELECT COUNT(*) FROM posts WHERE site_id = s.id AND status = 'published') AS post_count
-    FROM sites s
-    LEFT JOIN users u ON u.id = s.owner_id
-    WHERE s.id != @mainId
-    ORDER BY post_count DESC, s.created_at DESC
-    LIMIT @limit
-  `).all({ mainId, limit: HOME_ROSTER_LIMIT });
-  const totalArtists = db.prepare('SELECT COUNT(*) AS c FROM sites WHERE id != ?').get(mainId).c;
-
-  // The hub page is GENERIC (not belonging to any user) — branding comes from global
-  // settings managed by the admin in the admin panel, not from a site.
-  const hub = {
-    title: getSetting('hub_title') || 'Overzicht',
-    tagline: getSetting('hub_tagline') || '',
-    intro: getSetting('hub_intro') || '',
-    heroImage: getSetting('hub_hero_image') || '',
-    heroOverlay: (() => { const v = parseInt(getSetting('hub_hero_overlay'), 10); return Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 45; })(),
-  };
-
-  renderPage(req, res, 'pages/hub-home', {
-    pageTitle: hub.title,
-    socialDescr: hub.intro || hub.tagline || '',
-    bodyClass: 'on-home on-hub',
-    hub,
-    mainSite,
-    artists,
-    totalArtists,
-    rosterLimit: HOME_ROSTER_LIMIT,
-    posts,
-  });
-});
-
-export default router;
