# Beautiful Empty States

## Objective

Replace blank screens with useful, contextual empty states.

Every list, table, and dashboard in your app has a "nothing here yet" state. Most
apps ship a blank rectangle — and it is often the very first thing a new user sees.

An empty state should say what belongs here, why it is empty, and what to do next.

## Before You Begin

This feature is being added to an application that already exists and already
works. Do not scaffold a new project, and do not assume a blank slate.

Inspect the codebase first and establish:

- The existing application structure and where code of this kind already lives.
- The framework and version in use.
- The existing design system — colours, spacing, typography, and component conventions.
- Existing UI components you can reuse instead of writing new ones.
- The existing database structure, if this feature needs to persist anything.
- The existing authentication and authorization system, if this feature is user-scoped.
- Dependencies already installed, so you don't add a library that duplicates one.
- The existing test setup and conventions.

Only start writing code once you understand the above. If the application
already implements part of this feature, extend it rather than replacing it.

## Implementation Instructions

Find every view in the application that can render zero items — lists, tables,
search results, dashboards, feeds, inboxes — and give each a purposeful empty state.

1. **Inventory the empty cases first.** List every collection view in the app and
   report that list before you start editing.
2. **Distinguish the three kinds of empty.** They are not the same, and must not
   share one component blindly:
   - **First-run empty** — the user has never created anything. This is an
     onboarding moment: explain the feature and offer the primary action.
   - **Filtered empty** — there is data, but the current search or filter matches
     nothing. Offer a way to clear the filter. Never say "create your first item"
     to someone who simply mistyped a search.
   - **Cleared empty** — the user finished everything (an empty inbox, a done list).
     This is a *success* state. Say so.
3. **Build one reusable empty-state component** from the existing design system,
   with slots for icon, heading, description, and an optional action.
4. **Use the app's existing icon set.** Do not add a new icon library.

## UI and UX Requirements

- A heading that names what is missing, in plain language.
- One or two sentences on what will appear here and why it matters.
- A primary action where one makes sense — the *real* action, wired to the same
  handler as the equivalent button elsewhere in the app.
- Centered in the space the content would have occupied, so the layout does not
  collapse.
- Quiet, not loud. An empty state must not look like an error.

## Responsive Requirements

- Scales down without the icon dominating a phone screen.
- Text wraps sensibly; no horizontal scroll at 320px.
- The action is full-width on mobile if that matches the app's conventions.

## Accessibility Requirements

- Announce the empty state to screen readers when a list becomes empty — use a live
  region on the results container.
- Decorative icons are `aria-hidden`.
- The heading uses the correct level for its position in the document outline.
- Any action is a real button or link and is keyboard reachable.

## Edge Cases

- **Loading is not empty.** Do not flash the empty state while data is still
  loading — that is what skeletons are for. Render it only once loading has
  resolved to zero items.
- **Error is not empty.** A failed request is an error state.
- **The user cannot create.** Do not show a "Create" action they lack permission for.
- **Pagination.** Page 3 of a 2-page list is a filtered empty, not a first-run empty.

## Testing

- Every collection view renders its empty state with zero items.
- Searching for a nonsense string shows the *filtered* empty state, with a way back.
- The empty state does not appear while loading.
- The empty state does not appear on error.
- The primary action works and matches the same action elsewhere.

## Acceptance Criteria

- [ ] Every collection view in the app has an empty state.
- [ ] First-run, filtered, and cleared empties are worded differently.
- [ ] The empty state never appears during loading or on error.
- [ ] One reusable component, built from the existing design system.
- [ ] Actions are wired to the app's real handlers.
- [ ] It reads correctly at a 320px viewport.
- [ ] Screen readers announce the state.

## Adaptation Rules

- Match the existing design system. Do not introduce a new colour palette,
  spacing scale, or component library.
- Reuse existing components and utilities wherever they fit.
- Follow the naming, file layout, and code style already present.
- Do not upgrade, replace, or remove existing dependencies to make this
  feature fit. Adapt the feature to the app, not the app to the feature.
- Do not break existing functionality. If a change is genuinely required in
  existing code, make the smallest one that works and say so.
- If something in these instructions conflicts with how the application is
  built, follow the application and explain the deviation.

## Final Verification

Before you report the work as done:

1. Re-read the acceptance criteria above and check each one against what you
   actually built.
2. Run the application and exercise the feature end to end.
3. Run the existing test suite and confirm you have broken nothing.
4. Check the feature on mobile, tablet, and desktop widths.
5. Check keyboard navigation and focus handling.
6. Summarize what changed: files added, files modified, and anything you
   deliberately did differently because of how this application is built.

If any acceptance criterion is unmet, fix it before reporting completion.
