# Tables Frontend Overhaul Implementation Plan

## Purpose

This document turns the vision in [tables_ux_bible.md](./tables_ux_bible.md) into an execution plan for the current Blazor Web App frontend in `src/RolemasterDb.App`.

It is intentionally implementation-focused:

- clear task breakdown
- explicit acceptance criteria
- concrete definition of done
- reasonable implementation order
- minimal churn to the existing backend and API contracts

## Source Inputs

- [tables_ux_bible.md](./tables_ux_bible.md)
- current Blazor app shell and routes in `src/RolemasterDb.App/Components`
- current API and view models in `src/RolemasterDb.App/Features`

## Constraints

- keep the current tech stack
- keep the current backend and API contracts
- keep the current critical-table data model and curation workflow as the domain foundation
- treat route and UI changes as frontend/presentation refactors unless an additive backend endpoint is explicitly approved later
- keep changes incremental and shippable by phase

## Working Status

- Branch: `frontend/tables-overhaul`
- Last updated: `2026-03-21`
- Current focus: `Phase 3`
- Document mode: living plan and progress log

### Progress Log

| Date | Phase | Status | Notes |
| --- | --- | --- | --- |
| 2026-03-21 | Phase 0 | Completed | Created overhaul branch, audited the current frontend, and locked the route map, component boundaries, migration path, and shared-state ownership. |
| 2026-03-21 | P1.1 | Completed | Replaced the legacy token root with semantic background, surface, text, border, focus, shadow, and semantic accent ramps while keeping compatibility aliases for incremental migration. |
| 2026-03-21 | P1.2 | Completed | Switched the app to Fraunces, IBM Plex Sans, and IBM Plex Mono with distinct display, body, UI, and code font roles instead of one shared heading font. |
| 2026-03-21 | P1.3 | Completed | Added explicit light, dark, and system theme modes in the token layer and introduced a scoped `ThemeState` service for later shell controls. |
| 2026-03-21 | P1.4 | Completed | Added shared browser-storage wrappers, persisted theme mode in `localStorage`, and initialize/apply theme state from the layout on interactive render. |
| 2026-03-21 | P1.5 | Completed | Replaced the permanent sidebar layout with a sticky top app shell and mobile bottom navigation backed by dedicated shell components. |
| 2026-03-21 | P1.6 | Completed | Added explicit shell slots for nav, omnibox, shortcuts, and utilities; switched shell navigation to `Play`, `Tables`, `Curation`, and `Tools`; and wired the first live theme control into the shell. |
| 2026-03-21 | P1.7 | Completed | Added a shell-level skip link and tightened the top-level header, navigation, and main landmarks around the new shell structure. |
| 2026-03-21 | P1.8 | Completed | Introduced a cooler tooling emphasis for `Tools`, diagnostics, and API surfaces, and styled the `Tools` destination as distinct without splitting the shell. |
| 2026-03-21 | Post-P1 fix 1 | Completed | Closed the 768px-1023px navigation gap by adding a shell hamburger menu and drawer so primary navigation never disappears at tablet widths. |
| 2026-03-21 | Post-P1 fix 2 | Completed | Replaced the most visible light-only surface and control colors with theme-aware tokens so switching between `Light`, `Dark`, and `System` produces a clear visual change. |
| 2026-03-21 | Post-P1 fix 3 | Completed | Restored layout-level shell interactivity by rendering routed content in `InteractiveServer` mode, which re-enabled shell event handlers such as the hamburger menu and theme selector. |
| 2026-03-21 | Post-P1 fix 4 | Completed | Added early theme bootstrapping in `App.razor` and `theme.js` so the stored mode is applied before hydration and remains visible after refresh. |
| 2026-03-21 | P2.1 | Completed | Added canonical `/tools/diagnostics` and `/tools/api` routes with dedicated tooling page components, extracted the diagnostics and API content into shared tool components, and updated the `Tools` landing page to link to the new route structure. |
| 2026-03-21 | P2.2 | Completed | Replaced the old `/diagnostics` and `/api` pages with lightweight compatibility routes that reuse a shared redirect component, preserve query strings and fragments, and replace browser history while forwarding into the canonical `Tools` routes. |
| 2026-03-21 | P2.3 | Completed | Added a shared `RecentTablesState` service backed by browser storage, centralized the recents storage key, and started recording successful table visits from the `Tables` page so later omnibox and rail work has real shared data. |
| 2026-03-21 | P2.4 | Completed | Added a shared `PinnedTablesState` service with browser persistence, centralized the pin storage key, initialized pin state in the `Tables` page, and added a first live pin/unpin action plus pinned status chips so later omnibox and navigation work have real saved pins to consume. |
| 2026-03-21 | P2.5 | Completed | Added shared table-context URL types and a serializer, registered the serializer centrally, and started round-tripping table context through `/tables` and `/tools/diagnostics` so direct links restore the selected table and diagnostic cell context instead of relying only on local storage defaults. |
| 2026-03-21 | P2.6 | Completed | Replaced the dead shell omnibox trigger with a live drawer-backed omnibox foundation that loads critical tables on demand, filters table search results, surfaces pinned and recent table sections from shared state, and exposes slash-command navigation for the core destinations and tooling routes. |
| 2026-03-21 | P2.7 | Completed | Added shared frontend primitives for app-bar actions, chips, segmented tabs, drawers, inspector sections, and status indicators, wired the shell omnibox trigger onto the new app-bar action primitive, and switched the new pinned-table labels in `Tables` to the shared status-chip primitive so later page work can build on reusable building blocks instead of fresh ad hoc markup. |
| 2026-03-21 | P2.8 | Completed | Added a shared `TableContextState` service on top of browser storage and the URL serializer, moved the `Tables` page off page-local table selection persistence, and switched diagnostics to the same restore/persist/build-URI flow so table context logic now lives in shared frontend state instead of being reinvented per page. |
| 2026-03-21 | Post-P2 fix 1 | Completed | Fixed the shell omnibox drawer regression by adding explicit shell offset variables, constraining drawer/body scrolling, and giving the omnibox its own backdrop geometry so the flyout opens within the visible viewport instead of collapsing into invalid top/bottom positioning. |
| 2026-03-21 | Post-P2 fix 2 | Completed | Rebuilt the shell omnibox as a dedicated command palette instead of a repurposed drawer, with shell-owned overlay markup, explicit viewport-safe geometry, autofocus, Escape and navigation close behavior, and a stable scrollable result body. |
| 2026-03-21 | Post-P2 fix 3 | Completed | Moved omnibox overlay ownership from the header subtree into `AppShell` itself via a shared omnibox state service and a top-level palette host, which restored full-screen backdrop coverage and reliable outside-click close behavior. |
| 2026-03-21 | P3.1 | Completed | Split `Tables.razor` into focused table components for the selector header, context bar, canvas, and legend while leaving loading, deep-link synchronization, and dialog state in the page host. |
| 2026-03-21 | P3.2 | Completed | Replaced the floating table picker with a permanent left-rail layout, converted the old selector component into a real page header, and kept the current selection flow intact inside the new reference frame. |
| 2026-03-21 | P3.3 | Completed | Added rail search, family filters, pinned and recent sections, curated status chips, and keyboard up/down plus Enter handling on top of the new permanent table index rail. |
| 2026-03-21 | P3.4 | Completed | Added a sticky context bar with reference-mode tabs, variant and severity selectors, roll-jump state, and active filter chips, then wired those controls into page state and canvas filtering. |
| 2026-03-21 | P3.5 | Completed | Reworked the canvas with sticky headers, a sticky roll-band column, row and column emphasis driven by selection and roll-jump state, selected-cell treatment, and a comfortable/dense density toggle. |
| 2026-03-21 | P3.6 | Completed | Removed the always-visible cell button stack from resting cells, leaving status-only hints by default and limiting compact edit/curation buttons to the currently selected cell. |

