diff --git a/docs/superpowers/specs/2026-06-09-device-icons-and-last-seen-design.md b/docs/superpowers/specs/2026-06-09-device-icons-and-last-seen-design.md
new file mode 100644
index 0000000..c6f74f2
--- /dev/null
+++ b/docs/superpowers/specs/2026-06-09-device-icons-and-last-seen-design.md
@@ -0,0 +1,117 @@
+# Device icons, last-seen timer & uploadable icon sets — design
+
+Date: 2026-06-09
+Feature area: Void dashboard → LAN Devices band (`lan_devices`, migration 024)
+
+## Goal
+Let the user assign an icon to each discovered LAN device (device-type icon OR
+brand logo — "both"), show how long ago an absent device was last seen, and
+manage/extend the available icons by uploading new icon sets from Settings.
+
+## Background (existing code reused)
+- `lan_devices` table (migration 024): MAC-keyed inventory; already has
+ `last_seen timestamptz` and `present boolean`. No icon column yet.
+- `public/views/devices_band.js`: renders tiles + an edit (✎) flow; `/api/devices`
+ PATCH (`lib/api/routes/devices.js`, zod `patchBody`).
+- **Existing icon proxy** (reused for brand logos): `GET /api/icons/:slug.png`
+ → `lib/health/icons.js#getIcon()` fetches `walkxcode/dashboard-icons` PNGs via
+ jsDelivr and caches them to `/var/lib/void/icons`. `validSlug = ^[a-z0-9-]+$`.
+ `public/components/service_tile.js` renders `
`
+ with a letter fallback on error.
+
+## Icon model
+A device's `icon` value is one of:
+- `set::` → bundled/uploaded type icon, served `/api/icon-sets//`
+- `brand:` → dashboard-icons logo, served `/api/icons/.png` (existing)
+- `NULL` → auto-default chosen by group/vendor (pure function)
+
+Auto-default mapping (group → bundled `devices` set):
+Network→router, Entertainment→tv, Smart Home→plug, Personal→phone, else→unknown.
+
+## Components
+
+### 1. Data — migration 02x
+`ALTER TABLE lan_devices ADD COLUMN icon text;` (nullable). No backfill (NULL =
+auto-default). Down: drop column.
+
+### 2. Bundled type-icon set (the "set of favicons")
+Download ~15 **Tabler Icons** (MIT) SVGs into the repo at
+`public/icons/devices/` as the read-only bundled set named `devices`:
+router, phone, tablet, laptop, desktop, tv, speaker, camera, printer, console,
+plug, server, watch, nas, unknown. Monochrome line icons → match blackflame.
+
+### 3. Uploadable icon sets (persistent, outside git)
+- Storage: `/var/lib/void/icon-sets//.(svg|png)` (persistent volume,
+ survives redeploys — NOT in git-tracked `public/`). Env override
+ `ICON_SETS_DIR`, default `/var/lib/void/icon-sets`.
+- A "set" is a directory of icon files. Set/name validated `^[a-z0-9-]+$`.
+- **Three ingest methods**, all converging on the same per-file processor:
+ 1. **Multi-file** — one or more SVG/PNG files.
+ 2. **Zip archive** — server unpacks; each entry runs the per-file processor.
+ Reject path traversal / absolute paths / nested dirs (flatten basenames);
+ skip non-image entries; cap entry count + uncompressed total (zip-bomb
+ guard).
+ 3. **URL ingest** — server fetches a remote URL; if the payload is a zip it is
+ unpacked (as above), otherwise treated as a single image. http/https only
+ (scheme allowlist, SSRF guard), 8 s timeout, total size cap.
+- **Per-file processor (shared):** validate name slug + extension; magic-byte
+ check (PNG/JPEG/SVG); **sanitize SVGs** (strip `