---
name: nuxt-frontend-design
description: "Build or polish Nuxt UI v4+ pages and design systems. Use for landing pages, dashboards, tokens, motion, or generic-looking UX."
argument-hint: "[component/page/area]"
effort: max
license: MIT
title: nuxt-frontend-design
canonical_url: https://skilld.dev/gh/harlan-zw/harlan-agent-kit/nuxt-frontend-design
last_updated: 2026-10-10T11:01:12.000Z
---

> Index of every page on this site: [llms.txt](https://skilld.dev/llms.txt)

> **Skill from skilld.dev.** Follow the user's requested action.
> If the user asked to fork this Skill, follow the fork workflow below. Do not execute the Skill instructions while copying it.
> Otherwise, follow the instructions below for this session. You do not need to install anything.
>
> 31 supporting files sit beside this SKILL.md. When the Skill refers to one, fetch https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/PATH with PATH replaced.
>
> If the user asked to install this Skill, run `npx skilld install harlan-zw/harlan-agent-kit/nuxt-frontend-design`. Install writes the Skill files into the project, so every session loads them.
>
> ## Fork workflow
>
> A fork creates an editable local Skill with its original author and licence. The request authorizes copying and local installation.
> 1. Check `./skills/nuxt-frontend-design`, the project lockfile, and selected Agent targets together. If the local directory or installed Skill exists, stop. Never overwrite an existing directory or Agent target.
> 2. Read [source metadata](https://skilld.dev/api/v1/skills/harlan-zw/harlan-agent-kit/nuxt-frontend-design) once. Use sourceUrl, sourceCommit, skillPath, sourceGone, and license. If the source is gone or its path is missing, stop. If license is null, read licence files at the source commit.
> 3. Fetch only the source commit into a temporary Git repository. Do not clone full history. Derive repository_url from sourceUrl, including repository renames. If sourceCommit is absent, resolve the sourceUrl ref once. Set source_commit to that actual commit. Run these commands in one shell call:
>
> ```sh
> git init --quiet "$temporary_dir"
> git -C "$temporary_dir" fetch --quiet --depth=1 "$repository_url" "$source_commit"
> git -C "$temporary_dir" checkout --quiet --detach FETCH_HEAD
> ```
>
> Read applicable licence declarations and notices at that commit. If copying is not permitted, report the restriction and stop.
> 4. Inspect source entries together, then copy the directory containing skillPath into `./skills/nuxt-frontend-design`. Use the user's path if selected. Keep the original SKILL.md, relative links, scripts, binary assets, and executable modes. Exclude .git metadata. Reject symlinks and paths outside the Skill directory. After checking entries, use cp -a where available. A regular source directory needs no custom copy script. Do not save this page wrapper as SKILL.md.
> Preserve author credit, notices, and applicable licence files from repository or parent directories. Add PROVENANCE.md with the Skill page, source URL, actual commit, original path, and licence. Retain any existing PROVENANCE.md and record new provenance separately. Batch source inspection, copying, and provenance work where practical.
> 5. In the project root, run `skilld install ./skills/nuxt-frontend-design --mode copy --plain`. If skilld is unavailable, use `npx skilld install ./skills/nuxt-frontend-design --mode copy --plain`. This known command needs no help lookup. Install does not support --json. Use detected Agent targets, or add --agent for the targets the user selected. Install the local path, never the upstream selector. If installation fails, preserve the local copy and report the exact failure.
> 6. Confirm the local lockfile source and installed Agent copies once. Report the local path, actual commit, and Agent targets. After edits, reinstall the same local path. Upstream updates must not replace it. Do not publish or push unless the user asks.

# Nuxt Frontend Design

Full lifecycle frontend skill: setup, build, polish. Detects the right phase from project state.

## Worktree isolation

Before any edit, follow the [worktree isolation contract](../../references/worktree-isolation.md).

Job artifacts, contract format, dev server, checkpointing, and the handoff schema live in [references/workflow.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/workflow.md). Read it before Phase 2 or Phase 3.

## Project State

!`bash "${CLAUDE_SKILL_DIR}/scripts/project-state.sh"`

## Phase Detection

`$ARGUMENTS` is the text after the invocation, e.g. `/nuxt-frontend-design frost landing page` → "frost landing page". Parse it for both a theme name and an action; that example means ensure the frost theme, then build the landing page.

IS_NUXT=false: this skill needs a Nuxt project (`nuxt.config.ts`). Say so and stop.

| State | Phase |
|---|---|
| HAS_COLORS / HAS_THEME / HAS_GUIDELINES all false | Phase 1 (setup) |
| Mixed (some true, some false) | Phase 1 (repair a corrupted setup) |
| `$ARGUMENTS` names a theme the design system doesn't use | Phase 1 with that theme |
| PRIOR_REVIEW with FAIL verdict | Repair pass (below) |
| `$ARGUMENTS` asks for new pages | Phase 2 (build) |
| `$ARGUMENTS` asks to refine/polish, or existing pages need work | Phase 3 (polish) |
| No arguments, design system exists | Phase 3 (audit existing pages) |

**Repair pass**: read the full `{JOB_DIR}/review-report.md`, not just the verdict line. Fix every [HARD REJECT] and [RUBRIC] item at its referenced file:line, then re-emit the handoff with updated `contract_criteria_status`. Reuse the existing job ID.

Phase 2 depends on a complete design system. If any of the three indicators is missing, run Phase 1 first and tell the user you're doing so.

After Phase 1, emit the handoff and continue into Phase 2 when pages were asked for. Offer a fresh conversation with `/nuxt-frontend-design {page}` only after repair passes or for multi-page builds.

## Content & Asset Rules

Apply across Phase 2 and Phase 3. Review treats violations as hard rejects.

### Every Element Earns Its Place

Each visible element does one job:

- **Inform**: data the reader acts on or decides with.
- **Teach**: something the reader does not know yet and needs now.
- **Orient**: navigation, wayfinding, current location.
- **Brand**: an element the site's `DESIGN.md` registers as a brand asset.

If an element has no job, delete it. Noise is any element that fails this test.

**Show, don't tell.** If a sentence describes what the UI does, show the UI doing it with a real component, real data, or a working demo. This applies to dashboards and empty states too.

**No text decoration.** These fail the test unless `DESIGN.md` registers them as brand:

- Eyebrows: a small label above a heading.
- Subtitles or taglines that restate the heading.
- Labels that restate the value ("Status: Active" becomes "Active").
- Counts or facts that do not vary ("Watching 3 of 3 sites"). For table columns, see Hierarchy in [craft-rules.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/craft-rules.md).
- Decorative icons beside headings, cards, or list items. A per-metric icon that encodes its data, a trend direction or a status, informs. The same constant icon on every card carries no data and fails.
- Section numbers where the order means nothing.
- Metadata lines joined with "·" that nobody acts on.

If a section reads flat after removal, fix it with separation, scale, or layout. Do not add the decoration back. Sanctioned replacements: a data line below the heading, a hairline with a directional action, numbering where order is real, emphasis on one lead item.

**Start with less.** Build the first version with the fewest elements. Each addition names its job. Never pad with placeholder sections, dummy stats, filler copy, icon grids, or logo bars. Ask before you add content the contract did not name.

**Subtraction pass.** Before handoff, list each visible element with its job. Delete the ones with none. Show before and after screenshots.

### AI Slop Ban List

Hard rejections unless the user explicitly asked for them:

- Aggressive gradient backgrounds (purple/blue hero gradients, full-page meshes)
- Cards with a coloured left-border accent stripe
- Illustrations drawn inline with SVG shapes (use a real asset or a labelled placeholder)
- Emoji in UI copy unless the brand system registers emoji as a token
- Generic stat blocks ("10M+ users, 99.9% uptime, 24/7 support")
- Overused sans stacks: Inter, Roboto, Open Sans, Lato, Montserrat, Arial, any bare `system-ui` / `sans-serif` fallback as the only font
- SaaS-landing cliché serifs (Fraunces, Playfair, DM Serif) used *without commitment*, i.e. paired with a generic sans for body copy as decoration only. A theme that genuinely commits to an editorial, paper-craft, or literary aesthetic (kinetic-paper, flow, monograph) is right to use an editorial serif. The ban targets "add a serif heading for personality" tokenism.

### Placeholder Over Fake

A labelled placeholder beats a bad attempt at the real thing.

- Missing hero image: a neutral block reading `600×400 hero image`, not a hand-drawn SVG mountain
- Missing avatars: `https://api.dicebear.com/9.x/initials/svg?seed={name}` or `https://ui-avatars.com/api/?name={name}`
- Missing product screenshots: solid block at the real aspect ratio with a short label
- Missing logos: `https://logo.clearbit.com/{domain}` for real brands, otherwise a labelled box

Never leave broken `<img>` tags or unstyled fallback boxes. Placeholders should look intentional.

Scope: placeholders suit internal tools, dashboards, and prototypes. Landing and marketing pages want real product demos, screenshots, and named logos per "Show, don't tell" above; a labelled grey box on a hero kills the sale. Fall back to placeholders only when real assets genuinely don't exist yet.

### Minimum Scales

Surface these in the build contract as testable criteria.

- Body copy ≥ 16px; never below 14px
- Mobile tap targets ≥ 44×44px (buttons, links, icon triggers, form controls)
- Form input height ≥ 40px desktop, ≥ 44px mobile
- Contrast: WCAG AA for all text against its background

---

## Phase 1: Design System Setup

Establish the visual foundation. Needed when no design system exists or a new theme is requested. No job ID: design system artifacts are shared, not job-scoped.

### Design Philosophy

Commit to an aesthetic direction that serves the content before coding. Define one design principle as a tradeoff statement: "We prioritize X over Y" (e.g. "readability over visual impact", "tactile depth over minimalism"). Record it in `DESIGN.md`.

### What to set up

1. **Color palette**: primary, neutral, accent via `app.config.ts`
2. **Typography**: font selection, registration via Nuxt Fonts, `--font-*` in `@theme`
3. **Icon system**: collection matching the aesthetic via `@nuxt/icon`
4. **Semantic overrides**: `--ui-bg`, `--ui-text`, `--ui-radius` for light/dark
5. **Component theming**: global overrides via `app.config.ts` slots/variants
6. **Extended colors**: registering custom theme colors in `nuxt.config.ts`

**Override, don't invent.** Use Nuxt UI's existing tokens (`bg-muted`, `text-default`, `--ui-bg`, `--ui-radius`) and Tailwind's built-in utilities (`shadow-md`, `rounded-xl`). Customize by overriding those in `app.config.ts` and `main.css` rather than creating generic duplicates. Before naming a new token, check whether an existing `--ui-*` variable or Tailwind utility already covers it.

Theme signature tokens are the exception: when a theme's voice depends on an effect Tailwind can't express (`--shadow-brutal`, `--shadow-clay`, `--shadow-paper`, `--shadow-glass`, mesh/glow variables), define it. The ban targets generic duplicates (`--shadow-soft`, `--radius-card`), not theme-specific voice.

### References

- [design-system.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/design-system.md): full setup guide (colors, fonts, tokens, component theming)
- [themes/{name}.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/themes): complete theme implementation files

Available themes: frost, clay, blueprint, nebula, zen, neon, teenage-engineering, kinetic-paper, flow, devtool, monograph (the live list is injected above).

Read exactly one theme file: `${CLAUDE_SKILL_DIR}/references/themes/{chosen-theme}.md`. Reading several for comparison burns context without improving the choice. With no theme specified, default to `frost` for dark mode projects and `zen` for light mode; ask only when the choice is genuinely ambiguous.

### After Setup: Emit DESIGN.md

Emit `DESIGN.md` at the project root after writing `app.config.ts`, `main.css`, and `nuxt.config.ts`:

1. **Collision guard**: if `DESIGN.md` exists, ask before overwriting. Offer to merge (keeping the decisions log) or abort.
2. Read the template: [templates/DESIGN.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/templates/DESIGN.md)
3. **YAML front matter**: the chosen theme file already carries a DESIGN.md-compatible YAML block. Copy it, then apply user-specific customisations (brand name, swapped primary hex, additional registered colours, extra component surfaces). Prefer token refs (`{colors.primary}`, `{rounded.md}`) over restating hex/px values.
4. **Prose sections**: fill every section below the front matter from the decisions just made, no placeholders.
5. Write to `DESIGN.md` at the project root.
6. **Verify placeholders removed**: `grep -cE '\{\{|TODO|placeholder' DESIGN.md` returns 0. (Single-brace `{colors.primary}` token refs are legitimate and stay.)
7. **Verify tokens lint**: run `pnpm dlx @google/design.md lint DESIGN.md` without hiding stderr or piping away its exit status. Require a successful exit and zero reported errors. If the linter crashes, preserve the diagnostic and repair its input before retrying. For `raw.match is not a function`, quote floats and convert `rgba()` values to 8-digit hex. Record intentional button-primary contrast tradeoffs in `docs/design-decisions.md`.
8. **Verify budget**: `DESIGN.md` is at or under 300 lines, and every section is at or under 40. The caps and the audit live in the [root docs contract](../../references/root-docs.md#size-budgets).

Modifying an existing design system: update `DESIGN.md` in place.

`DESIGN.md` binds [craft-rules.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/craft-rules.md) to the project's components. It never restates those rules.

### After Setup: COPY.md is the other half

`DESIGN.md` owns the pixels. It does not own the words, and a page built with no decision about
its words ships whatever sentence each agent liked that day.

After emitting `DESIGN.md`, check for `COPY.md` at the project root. If the project has
user-visible strings and no `COPY.md`, say so and offer to run the
installed Brundlefly `copywriting` Skill `init` workflow. Do not write one from inside
this skill: it bootstraps from the strings that already ship, and that is a different harvest
from the one done here.

When `COPY.md` exists, read it before writing a single label, heading, empty state or error, and
keep `DESIGN.md` pointing at it rather than restating voice rules. `DESIGN.md`'s Voice section
is one line: which file owns this.

### Setup Recovery

Phase 1 failing mid-setup (build error, malformed config) means fixing the config before anything else. Verify all three indicators pass (`colors:` in app.config.ts, `@theme` in main.css, `DESIGN.md` with no placeholders) before moving to Phase 2. A `DESIGN.md` with unfilled template sections is worse than none.

### Setup Gotchas

- **Font selection**: avoid the top 5 web fonts (Inter, Roboto, Open Sans, Lato, Montserrat) and system-ui. Pick fonts that reinforce the design principle.
- **Button visibility**: primary CTAs need visible backgrounds. Set `colors.primary` plus `button.defaultVariants.variant: 'solid'` in `app.config.ts`. Secondary actions (icon triggers, overflow menus, table row actions) can use `ghost` or `outline`; see [components/feedback.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/components/feedback.md).
- **No fake UI**: if it looks interactive, wire it up.

---

## Phase 2: Build Pages

Compose pages and UI patterns with Nuxt UI v4+. Requires a design system.

Run the dev server setup and contract steps in [references/workflow.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/workflow.md) before the first smoke test.

**Build recovery**: `build-progress.md` present without `build-handoff.json` means a previous build was interrupted. Read the progress file for which pages completed and which criteria remain, resume from the last incomplete page, and re-run dev server setup since the old process is gone.

### Read the Foundation

If not already in context from Phase 1:

1. Read the `DESIGN.md` core.
2. Read the topic file its load map names for the layer you work in. Skip the others.
3. Read `COPY.md`.
4. Grep `GLOSSARY.md` for each noun you will render. Do not read it whole.
5. Open `main.css`, `app.config.ts` or `nuxt.config.ts` only to look up a token you need.

Every string the page renders comes from `COPY.md` and `GLOSSARY.md`, in that order: the noun
from the glossary, the sentence around it from the copy file. Inventing either while building a
component is how a product ends up describing itself four ways.

Use the project's semantic tokens, fonts, and component overrides. Never hardcode colors, shadows, or radii that bypass the design system. For a design variation, override an existing Nuxt UI token rather than introducing a new one.

### References

Load the reference matching what you're building. Loading several before writing any code costs context without improving the first page; pull the next one when you reach a new component type.

| Building… | Reference |
|-------------|-----------|
| Landing / marketing page | [pages/landing.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/pages/landing.md) |
| Dashboard / admin | [pages/dashboard.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/pages/dashboard.md) |
| Forms | [components/forms.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/components/forms.md) |
| Data tables | [components/tables.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/components/tables.md) |
| Navigation | [components/navigation.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/components/navigation.md) |
| Feedback / overlays | [components/feedback.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/components/feedback.md) |
| Charts, dashboards, sparklines, stat cards | [polish/data-viz.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/polish/data-viz.md) |
| Lists, tables, async states, custom CSS classes | [craft-rules.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/craft-rules.md) |

### When The User Asks For Variations

For 2+ options of the same page or component, vary across concrete dimensions rather than producing near-duplicates. Pick at least three of:

- **Scale**: hero type at 48px vs 96px vs 144px
- **Fill vs outline**: solid surfaces vs bordered/ghost
- **Layout structure**: stacked vs split vs asymmetric grid
- **Visual rhythm**: uniform cards vs feature + supporting mix
- **Type treatment**: display serif vs utility sans, tight vs wide tracking
- **Texture and layering**: flat vs shadowed vs offset/overlapping
- **Density**: airy vs compact

Start the first variation by-the-book, then escalate: each successive variation pushes further on one or two axes. Three variations differing only in accent colour are the same design three times.

Expose variations via route (`/pages/index-a.vue`, `/pages/index-b.vue`) or a `?variant=` query param with `v-if` blocks so the user can A/B them in one tab.

### Build Gotchas

Framework traps that grep won't reveal:

- **v4 component renames**: `ButtonGroup` → `UFieldGroup`, `PageMarquee` → `UMarquee`. Old names silently render nothing.
- **`UPageHero` needs a parent section**: wrap in `UPageSection` or a max-width container.
- **Form validation timing**: `UForm` with Zod validates on blur by default. `validate-on="input"` for inline.
- **`UTable` empty state**: without an explicit `empty` slot, an empty table shows nothing.
- **SSR boundary**: wrap client-only animations in `ClientOnly`, not entire page sections.
- **Component locality**: a new `app/components/Foo.vue` claims app-wide ownership (global auto-import, rename blast radius, collision risk). Default to colocating as `_Foo.vue` next to its page; the `_` prefix opts out of auto-import. Promote to `app/components/` once ≥2 unrelated features consume it. Review hard-rejects single-caller globals.

Review's hard rejection list is the authoritative rubric; see `/nuxt-frontend-review`.

---

## Phase 3: Polish

Refine existing interfaces against the project's own design system, not generic best practices. If `$ARGUMENTS` names an area (typography, motion, color), go straight to that reference.

Read the foundation files from Phase 2 if they aren't in context.

### Audit Foundation Tokens

Missing tokens cause inconsistency downstream. Fix gaps before elevating.

| Token category | Where defined | What to check |
|----------------|---------------|---------------|
| Colors | `app.config.ts` `colors` | `primary` and `neutral` set? Additional theme colors registered? |
| Fonts | `@theme` `--font-*` | At least `--font-sans`? Display/mono if used? |
| Semantic overrides | `:root` / `.dark` `--ui-*` | `--ui-bg`, `--ui-text`, `--ui-border` customized? |
| Component overrides | `app.config.ts` `ui.*` | Key components themed? `defaultVariants` set? |
| Unnecessary tokens | `@theme` | Custom tokens duplicating Tailwind builtins or `--ui-*`? Remove and use the existing token. |

### Observe Before Changing

Polish modifies an existing voice. Read 2-3 key `.vue` files first and state what the interface is currently saying: copy tone, shadow and card treatment, density, hover and focus states, animation style, rhythm between sections. The goal is to match and elevate that vocabulary. Not being able to describe the existing voice in one sentence means you are not ready to polish.

### Audit Consistency

Review's mechanical checks are the authoritative list (hardcoded hex/rgb, `slate-`/`gray-`/`zinc-`/`stone-` outside the configured neutral, `bg-white`/`text-black`, banned font families, custom `@theme` tokens duplicating `--ui-*`). See `harlan-agent-kit:nuxt-frontend-review` → `references/mechanical-checks.md`. Fix hits before handoff; review re-grades the same patterns.

Lead with the class-token inventory, the same command review runs:

```bash
pnpm dlx @ripast/cli css-class-scan --glob 'app/**' --sort count-desc --json
```

Look for:
- **Synonym clusters**: `bg-gray-100` + `bg-slate-100` + `bg-zinc-100` all filling one semantic role (`bg-muted`). Each cluster is a conformity fix.
- **One-off tokens** (count = 1): usually a hand-tuned value that should map to a token.
- **Low-count spellings near a high-count one**: drift from the canonical class.

With an obvious token map, apply it via `ripast css-class-rename --map tokens.json --apply` (dry-run first) rather than hand-editing call sites.

Beyond the mechanical list: inconsistent shadow/radius choices across similar components (pick one per component type in `app.config.ts`), inline `style=`, raw HTML where a Nuxt UI component exists, and anything in `DESIGN.md` the implementation contradicts.

### Audit Confirmation

Present findings before changing anything:

```
**Audit findings:**

Token issues (will fix):
1. Hardcoded `bg-slate-100` in HeroSection.vue:42 → should use `bg-muted`

Aesthetic observations (need your input):
2. Hero text feels small for a landing page → increase size? [intentional / fix]
3. Cards all use identical treatment → add hierarchy? [intentional / fix]
```

- Token and consistency violations are objectively wrong per the design system: present as "will fix".
- Aesthetic judgments (sizing, hierarchy, rhythm, visual weight) need user input. Do not assume they are problems.
- Read the decisions log first: `docs/design-decisions.md`, or `## Design Decisions` in `DESIGN.md` if the repo has not split. Anything already ruled on is settled; present only new observations. If all of them are covered, fix the token issues and move to Elevate.
- Wait for the user to mark each aesthetic item "intentional" or "fix".

After confirmation, append each "intentional" choice to `docs/design-decisions.md` with a date. If it changes a standing rule, edit that rule in `DESIGN.md` in one sentence. Never add dated text to `DESIGN.md`. Follow the [root docs budgets](../../references/root-docs.md#size-budgets).

Fix only approved items.

### Elevate

Once foundation and consistency are solid and the audit is confirmed. Read by symptom:

| Symptom | Reference |
|---------|-----------|
| Feels flat/static | [polish/interactions.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/polish/interactions.md) |
| No entrance animations | [polish/motion.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/polish/motion.md) |
| Typography feels generic | [polish/typography.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/polish/typography.md) |
| Layout cramped or boring | [polish/spatial.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/polish/spatial.md) |
| Colors dull or inconsistent | [polish/color.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/polish/color.md) |
| Not responsive enough | [polish/responsive.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/polish/responsive.md) |
| Copy unclear or generic | [polish/ux-writing.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/polish/ux-writing.md) |
| Reaching for JS/custom tokens for native CSS work | [polish/css-toolkit.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/polish/css-toolkit.md) |
| Chart/dashboard noisy, dishonest, or low data-ink | [polish/data-viz.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/polish/data-viz.md) |

For "make it better" or "polish everything": start with `interactions.md` + `motion.md` + `color.md` (highest impact), add `spatial.md`, `typography.md`, `responsive.md`, `ux-writing.md` only where the audit found issues, and consult `css-toolkit.md` whenever you are about to invent a token, add a JS scroll observer, or hand-code a popover, since the native CSS equivalent is usually one line.

### Verify the Route Still Loads

With `$DEV_PORT` / `$DEV_LOG` allocated (see workflow reference):

```bash
curl -sf "http://localhost:$DEV_PORT/{route}" > /dev/null && echo OK || echo FAIL
grep -nE '^\s*(\[error\]|\[warn\]|ERROR|WARN|✖|✘|Hydration |Cannot find|Failed to (resolve|compile))' "$DEV_LOG" \
  || echo "dev server log clean"
```

That is the whole self-verification at this stage. Visual and interaction verification is review's job; duplicating it here wastes context.

### Polish Rules

- Keep what already works and is distinctive.
- "Same product, elevated execution", not "this is different".
- Refine rather than replace wholesale.
- Polish what's there; adding features is scope creep.
- Over-polishing kills distinctiveness. Pick 1-2 areas to elevate, leave the rest.

### Polish Gotchas

- **Motion-v SSR hydration**: `ClientOnly` wrapper or `onMounted` for entrance animations
- **OKLCH browser support**: `@supports` fallback for older Safari
- **Font loading flash**: register fonts via Nuxt Fonts, not CSS `@import`
- **Container queries**: need `container-type: inline-size` on the parent
- **Don't refactor while polishing**: polish is visual refinement, not code cleanup

Polish work emits the same handoff as a build; see [references/workflow.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/nuxt-frontend-design/references/workflow.md).

---

## Reka UI

For components Nuxt UI doesn't cover, or where it is too prescriptive, use [Reka UI](https://reka-ui.com/docs/overview/installation): unstyled, accessible Vue primitives you style with Tailwind.