### Lessons Learned

- The current app shell is simple enough that the redesign can land incrementally in `MainLayout.razor` without changing the hosting model in `Program.cs`.
- The current `Tables.razor` page already contains three different concerns: reference browsing, curation queue work, and full editing. Splitting by workflow is the highest-value maintainability move.
- Existing contracts in `LookupContracts.cs` already contain the identifiers needed for deep links and cross-surface navigation: table slug, group key, column key, roll band, and result id.
- Diagnostics already behaves like a separate workflow and should be moved under `Tools` early, before the `Tables` page is rewritten further.
- `localStorage` access is currently page-local and ad hoc. Theme, recents, pins, and table context need one shared storage boundary before more UI work starts.
- The old typography setup coupled display and utility text under a single token. The new shell work needs separate display and UI font roles to avoid decorative type in controls.
- Theme mode selection can be prepared independently of persistence. Splitting those concerns keeps the theme CSS and the storage wiring reviewable.
- Shared UI state events in Blazor should stay synchronous unless the event contract is async-aware. Layout refresh can be triggered safely with `InvokeAsync(StateHasChanged)` from a synchronous handler.
- Extracting shell markup into dedicated components is lower-risk than continuing to evolve `MainLayout.razor` directly. It isolates responsive frame work from page content and keeps later nav changes localized.
- Once a Razor component exposes multiple named `RenderFragment` parameters, the page body must be passed explicitly through `<ChildContent>`. That pattern is now the baseline for shell composition here.
- Accessibility work is cheaper when the shell owns the landmarks. Adding skip links and nav/main structure at the shell layer avoids repeating that work page by page.
- Tooling can feel distinct through cooler surfaces and labeling alone. A separate app shell is unnecessary and would undermine the shared-product goal.
- Responsive shell design needs an explicit tablet state, not just desktop and phone states. The original breakpoints left a navigation dead zone between the top nav and bottom nav layouts.
- Theme infrastructure is not enough on its own. Any surface that keeps hardcoded light values will make the theme switch feel broken even when the selector logic is correct.
- In Blazor Web Apps, page-level render modes do not automatically make layout-level controls interactive in the way this shell expects. The routed shell itself needs an interactive render boundary.
- Persisted theme state should be applied before Blazor hydrates, not only after layout initialization. Otherwise refresh can look broken even when storage writes succeed.
- For route migration in Blazor, extracting the destination UI into shared components keeps canonical routes and temporary compatibility routes from drifting while the redirect phase is still pending.
- Compatibility routes should stay declarative and shared. A single redirect component is enough for route forwarding and avoids copy-pasted `NavigationManager` lifecycle logic in page files.
- Shared browser-backed state becomes more useful once one real page writes to it immediately. Recording recents from `Tables` now keeps later omnibox work from being blocked on synthetic placeholder data.
- Shared pinned-state services also need one live writer early. A minimal pin/unpin affordance in the current `Tables` page is enough to validate persistence before the larger navigation surfaces consume pins.
- URL serializers only pay off when wired into real pages. Using the shared serializer in both `Tables` and diagnostics now gives the project one verified round-trip path before the larger table-context service lands.
- The serializer alone is not the reusable boundary. The maintainable seam is a shared context-state helper that owns restore, persist, normalization, and URI-building conventions while pages keep only workflow-specific selection logic.
- Primitive extraction lands best when one or two live consumers adopt the new components immediately. That keeps the foundation honest without forcing a broad page rewrite just to validate the abstraction.
- The omnibox foundation does not need the full final interaction model to be useful. A drawer with real table search, real pinned/recent data, and a small slash-command set is enough to validate the shell surface before Phase 3 builds deeper index and inspector flows on top of it.
- Shared overlay primitives should not depend on undeclared layout variables. If a drawer needs shell offsets, the shell must define them explicitly and overlay-specific backdrops should be adjustable instead of assuming full-screen dimming is always correct.
- A command palette is not just a styled drawer. It needs shell-owned geometry, predictable focus behavior, and a bounded scroll region; treating it as a generic side panel led directly to the layout regressions found in Phase 2.
- Backdrop and outside-click behavior depend on overlay ownership as much as CSS. If the trigger owns the overlay inside a sticky header subtree, fixed-position assumptions can break; shell-level overlays should be rendered by the shell, not by individual header controls.
- The `Tables` rewrite is safer when orchestration and rendering are separated early. Keeping loading, persistence, and dialog state in the page host while extracting render-only components makes later layout and interaction changes much lower risk.
- The `Tables` navigation model needs its own persistent geometry before advanced behaviors land. Converting the selector to a real rail first keeps later search and keyboard work from being tangled up with another structural rewrite.
- Rail keyboard behavior is easiest to maintain when it works from one deduplicated option order, even if the UI shows multiple sections. Keeping one internal option list avoids separate arrow-key state per section.
- The context bar controls should own one shared view-state model before the canvas gets more visual treatment. Wiring the filters into the host page now avoids a second refactor when row, column, and cell emphasis land.
- Canvas emphasis becomes maintainable once selection, roll-jump, and density are all fed through one explicit state model. That lets the grid respond to context without hiding selection logic inside CSS-only heuristics.
- Resting-cell quietness should be enforced structurally, not only visually. Showing actions only for the selected cell prevents future CSS regressions from reintroducing button clutter across the whole grid.

