Shell
The signed-in web app has one shell for every program page: a rail on the left, a panel next to it
and a topbar. The rail names areas (Home, the four products, Setup, Organization); the panel lists the
sections of the selected area; the topbar holds the program switcher, breadcrumbs, the command palette and
the theme toggle. UI paths in these docs are written Area › Section.
Rail
| Rail item | Shown when | First section |
|---|---|---|
| Home | always inside a program | /p/<slug>/home |
| Evidence | evidence.questions.read | /evidence/questions |
| Plans | plans.plans.read | /plans/plans |
| Review | review.findings.read | /review/findings |
| Progress | progress.milestones.read | /progress/overview |
| Setup | program.settings.read (Overview) or any Setup section permission | /setup/overview |
| Organization | any org.*.read | /org/settings |
The rail sits on Midnight (--rail-bg) with White foreground and lifted hover and active states
(--rail-hover, --rail-active); the brand symbol is the reversed variant. Each product item carries its
kit icon.
Panel
Sections come from web/lib/content.ts (productSections, setupNav, orgNav) and each is filtered by
its permission: Evidence (Questions, Sources, Findings, Hypotheses, Gaps), Plans (Plans, Protocols,
Experiments, Reports, Tools), Review (SOPs, Checks, Findings, Deviations), Progress (Overview, Milestones,
Dependencies, Open items, Approvals), Setup (Overview, Connections, Members, Roles, Agent runs, Audit),
Organization (Settings, Programs, Users, Groups, Roles, Audit). The panel can be collapsed with the
“Toggle sections panel” control; its state is the shell_panel cookie (open or closed, path /,
30 days, SameSite=Lax), read by the server layout so the first paint matches.
Topbar
- Program switcher (aria-label “Switch program”): a listbox titled “Programs” listing the programs from
/mein the app’s order; choosing one writes thelast_programcookie. - Breadcrumbs: program, area, section.
- Command palette: searches sections (“Search sections”); the keyboard order is tested end to end.
- Theme toggle: switches between light and dark; until a choice is made the theme follows the system preference; the storage key is
themeand the dark class ishtml.dark.
Breakpoints
| Width | Behaviour |
|---|---|
| above 1100 px | rail and panel side by side with the content |
| 1100 px and below | the panel becomes an overlay opened from the topbar |
| 767 px and below | rail and panel move into a navigation sheet (“Open navigation”); tables scroll inside .table-scroller, product cards stack in one column and the stage rail wraps to two columns |
The e2e suite checks the 1100 px overlay and the 390 px sheet; check:mobile fails when any element
outside a .table-scroller exceeds the 390 x 844 viewport.
Cookies and redirects
| Name | Purpose | Attributes |
|---|---|---|
last_program | the program / resolves to | path /, 180 days, SameSite=Lax |
shell_panel | panel open or closed | path /, 30 days, SameSite=Lax |
/p/<slug> redirects 308 to /p/<slug>/home and /org to /org/settings, query preserved
(legacyRedirectTarget in web/lib/routes.ts). The resolver at / reads /me, then last_program,
then the first program.
Vocabulary on screen
“Saved” confirms a completed UI action; “Approved” is only the status of an approval record. Status chips always print a text label; product accents never carry status meaning; the action colour is never the fail colour. Seeded records show “Illustrative”.
Source: web/components/shell/app-shell.tsx, web/components/shell/panel-state.ts, web/lib/routes.ts, web/lib/program.tsx, web/lib/content.ts, web/README.md, PRODUCT-CONTRACT.md