diff --git a/.gitignore b/.gitignore
index f41edda..2236821 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,4 +17,6 @@ node_modules/
# Local databases (SQLite projection + Hydrant fjall store).
/data/
/hydrant.db/
-rustc-ice-*.txt
\ No newline at end of file
+rustc-ice-*.txt
+# Impeccable design detector scratch (ignore lists, design sidecar, critique snapshots).
+.impeccable/
diff --git a/.polytoken/skills/frontend-design/SKILL.md b/.polytoken/skills/frontend-design/SKILL.md
new file mode 100644
index 0000000..f7cfe57
--- /dev/null
+++ b/.polytoken/skills/frontend-design/SKILL.md
@@ -0,0 +1,162 @@
+---
+description: Use when designing, building, reviewing, critiquing, or polishing any Polymodel front-end surface (Dioxus RSX components, routes, CSS, layout, color, type, motion, states, copy). Carries the adapted Impeccable design method for Polymodel's blueprint identity and product register.
+polytoken:
+ tags: [frontend, design, ui]
+---
+# Polymodel front-end design
+
+Use this whenever you touch a Polymodel UI surface: a Dioxus component, a route, `assets/styling/*.css`, or any decision about layout, color, type, motion, state, or UX copy. It exists so front-end work ships with intentional craft instead of generic AI-generated defaults.
+
+Announce: "using the frontend-design skill for Polymodel UI work".
+
+**Source and companions.** This skill adapts [Impeccable](https://github.com/pbakaus/impeccable) (Paul Bakaus, Apache-2.0), which builds on Anthropic's `frontend-design` skill — distilled to Polymodel's stack and identity rather than vendored wholesale. Companions:
+
+- **`DESIGN.md`** (repo root) — the blueprint design system as machine-readable tokens (Stitch format) mirroring `assets/styling/theme.css`. Source of truth for the deterministic detector's design-system checks. Keep it in sync with `theme.css`.
+- **`tools/design-detector/`** — the vendored deterministic linter (see Detector below).
+- **Confluence**, space `PM`, [*Front-end design guidance*](https://radiant-industries.atlassian.net/wiki/spaces/PM/pages/655362) (child of the Polymodel Overall Design Plan) — the durable human-facing version of this method, with credit and links.
+
+Read `DESIGN.md` and the relevant `assets/styling/*.css` before non-trivial UI work.
+
+---
+
+## 1. Setup: orient before you design
+
+1. **Read the tokens and the existing vocabulary.** `theme.css` (color, fonts, spacing, radius, dark mode), then `base.css` and `cards.css` (cards, buttons, inputs, tabs, status pills, skeletons, the drafting-grid media). Reuse what exists; do not invent a parallel system. `DESIGN.md` documents these as a system with named rules.
+2. **Know the register.** Polymodel is **product UI** — a tool people browse and publish with — not a marketing/brand surface. Design *serves* the task.
+3. **Preserve the blueprint identity** (§3). It is committed and distinctive. Do not "fix" it toward generic flat-SaaS or dark-terminal defaults.
+
+---
+
+## 2. The register: product, not brand
+
+Every design task is either **brand** (marketing/landing/portfolio — design *is* the product) or **product** (app UI, tools, dashboards — design *serves* the product). Polymodel is product.
+
+The product test is not "would someone say AI made this" — familiarity is a feature here. The test is: **would a user fluent in the category's best tools (Printables, Linear, Figma, Stripe) sit down and trust this, or pause at every subtly-off component?** Product UI's failure mode isn't flatness, it's *strangeness without purpose*: over-decorated buttons, mismatched controls, gratuitous motion, display fonts where labels belong, invented affordances for standard tasks. The bar is **earned familiarity**; the tool should disappear into the task.
+
+Product can afford things brand can't: familiar sans defaults, standard nav patterns, density when users need it, consistency over surprise. Save delight for moments, not pages.
+
+---
+
+## 3. The blueprint identity (committed — preserve it)
+
+Polymodel's north star is **"The Drafting Table"**: a well-kept set of engineering blueprints rendered for the web. These are intentional choices, not slop to clean up.
+
+- **Paper base, not "AI cream."** `--color-base` (`#f5f1e8` light) is a drafting-paper tone tinted toward the brand — the blueprint substrate. This is a *committed* identity choice; identity-preservation beats the generic "never warm-neutral body bg" rule. Never rename it `--paper`/`--cream`/`--sand`; never swap it for a flat off-white.
+- **Teal primary, one warm-orange action.** `--color-primary` teal carries structure (active/selected/focus, grid lines). `--color-action` orange is the single warm accent, reserved for the *one* primary action per view. Accent marks action and state, never decoration.
+- **Near-square corners.** `--radius-panel: 2px`; controls render at 0px (`base.css`). Never round cards/inputs to 12px+; full pill only for tags. Over-rounding breaks the drafting feel.
+- **Drafting-grid media.** Empty/preview surfaces use the grid background (`--color-grid-line`), and missing media draws nested registration rectangles — never a flat gray box, never fake content.
+- **Mono for metadata.** `--font-mono` (Ioskeley Mono) carries dimensions, formats, DIDs/handles, counts, status pills. `--font-ui`/`--font-heading` (Proza Libre) carries everything else — one humanist sans for body, headings, labels, buttons.
+- **Both schemes first-class.** Every token has a dark variant; verify light *and* dark.
+
+---
+
+## 4. General rules
+
+### Color
+- **Verify contrast.** Body ≥ 4.5:1; large/bold-large (≥18px / bold ≥14px) ≥ 3:1; placeholders ≥ 4.5:1 (not muted-gray). The single most common AI failure is muted gray body text on a tinted near-white — exactly our paper base. When a value is even close, move toward `--color-text`/`--color-emphasis`, not `--color-muted`.
+- **No gray on color.** Gray text on a colored background looks washed out — use a darker shade of that hue, or a transparency of the text color.
+- **Restrained palette.** Tinted neutrals + the action accent. Heavy/full-saturation color does not belong on inactive states. A single surface may earn a committed color, but restrained is the product floor.
+- **State vocabulary, standardized:** hover, focus, active, disabled, selected, loading, error, warning, success, info. Accent is for primary action / current selection / state indicators only.
+
+### Typography
+- **One UI family.** Proza Libre for headings, labels, body, buttons. No display/body pairing. Mono only for the metadata roles in §3. Never a display font in labels, buttons, or data.
+- **Fixed rem scale, not fluid `clamp()` headings.** Product UI is viewed at consistent DPI; a heading that shrinks in a panel looks worse. Tight step ratio (~1.125–1.2). The card-title `clamp()` is the one sanctioned exception.
+- **Prose line length 65–75ch.** Dense data/tables may run wider.
+- **`text-wrap: balance`** on headings; `pretty` on long prose.
+
+### Layout
+- **Flexbox for 1D, Grid for 2D.** Don't reach for Grid where `flex-wrap` is simpler. Responsive card grids without breakpoints: `repeat(auto-fit, minmax(280px, 1fr))`. **Repo trap (AGENTS.md):** a Grid container + `min-height: 100vh` stretches rows and opens large gaps — use a flex column for vertical page shells.
+- **Cards are the lazy answer; nested cards are always wrong.** Use a card only when it's genuinely the best affordance. Thing cards are legitimate; a card wrapping cards is not.
+- **Vary spacing for rhythm.** Build a semantic z-index scale (dropdown → sticky → modal → toast → tooltip); never `999`/`9999`.
+- **Responsive behavior is structural** (collapse nav, responsive tables, breakpoint columns), not fluid typography.
+
+### Motion
+- **Conveys state, not decoration.** 150–250 ms, ease-out (quart/quint/expo) — no bounce, no elastic. Reserve it for state change, feedback, loading, upload progress, publish-state, viewer readiness. No orchestrated page-load sequences; users load into a task.
+- **`prefers-reduced-motion` is not optional** — every animation needs a reduce fallback (crossfade or instant).
+- **Don't animate layout properties** or `
` on hover; animate background/border/shadow instead.
+
+### Components & states
+- **Every interactive component ships all states:** default, hover, focus, active, disabled, loading, error. Don't ship half. Focus must be visible (the input `:focus` outline in `cards.css`).
+- **Skeletons, not center spinners,** for content loading (`.skeleton-*` exist).
+- **Empty states teach** the interface ("publish your first thing" + CTA), never "nothing here."
+- **Consistent affordances** across browse/search/profile/thing/publish: same button shape, same control vocabulary, same icon style. If "save" looks different in two places, one is wrong.
+
+### Interaction
+- Dropdowns with `position: absolute` inside `overflow: hidden/auto` get clipped — use `position: fixed`, the popover/`