## Target Outcomes

The overhaul is complete when the app behaves as one coherent product with four clear destination families:

- `Play` for live lookup and fast resolution
- `Tables` for reference and inspection
- `Curation` for queue-based repair work
- `Tools` for diagnostics and API documentation

The new shell, navigation, spacing, theming, and interaction grammar must be reusable for future pages.

## Overall Definition Of Done

The frontend overhaul is done when all of the following are true:

- the app uses a shared design system with explicit light, dark, and system themes
- the primary navigation matches the UX bible and no longer reflects implementation buckets
- `/tables` is browse-first, selection-driven, and free of resting-state cell action clutter
- `Curation` is a dedicated queue-first workflow rather than ambient clutter inside `Tables`
- diagnostics and API docs are grouped under `Tools`
- `Play` and `Tables` share the same shell and interaction model
- deep links preserve object context for key user journeys
- keyboard, focus, contrast, responsive behavior, and sticky layout behavior meet the UX bible rules
- the solution is maintainable, with the current monolithic `Tables` page split into reusable components and services

## Delivery Strategy

Implement in vertical slices, not by page-wide rewrites. Each phase should leave the app in a buildable, reviewable, and partially usable state.

Recommended order:

1. foundation and shell
2. shared state and deep-link infrastructure
3. `Tables` reference experience
4. `Curation` workflow
5. `Tools` consolidation
6. `Play` alignment
7. hardening, QA, and rollout cleanup

## Phase 0: Discovery And Technical Baseline

### Status

`Completed`

### Goal

Create the implementation foundation so the visual overhaul does not start with uncontrolled edits in page files.

### Tasks

- `P0.1` Audit current component ownership in `Components/Layout`, `Components/Pages`, and `Components/Shared`.
- `P0.2` Identify which behaviors already exist and should be preserved:
  - selected table persistence
  - cell editor and curation dialogs
  - diagnostics selection model
  - lookup forms and result cards
- `P0.3` Define the target frontend structure for the overhaul.
- `P0.4` Decide the new route map and compatibility redirects.
- `P0.5` Define a shared frontend state strategy for:
  - theme
  - recent tables
  - pinned tables
  - selected table context
  - deep-link parsing and serialization
- `P0.6` Define component boundaries for shared primitives before major page work starts.

### Deliverables

- agreed route map
- agreed component and state boundaries
- agreed migration path from current shell and pages

### Acceptance Criteria

- every planned frontend surface has an explicit owner component or service area
- route compatibility is defined before navigation work begins
- there is a clear plan for what stays in page components versus what moves to shared services/components

