Replace the single-scroll showcase and its anchor/scrollIntoView
navigation with real routes: /, /patterns, /components/*, /foundations/*,
/docs/*, plus a 404 fallback.
- src/app/routes.tsx is the route table and the only source for paths,
section headings, sidebar entries, breadcrumbs and the rail, so
navigation cannot drift from the pages that exist
- src/pages/* holds one component per route; App.tsx is now the shell
(topbar, sidebar, breadcrumbs, Switch, right rail, scroll-to-top)
- the active pattern moves into the URL (/patterns?pattern=table) and the
sidebar/palette deep-link into it; SearchPalette results now carry a path
- Sidebar/RightRail render <Link> with aria-current; Hero and Topbar use
route links too (ButtonLink keeps the button visual)
- PATTERNS + PatternId move to src/data/patterns.ts (no non-component
export in a component file), pattern buttons gain aria-pressed
- tests/routing.test.tsx: registry/nav invariants, per-route rendering,
sidebar navigation, pattern deep links, 404
Central context for the settings a template app shares instead of prop
drilling: theme, viewMode, sidebarCollapsed and the search palette, with
the ⌘K/Ctrl+K shortcut moved out of App.
- settings persist on user action only (an effect-written theme would
freeze the OS preference for users who never toggled)
- theme still boots from the <html data-theme> attribute the pre-paint
script set; viewMode mirrors to data-view-mode as the audience-preset
hook and deliberately gates nothing yet
- Topbar: viewMode segmented control, theme toggle and search now read
the context; useAppState throws outside the provider
- tests/appState.test.tsx: defaults, persistence, rehydration, garbage
storage values, ⌘K shortcut
The Overlay refactor dropped the early return, so the fixed-inset backdrop
stayed mounted permanently: the palette covered the page and swallowed
every click. Restore the guard and cover it with tests.