# Command Palette

## Objective

Add a keyboard-accessible command interface for navigation and actions.

A command palette turns your app's navigation and actions into a single searchable
overlay, opened from anywhere with a keyboard shortcut.

- Keyboard shortcut to open the palette from anywhere
- Fuzzy search across navigation destinations and actions
- Full keyboard navigation, with the mouse as an option rather than a requirement
- Recent items, so the thing you did last is one keystroke away
- Responsive behaviour that degrades to something usable on a phone
- Accessible focus management and screen reader support

## 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

Add a command palette: a single overlay that lets a user search and jump to any
destination or trigger any action in the application.

Build it from what already exists:

1. **Find the app's routes and pages.** Every primary destination the user can
   already navigate to should become a command. Do not invent new destinations.
2. **Find the app's existing actions** — "create X", "log out", "open settings" —
   and wire the palette to the *existing* handlers. Do not reimplement the logic
   behind a button; call the same code it calls.
3. **Register a global keyboard shortcut** to open the palette. Do not hijack a
   shortcut the application or the browser already uses meaningfully.
4. **Search.** Filter commands as the user types, matching label and keywords.
   Substring matching is enough; do not add a fuzzy-search dependency unless the
   project already has one.
5. **Group results** by kind (Navigation, Actions) when there is more than one
   kind, so the list stays scannable.

## UI and UX Requirements

- Opens instantly. The palette must not wait on a network request to render.
- The search input is focused the moment the palette opens.
- The first result is highlighted by default, so Enter always does something.
- Show the shortcut hint somewhere discoverable — an existing header or menu.
- Selecting a command closes the palette and performs the action.
- Escape closes the palette and returns focus to where it was before.
- Clicking the backdrop closes it.
- If nothing matches, say so — do not render an empty box.

## Responsive Requirements

- **Desktop:** a centered overlay, roughly 560–640px wide, in the upper third of
  the viewport rather than dead center.
- **Tablet:** the same, with reduced width and margins.
- **Mobile:** a full-screen sheet. A phone has no physical keyboard, so the palette
  must also be reachable from a visible control — add a search affordance to the
  existing mobile navigation or header.

## Accessibility Requirements

- The palette is a modal dialog: `role="dialog"` and `aria-modal="true"`.
- **Trap focus** inside the palette while it is open.
- **Restore focus** to the triggering element when it closes.
- Up/Down arrows move through results; Enter selects; Escape closes.
- The results list uses `role="listbox"` with `role="option"` children, and the
  input points at the active option with `aria-activedescendant`.
- Announce the number of results via a live region.
- The highlighted result must be distinguishable without relying on colour alone.
- Respect `prefers-reduced-motion` — no entrance animation when it is set.

## Edge Cases

- **The user is typing in a form.** The shortcut must not fire while focus is in an
  input, textarea, or contenteditable element.
- **The palette is already open.** Pressing the shortcut again closes it.
- **Another modal is open.** Either block the palette or close the other modal
  first — never stack two modals.
- **An action the user lacks permission for.** Hide it. Never show a command that
  fails when selected.
- **The user is signed out.** Show only the commands that make sense signed out.
- **A very long command list.** Cap or virtualize the rendered results; do not
  render a thousand DOM nodes.
- **A recent item pointing at a deleted record.** Drop it from the list rather than
  navigating to a 404.

## Testing

- The shortcut opens the palette from every major page.
- The shortcut does *not* fire while typing in a form field.
- Typing filters the list; a nonsense query shows the empty state.
- Enter activates the highlighted command and it genuinely performs the action.
- Escape closes it and focus returns to the previously focused element.
- Tab cannot move focus outside the open palette.
- It is usable at a 375px viewport width.
- A screen reader announces the dialog and the result count.

## Acceptance Criteria

- [ ] The palette opens from anywhere via the keyboard shortcut.
- [ ] It does not open while the user is typing into a field.
- [ ] Every primary navigation destination is reachable from it.
- [ ] Actions call the app's existing handlers rather than reimplementing them.
- [ ] Search filters results as the user types.
- [ ] The list is fully keyboard-navigable and Enter activates the selection.
- [ ] Escape closes the palette and restores focus.
- [ ] Focus is trapped while it is open.
- [ ] It works on mobile, with a non-keyboard way to open it.
- [ ] It matches the app's existing design system — no new palette or UI library.
- [ ] No existing keyboard shortcut or functionality is broken.

## 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.