### Definition Of Done

- no unresolved structural ambiguity remains around shell, routes, state ownership, or shared primitives

### Current Repo Audit

| Area | Current owner | Current responsibility | Phase 0 decision |
| --- | --- | --- | --- |
| App host | `src/RolemasterDb.App/Components/App.razor` | document shell, fonts, global CSS/script includes | keep as the document root; only update fonts and global assets during Phase 1 |
| Router | `src/RolemasterDb.App/Components/Routes.razor` | route resolution and layout selection | keep single router; add compatibility route components instead of special middleware redirects |
| App shell | `src/RolemasterDb.App/Components/Layout/MainLayout.razor` | current sidebar layout and page body host | replace with the new top app bar shell and mobile bottom nav |
| Primary nav | `src/RolemasterDb.App/Components/Layout/NavMenu.razor` | implementation-bucket navigation | retire after the new shell lands; replace with destination navigation primitives |
| Home page | `src/RolemasterDb.App/Components/Pages/Home.razor` | live lookup flow | keep behavior, later restyle and reframe as `Play` |
| Tables page | `src/RolemasterDb.App/Components/Pages/Tables.razor` | table selection, table rendering, persisted selection, editor launch, curation queue work | split into page shell, selection state, index rail, context bar, table canvas, inspector, and action services |
| Diagnostics page | `src/RolemasterDb.App/Components/Pages/Diagnostics.razor` | engineering inspection of a selected cell | move under `Tools` and reuse shared table-selection state |
| API page | `src/RolemasterDb.App/Components/Pages/Api.razor` | static API docs page | move under `Tools` with updated framing |
| Shared editor and curation UI | `src/RolemasterDb.App/Components/Shared/CriticalCellEditorDialog.razor`, `src/RolemasterDb.App/Components/Shared/CriticalCellCurationDialog.razor` | full editing and quick curation interactions | preserve behavior; change launch points and page ownership |
| Lookup and table contracts | `src/RolemasterDb.App/Features/LookupContracts.cs` | frontend-facing DTOs for tables, lookups, editing, and diagnostics | preserve contracts; build frontend state and deep links around them |

### Behaviors To Preserve

| Behavior | Current source | Preserve as | Notes |
| --- | --- | --- | --- |
| Selected table persistence | `Tables.razor` local storage key `rolemaster.tables.selectedTable` | shared per-destination context persistence service | move out of page code during Phase 2 |
| Full cell editor flow | `Tables.razor` + `CriticalCellEditorDialog.razor` | stable editor entry from inspector, curation, and tools | editor remains modal for now |
| Quick curation flow and save-next behavior | `Tables.razor` + `CriticalCellCurationDialog.razor` | dedicated `Curation` workflow with reused quick-parse components | queue logic moves off the reference page |
| Diagnostics selection model | `Diagnostics.razor` | shared table-position selector model used by `Tools` | existing selection order is a good starting point |
| Attack and direct critical lookup flows | `Home.razor` | `Play` page behaviors | preserve contracts and calculation behavior |
| Result preview components | `CriticalLookupResultCard.razor`, `CompactCriticalCell.razor`, related shared components | reusable reference and inspector content | keep and adapt instead of rewriting presentation logic from scratch |

### Resolved Route Map

| Surface | Target route | Compatibility handling | Owner page/component |
| --- | --- | --- | --- |
| Play | `/` | none | `Pages/Home.razor` until renamed later |
| Tables | `/tables` | none | `Pages/Tables.razor`, later split into page components under `Components/Tables` |
| Curation | `/curation` | none | new page introduced in Phase 4 |
| Tools landing | `/tools` | none | new page introduced in Phase 5 |
| Diagnostics | `/tools/diagnostics` | keep `/diagnostics` as compatibility page that forwards to `/tools/diagnostics` | new page in `Pages/Tools/Diagnostics.razor` |
| API docs | `/tools/api` | keep `/api` as compatibility page that forwards to `/tools/api` | new page in `Pages/Tools/Api.razor` |

### Route Compatibility Strategy

- Use lightweight compatibility pages instead of server-side redirects so route behavior stays inside the Blazor app.
- Compatibility pages should preserve query string values and replace browser history when forwarding, so old bookmarks do not create noisy back-stack entries.
- New deep-link work should target the destination routes only. Compatibility pages are temporary migration aids and should not gain new UI.

### Target Frontend Structure

| Area | Planned location | Responsibility |
| --- | --- | --- |
| Shell components | `src/RolemasterDb.App/Components/Shell` | app frame, top app bar, bottom nav, destination nav, shell actions |
| Shared app state | `src/RolemasterDb.App/Frontend/AppState` | theme, recents, pins, selected context, URL serialization, storage access |
| Shared primitives | `src/RolemasterDb.App/Components/Primitives` | chips, tabs, buttons, drawers, inspector sections, empty states |
| Tables-specific components | `src/RolemasterDb.App/Components/Tables` | index rail, context bar, table canvas, inspector, state adapters |
| Curation-specific components | `src/RolemasterDb.App/Components/Curation` | queue layout, quick parse surface, save-and-advance actions |
| Tools-specific components | `src/RolemasterDb.App/Components/Tools` | diagnostics inspector, API docs framing, context links |
| Play-specific components | `src/RolemasterDb.App/Components/Play` | lookup forms, result rail, deep-link actions |

