Skip to Content

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 itemShown whenFirst section
Homealways inside a program/p/<slug>/home
Evidenceevidence.questions.read/evidence/questions
Plansplans.plans.read/plans/plans
Reviewreview.findings.read/review/findings
Progressprogress.milestones.read/progress/overview
Setupprogram.settings.read (Overview) or any Setup section permission/setup/overview
Organizationany 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 /me in the app’s order; choosing one writes the last_program cookie.
  • 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 theme and the dark class is html.dark.

Breakpoints

WidthBehaviour
above 1100 pxrail and panel side by side with the content
1100 px and belowthe panel becomes an overlay opened from the topbar
767 px and belowrail 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

NamePurposeAttributes
last_programthe program / resolves topath /, 180 days, SameSite=Lax
shell_panelpanel open or closedpath /, 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