### Shared State Strategy

| Concern | Planned owner | Persistence | Consumers |
| --- | --- | --- | --- |
| Theme mode | `ThemeState` service | `localStorage` | shell, all pages |
| Recent tables | `RecentTablesState` service | `localStorage` | shell omnibox, tables rail, curation |
| Pinned tables | `PinnedTablesState` service | `localStorage` | shell shortcuts, tables rail, curation |
| Selected table context | `TableContextState` service | URL first, `localStorage` fallback per destination | tables, curation, tools |
| Table deep-link parsing and serialization | `TableContextUrlSerializer` helper | URL only | tables, curation, tools, play deep links |
| Local storage access | `BrowserStorageService` | wrapper around JS interop | all frontend state services |

### State Ownership Rules

- URL state is the source of truth for sharable context.
- Local storage is only for preferences and last-used convenience state.
- Page components should consume state services and emit intents. They should not own persistence logic directly.
- Editor and curation dialog transient state stays local to the workflow component that opened it.

### Shared Primitive Boundaries

| Primitive | First consumer | Notes |
| --- | --- | --- |
| App bar and destination nav | shell | replaces `NavMenu.razor` |
| Bottom nav | shell | mobile-only persistent destination nav |
| Omnibox trigger and panel | shell, tables | foundation in Phase 2; full search later |
| Chip and status pill primitives | shell, tables, curation, tools | replace ad hoc chip styling in `app.css` |
| Tabs and segmented controls | tables, tools | mode switching and filtered views |
| Drawer and bottom sheet primitives | tables, curation | inspector on small screens |
| Inspector section cards | tables, tools, curation | unify right-rail and sheet layout |

### Migration Path

1. Land the new shell and theme infrastructure in `MainLayout.razor` and `wwwroot/app.css` without changing page internals.
2. Add shared state and compatibility routes before splitting the largest pages.
3. Move diagnostics and API docs under `Tools` early to reduce noise in the main navigation.
4. Split `Tables.razor` into composable pieces while preserving existing editor and curation behaviors.
5. Extract the dedicated `Curation` workflow once the shared selector and table context code already exists.
6. Restyle and reconnect `Play` after shell, deep links, and shared primitives are stable.

### Phase 0 Exit Criteria

- the route map above is treated as implementation truth unless a later change is explicitly recorded here
- page, shell, and shared-state ownership are defined strongly enough to begin Phase 1 without structural rework
- compatibility handling for `/diagnostics` and `/api` is decided
- preserved behaviors are identified so later phases do not regress them accidentally

### Next Implementation Slice

- Start Phase 1 with the shell and design-token foundation in `MainLayout.razor`, `App.razor`, and `wwwroot/app.css`.
- Introduce the shared theme state and browser storage wrapper before rewriting destination pages.
- Replace the current sidebar navigation first so later page work lands inside the target shell instead of the legacy layout.

## Phase 1: Design System And Application Shell

### Status

`Completed`

### Task Progress

| Task | Status | Notes |
| --- | --- | --- |
| `P1.1` | Completed | Semantic token layer landed in `wwwroot/app.css` with compatibility aliases to keep existing pages stable. |
| `P1.2` | Completed | Font loading now uses Fraunces, IBM Plex Sans, and IBM Plex Mono with explicit role-based tokens. |
| `P1.3` | Completed | Explicit light, dark, and system modes now exist in CSS, backed by a scoped `ThemeState` service. |
| `P1.4` | Completed | Theme mode now persists through a shared storage service and is applied from the layout during interactive startup. |
| `P1.5` | Completed | The sidebar is gone; pages now render inside a sticky top-shell with a mobile bottom nav. |
| `P1.6` | Completed | The shell now has explicit nav, omnibox, shortcut, and utility slots, plus a live theme selector and destination-model navigation. |
| `P1.7` | Completed | The shell now exposes a skip link and explicit header/nav/main landmarks. |
| `P1.8` | Completed | Tooling surfaces and the `Tools` nav item now use a cooler emphasis without leaving the shared shell system. |

### Goal

Establish the shared shell, tokens, typography, and theme system that every destination will inherit.

### Tasks

- `P1.1` Replace the current token set in `wwwroot/app.css` with a semantic token system aligned to the UX bible:
  - `--bg-*`
  - `--surface-*`
  - `--text-*`
  - `--border-*`
  - `--focus-*`
  - `--shadow-*`
  - accent ramp
  - success ramp
  - warning ramp
  - danger ramp
  - info ramp
- `P1.2` Update typography to:
  - `Fraunces` for display and section titles
  - `IBM Plex Sans` for body and UI labels
  - `IBM Plex Mono` for diagnostics and code
- `P1.3` Implement theme modes:
  - `Light`
  - `Dark`
  - `System`
- `P1.4` Persist theme preference in browser storage.
- `P1.5` Replace the current sidebar-first layout with a responsive shell:
  - top app bar on desktop
  - mobile top bar
  - mobile bottom nav
- `P1.6` Add global shell slots for:
  - app mark
  - primary destination nav
  - omnibox trigger or field
  - recent/pinned shortcut slot
  - theme/settings/help utilities
- `P1.7` Add a skip link and ensure main-content landmarks are valid.
- `P1.8` Keep tools visually separated from play-facing surfaces through styling and labeling, not a separate app.

### Deliverables

- global shell component(s)
- theme service or equivalent state holder
- revised design token layer
- updated app typography

### Acceptance Criteria

- the app no longer depends on the old permanent navigation rail for primary navigation
- theme selection survives reload
- light and dark themes are intentionally designed, not simple inversion
- sticky top navigation does not obscure page content
- the shell works at 375px, 768px, 1024px, and 1440px without horizontal overflow

### Definition Of Done

- all pages render inside the new shell
- primary navigation shows `Play`, `Tables`, `Curation`, and `Tools`
- the app has a stable theme system and global spacing/typography rules

### Phase 1 Exit Notes

- The app now has a semantic token system, explicit typography roles, theme modes with persistence, and a responsive shell.
- The shell already uses the destination model `Play`, `Tables`, `Curation`, and `Tools`, even though deeper route migration remains a Phase 2 concern.
- The next implementation focus is Phase 2: shared route compatibility, recents, pins, omnibox foundations, and deep-link infrastructure.

## Phase 2: Shared Navigation, Search, And State Infrastructure

### Status

`Completed`

### Task Progress

| Task | Status | Notes |
| --- | --- | --- |
| `P2.1` | Completed | Canonical `Tools` child routes now exist, backed by dedicated route pages and shared tooling content components. |
| `P2.2` | Completed | Old `/diagnostics` and `/api` routes now forward into the canonical `Tools` routes with shared redirect behavior. |
| `P2.3` | Completed | Recent critical-table visits now persist through a shared app-state service and are recorded from the `Tables` page. |
| `P2.4` | Completed | Pinned tables now persist through a shared app-state service and can already be toggled from the `Tables` page. |
| `P2.5` | Completed | Shared table-context URLs now parse and serialize through one helper and are consumed by `/tables` and `/tools/diagnostics`. |
| `P2.6` | Completed | The shell omnibox now opens a live drawer with table search, pinned tables, recent tables, and slash-command navigation. |
| `P2.7` | Completed | Shared primitives for chips, tabs, drawers, inspector sections, app-bar actions, and status indicators now exist in reusable components. |
| `P2.8` | Completed | Table-context restore, persistence, normalization, and URI building now flow through one shared state service used by `Tables` and diagnostics. |

### Goal

Build the shared interaction infrastructure needed by multiple destinations before page-specific UI work deepens.

### Tasks

- `P2.1` Implement the frontend route structure:
  - keep `/`
  - keep `/tables`
  - add `/curation`
  - add `/tools`
  - move diagnostics and API docs under `/tools/...`
- `P2.2` Add compatibility redirects or navigation helpers for old `/diagnostics` and `/api` links.
- `P2.3` Implement a shared recent-items model for critical tables.
- `P2.4` Implement pinned tables state and persistence.
- `P2.5` Implement deep-link parsing and URL serialization for table context:
  - table slug
  - group key
  - column key
  - roll band or roll jump
  - selected cell result id
  - mode
- `P2.6` Build an omnibox foundation that can support:
  - table search
  - recent items
  - pinned items
  - slash commands
- `P2.7` Create shared primitives for:
  - chips
  - tabs
  - app-bar actions
  - drawers or sheets
  - inspector sections
  - status indicators
- `P2.8` Create a shared table-selection service or helper so `Tables`, `Curation`, and `Tools` do not each reinvent selection logic.

### Deliverables

- route updates
- local storage persistence helpers
- omnibox/search primitives
- shared state services/helpers

### Acceptance Criteria

- direct links into a selected table context can be opened and restored reliably
- recent and pinned tables are available to any page that needs them
- diagnostics and API docs remain reachable via new tools routes
- shared controls exist before page-specific implementations duplicate them

### Definition Of Done

- common navigation and state concerns are implemented once and consumed from shared code

## Phase 3: `Tables` Reference Experience

### Status

`In progress`

### Task Progress

| Task | Status | Notes |
| --- | --- | --- |
| `P3.1` | Completed | `Tables.razor` now acts as the stateful host while selector/header/canvas/legend rendering lives in dedicated `Components/Tables` components. |
| `P3.2` | Completed | The old dropdown picker is gone; `/tables` now uses a permanent left rail and a real page header while keeping the current selection flow intact. |
| `P3.3` | Completed | The rail now supports search-as-you-type, family filters, pinned and recent sections, curated status chips, and a deduplicated arrow/Enter keyboard path. |
| `P3.4` | Completed | The table surface now has a sticky context bar with mode tabs, variant/severity focus, roll-jump state, and active filter chips wired into host-page view state. |
| `P3.5` | Completed | The canvas now supports sticky headers and roll bands, row and column emphasis from selection and roll-jump state, selected-cell treatment, and a comfortable/dense density toggle. |
| `P3.6` | Completed | Resting cells now show only status hints; compact edit/curation buttons appear only for the selected cell. |
| `P3.7` | Pending | Add the desktop selection-driven inspector. |
| `P3.8` | Pending | Add the mobile bottom-sheet inspector variant. |
| `P3.9` | Pending | Move legend/help to an on-demand secondary surface. |
| `P3.10` | Pending | Hide maintenance and developer noise in default reference mode. |
| `P3.11` | Pending | Preserve editor and curation entry points through the inspector. |
| `P3.12` | Pending | Normalize click/tap/keyboard selection and close the phase with a hardening pass. |

### Goal

Turn `/tables` into the canonical reference surface for reading and inspecting critical tables quickly.

### Tasks

- `P3.1` Split the current `Tables.razor` into smaller components:
  - page header
  - table index rail
  - sticky context bar
  - table canvas
  - inspector
  - filter and mode controls
- `P3.2` Replace the current dropdown table picker with a searchable left rail.
- `P3.3` Add table index behavior:
  - search-as-you-type
  - keyboard arrow navigation
  - enter to open
  - pinned group
  - recent group
  - all tables list
  - status chip showing curated percentage
  - optional family filters
- `P3.4` Build the sticky context bar with:
  - current table title
  - variant selector when applicable
  - roll jump input
  - optional severity focus
  - mode tabs
  - filter chips
- `P3.5` Rework the table canvas for reference reading:
  - sticky top headers
  - sticky left roll-band column
  - active row emphasis
  - active column emphasis
  - selected cell focus treatment
  - optional roll-jump marker
  - density toggle
- `P3.6` Remove resting-state button clutter from cells.
- `P3.7` Move cell actions to a selection-driven inspector and optional compact selected-cell affordances.
- `P3.8` Build the right inspector on desktop and bottom-sheet inspector on mobile.
- `P3.9` Rework legend/help so it is on-demand and secondary to the canvas.
- `P3.10` Hide maintenance and developer noise in default `Reference` mode.
- `P3.11` Preserve the current full editor and curation entry points, but expose them from the inspector instead of per-cell button stacks.
- `P3.12` Ensure one-tap or one-click selection works the same on desktop and touch.

### Deliverables

- new `Tables` page composition
- left rail selector
- sticky context bar
- selection-driven inspector
- deep-link-aware table state

### Acceptance Criteria

- a user can open a table in one search action from the index rail or omnibox
- a user can jump to a roll using a dedicated roll field
- the selected row, column, and cell are visually obvious
- a result can be read without opening a modal
- no action in `Tables` depends on hover-only discovery
- non-selected cells remain visually quiet
- mobile keeps the same task model using sheets instead of a persistent inspector

### Definition Of Done

- `/tables` is browse-first, not edit-first
- the grid is visually dominant and the inspector is secondary
- resting cells contain state hints, not visible action stacks

## Phase 4: `Curation` Workflow Surface

### Goal

Create a dedicated queue-first curation workflow so repair work is fast and does not pollute the reference experience.

### Tasks

- `P4.1` Create the new `/curation` page and route.
- `P4.2` Reuse shared table/context selection patterns from Phase 2 and Phase 3.
- `P4.3` Define queue scopes:
  - all tables
  - selected table
  - pinned set
- `P4.4` Build a stable queue-first layout with:
  - current queue item summary
  - source image
  - parsed preview
  - quick parse area
  - save-and-advance actions
- `P4.5` Move the current “next uncurated” logic into the dedicated workflow surface.
- `P4.6` Keep full editor access available, but make quick parse and mark curated the fast path.
- `P4.7` Ensure save-and-advance keeps the user in the same workflow lane without reopening context.
- `P4.8` Use warning styling only for disruptive repair actions, not for normal save flow.
- `P4.9` Hide developer-only diagnostics from the normal curation workflow.

### Deliverables

- `/curation` page
- queue-first layout
- integrated save-and-advance flow
- quick parse in-context workflow

### Acceptance Criteria

- a curator can move from one uncurated cell to the next with one primary action after save
- source and parsed result are visible side by side on wide screens
- quick parse can be completed without opening the full editor for common cases
- `Tables` no longer carries the primary queue-work burden

### Definition Of Done

- curation is a dedicated workflow page with a stable repeated interaction loop

## Phase 5: `Tools` Consolidation

### Goal

Separate diagnostic and developer tooling from player-facing flows without losing deep-link usefulness.

### Tasks

- `P5.1` Create a `Tools` landing page.
- `P5.2` Move diagnostics to `/tools/diagnostics`.
- `P5.3` Move API documentation to `/tools/api`.
- `P5.4` Reuse shared selection and table-context patterns so tooling feels related but distinct.
- `P5.5` Add cross-links back to `Tables` and `Curation` preserving object context where possible.
- `P5.6` Keep raw JSON, parser provenance, and deep inspection limited to tooling surfaces.
- `P5.7` Style tooling surfaces with the shared system but with the subdued “cool slate” tooling emphasis defined by the UX bible.

### Deliverables

- `Tools` hub
- migrated diagnostics page
- migrated API docs page
- context-preserving navigation back into reference and curation views

### Acceptance Criteria

- diagnostics and API docs remain bookmarkable
- player-facing pages no longer expose raw payload inspection
- a developer can inspect a cell in tools and jump back to its reference or curation context

### Definition Of Done

- developer-facing tools are clearly separated in both navigation and presentation

## Phase 6: `Play` Alignment

### Goal

Make the default landing experience feel like part of the same product and connect it to the new reference surfaces.

### Tasks

- `P6.1` Reframe the current home page as `Play`.
- `P6.2` Apply the new shell, typography, spacing, token, and action hierarchy to lookup forms and results.
- `P6.3` Reorganize the page to prioritize fast resolution over dashboard-like symmetry.
- `P6.4` Add deep links from lookup outcomes into `Tables` where the user wants to inspect the underlying critical result.
- `P6.5` Ensure player-facing copy avoids maintenance terminology.
- `P6.6` Preserve current lookup behavior and contracts while improving layout, clarity, and action priority.

### Deliverables

- updated `/` page within the new shell
- unified visual and interaction system
- result-to-table deep-link paths

### Acceptance Criteria

- a lookup result can lead directly into the relevant table context
- `Play` shares the same design language as `Tables` and `Curation`
- the primary action on the page is always obvious

### Definition Of Done

- `Play` and `Tables` feel connected, not like separate demos

## Phase 7: Hardening, Accessibility, Performance, And Rollout Cleanup

### Goal

Stabilize the overhaul and ensure the final UX matches the bible under real usage conditions.

### Tasks

- `P7.1` Review keyboard reachability for all app-bar actions, chips, tabs, table index items, table cells, inspector actions, and drawers.
- `P7.2` Verify visible focus states across light and dark themes.
- `P7.3` Verify contrast and accent-vs-semantic color distinction in both themes.
- `P7.4` Test sticky headers, sticky context bars, inspectors, and sheets across target breakpoints.
- `P7.5` Verify no page content is obscured by fixed or sticky shell elements.
- `P7.6` Verify deep links round-trip correctly across `Play`, `Tables`, `Curation`, and `Tools`.
- `P7.7` Verify last-used context persistence per destination.
- `P7.8` Measure table-switch and inspector-open performance and optimize obvious hotspots.
- `P7.9` Introduce virtualization only if profiling shows it is required and sticky behavior remains intact.
- `P7.10` Remove obsolete CSS and component paths left behind by the old shell or old `/tables` flow.
- `P7.11` Update documentation to reflect the final route map and shell model.

### Deliverables

- accessibility review pass
- responsive review pass
- performance review pass
- cleaned-up documentation and obsolete styles/components removed

### Acceptance Criteria

- keyboard-only usage is viable for the major reference and curation flows
- the app has no hover-only critical actions
- mobile hit targets are at least 44x44 px on primary controls
- there is no horizontal page overflow except intentional table-canvas panning
- table switching feels fast after initial load

### Definition Of Done

- the overhaul is stable, accessible, responsive, and cleaned up for future extension

## Cross-Cutting Technical Tasks

These tasks should be scheduled alongside the phases above rather than saved for the end.

### Component Architecture

- extract new classes and services into their own files
- keep page components thin and move reusable logic into helpers/services
- favor shared components over repeated markup in page files

### State Management

- centralize local storage keys
- avoid duplicating route parsing logic across pages
- keep selection state deterministic and serializable

### Visual Consistency

- use shared button hierarchy and chip patterns
- reserve warning and danger styles for true risk states
- ensure tools, curation, and reference surfaces differ through emphasis, not through unrelated styling systems

### Accessibility

- use semantic headings in order
- use true button and link elements for interactions
- only use grid semantics if keyboard behavior matches the semantics

### Documentation

- update related docs when route names, page responsibilities, or user flows materially change

## Proposed Task Sequencing Within The Repo

This is the recommended execution order at file and module level.

1. create shared theme, shell, and app-bar primitives
2. update root app layout and route structure
3. add shared state helpers for theme, recents, pins, and deep links
4. migrate diagnostics and API routes into the `Tools` shape with compatibility handling
5. split `Tables.razor` into focused components and land the new reference mode
6. add the dedicated `Curation` page reusing shared selectors and editor flows
7. align `Home.razor` into `Play`
8. remove obsolete shell and `/tables` implementation fragments
9. complete accessibility, responsive, and performance hardening

## Milestone-Based Acceptance Summary

### Milestone A

Foundation is accepted when the new shell, theme system, and route structure are in place without breaking basic navigation.

### Milestone B

`Tables` is accepted when a gamemaster can locate a table, jump to a result, and read it without modal friction or cell-level chrome clutter.

### Milestone C

`Curation` is accepted when a curator can save and advance through a stable queue flow without using `Tables` as the primary repair surface.

### Milestone D

`Tools` is accepted when diagnostics and API documentation are grouped under tooling routes and do not pollute player-facing flows.

### Milestone E

The overhaul is fully accepted when `Play`, `Tables`, `Curation`, and `Tools` all share the same shell, theme, navigation grammar, and deep-link model.

## Non-Goals For This Plan

- changing the backend data model
- redesigning API contracts
- adding speculative admin surfaces not described in the UX bible
- introducing a new frontend framework
- forcing virtualization before actual profiling justifies it

## Recommended First Implementation Slice

Start with a narrow but high-leverage slice:

1. semantic tokens and theme persistence
2. top app bar and mobile bottom nav
3. route restructuring for `Tools`
4. shared state helpers for recents, pins, and deep links
5. extraction of `/tables` shell pieces without yet rewriting every detail of the canvas

This sequence reduces risk because it establishes the shared infrastructure before the most complex page rewrite.
