Skip to content

Screen inventory

Part of the design-brief package (issue #263). Every surface the design must cover, with per-screen purpose, key states, and priority. Priorities: P1 = the product's core loop, design these first and best; P2 = differentiation surfaces; P3 = back-office (consistent and efficient beats beautiful).

Two surfaces, two registers: public screens follow all five design principles; admin screens are a dense working back-office themed separately (see docs/reference/theming.md — per-surface themes).

Public surfaces

/ — Home (P1)

Purpose: orient each persona (architect/pro, builder, homeowner), teach the right-sizing value proposition, route into the guided flow, a persona track, or compare. Education first — no lead-capture form or gate, ever.

Sections (top to bottom): slim resume bar (returning sessions only — one compact line with resume / start-fresh / dismiss, never tall enough to push the hero below the mobile fold; #840) · photographic hero (admin-set imagery as a cover-fit stage, copy overlaid on the measured --ns-color-scrim, full-bleed when the layout grants --ns-layout-hero-bleed; single primary CTA into /select, compare as the quiet secondary; the hero rendition is preloaded — it is the LCP, budgeted ≤2.5 s on fast-3G via scripts/perf/lcp-home.mjs) · persona track cards (one per published track; whole-card links, ≥44px targets, equal heights) · how-it-works (3 steps) · operation-type education strip (Folding / Sliding / Stacking from the admin enum's education copy + attached family photo, each card deep-linking to its family group in the compare picker; text-only without media, absent without enum data; #841) · right-sizing story (the 645 → 640 → SL45 over-specification example) with showcase imagery · compare entry. The direction doc's "projects" slot is intentionally absent — "Projects like yours" lives on its own results tab (#983).

A video hero still keeps its playable framed treatment instead of the immersive stage (copy over a click-to-play surface would bury the affordance); no hero media at all collapses to the text hero — no placeholder box (the H5 empty-state contract below).

Content section (exemption, #976). The right-sizing story's showcase imagery renders as a Slideshow (one framed image at a time), not the static-first stack the rest of the page uses — a pile of images read as broken. This is a deliberate content-section deviation from the static-first rule: it still degrades to a single static framed image when JS or images are absent, so the "must look designed, not broken" empty-state contract below is preserved. See Slideshow.

StateBehavior the design must handle
SuccessAll sections present
Empty (static-first degradation)No published tracks → no cards section; no session → no resume banner; no images → no showcase strip. The page must look designed, not broken, with every dynamic section absent
ResumeSlim-bar variants (#840): in-progress ("N of M questions answered" + Resume / Start fresh / dismiss) and completed ("You reached a recommendation" + View recommendation / Start fresh / dismiss)
Loading / errorServer-rendered; failures degrade to the empty variants above — no spinners, no error panels on the front door

/select — Guided stepper (P1, the signature screen)

Purpose: one factor per step, educational trade-off content at the decision point, converging on a recommendation. 14 active factors today (interior/ exterior, geography, climate, residential/commercial, ADA, acoustics, durability, opening shape, material & finish, stacking, panel sizes, sill depth & floor type, structural). Steps are data-driven — the design must work for any factor count.

Per-step anatomy: progress ("Step N of M" + indicator) · factor name + description · inline education (the factor's trade-off narrative as first-class reading content — a serif lede above the options, multi-paragraph capable, never a tooltip, never collapsed; #826) · options as toggle buttons (#436), each with its optional "what this means" line visible beneath the label · Previous (not on step 1) / Next (final step: See results). The "?" InfoDisclosure carries only genuinely supplementary depth (an attached visual), never the primary education.

StateBehavior
DefaultOption list unselected; forward action available (answers optional)
SelectedClear selected state; re-clicking the chosen option clears it
Resume offer"Welcome back" card above the stepper: Resume / Start fresh (in-progress) or See your results / Start over (completed). Non-modal, dismissible
Education-less factorA factor without education content renders cleanly with no gap
ErrorNo DB → the route 503s (designed error page out of scope for this brief)

/select results view (P1)

Purpose: the payoff — a right-sized recommendation with visible rationale, plus onward hand-offs. Rendered after the final step (same route).

Anatomy (#836): two tabs via the shared public Tabs, payoff first — "Your recommendation" (default) and "Your answers (N of M)" (the quiet completeness meter lives on the tab label). URL-synced (?view= recommendation|answers), so resume/share deep-links land on the right tab; leaving results for the questions clears the param so the next arrival defaults to the payoff again. Panels stay mounted across switches (state survives); tab changes are announced to screen readers and the panel entrance respects prefers-reduced-motion.

Recommendation tab: recommended system (photo, name, tier) · rationale (which answers drove the match) · cheaper-alternative call-out (first-class, affirmative — see principle 2) · shortlist of close matches · actions: compare shortlist (pre-filled /compare), per-system configurator deep-link, product resources · lead capture.

Answers tab: one-line completeness invitation for a partial session (calm, muted — it replaced the amber "computed from N of M factors" banner) · the answer list (answered / skipped per factor).

StateBehavior
SuccessFull recommendation + rationale + alternatives
Right-sizing nudgeThe cheaper-alternative card — the single most important element in the product; design it as good news
Partial sessionQuiet count on the answers tab label + one-line invitation on the answers tab — never an amber banner above the payoff
Coverage warningPartial data / unmet requirement → calm verification prompt, not red alarm
EmptyNo system satisfies the answers → honest dead-end with guidance to relax specific answers, advisor hand-off
LoadingRecommendation is fetched — brief skeleton/pending state allowed here
Deep-linked tab?view=answers (resume/share) lands on the answers tab; unknown/missing value falls back to the recommendation

/select/[slug] — Track entry (P2)

Purpose: persona-tailored entry into the same stepper (e.g. /select/commercial-pro); track sets factor subset and ordering. Same anatomy and states as /select, plus a track header naming the persona framing. Unknown/unpublished slug → routes to the default flow.

/compare — Comparison matrix (P2, expert register)

Purpose: side-by-side of shortlisted systems over the ~60-attribute matrix; the expert's room — denser by design.

Anatomy: system picker grouped by System Operation Type (Folding / Sliding / Stacking) — each family a fieldset+legend with its education copy + representative media, systems as photo cards (thumb · name · tier chip · tagline, graceful no-photo collapse) · sticky selection tray (running count, removable chips, one "Compare these N" action; fixed bottom bar on mobile; 4-selection cap with calm feedback) (#831) · sticky header row with system names/photos · attribute rows grouped by the 11 MECE categories (in the managed sort_order), each group opened by a sticky sub-header carrying the category name + its managed intro (categories.description) · both axes pinned (system header top, first column left) · difference filter as a segmented control [All attributes | Differences (N)], count always visible · numeric/technical cells in --ns-font-mono + tabular-nums · inline column management: each column header carries a Remove link + an operation-type-grouped Swap select, with a "+ Add system" ghost column (when <4) — every edit rebuilds ?systems= (back/forward + share coherent) (#833) · right-size crown: arriving via the results over-spec hand-off (&crown=), the cheaper-sufficient column shows the compact NudgeCard (success trio, never amber); never rendered on organic visits (#833) · per-system configurator/resources links. (#832)

Responsive behavior (exemption, #834). The /compare matrix is the one public screen that deliberately accepts a "best on desktop" register — a ~60-row × up-to-4-column matrix cannot reflow to a single narrow column without ceasing to be a comparison. Under 768px (the single breakpoint all compare mobile behavior shares) it instead becomes a paged experience, still usable on phones and showroom tablets: the matrix horizontal-scrolls one system column at a time (CSS scroll-snap on the system headers), the first column stays pinned (tightened to 9rem so a value column gets real width) with scroll-padding clearing it, and a column-position dots indicator tracks the in-view column and jumps to any column on tap. Attribute category sub-headers collapse to accordions (default expanded, consistent; inert and always-open ≥768px — a mobile-only affordance, so SSR/desktop render every row expanded with no hydration churn). The selection tray becomes a fixed bottom bar at the same 768px boundary, and all interactive targets are ≥44px on touch. The dots and active-column highlight are progressive enhancement — with no JS the matrix still scrolls and the pin still holds. Verified at 375px and 768px with 4 systems and the longest system names (H4).

Share + print (exemption, additive affordance, #835). Compare is URL-canonical (the ?systems= param encodes the exact selection), so two additive affordances turn that into explicit deliverables architects and homeowners forward. A "Copy link" button in the results toolbar copies location.href verbatim — the shared link reproduces the selection exactly — with on-button + aria-live confirmation and an address-bar fallback when the clipboard API is blocked. A print stylesheet makes the comparison survive a bid meeting: a print-only artifact header (brand line, date produced, compared systems with budget tiers), the full grouped matrix in a monochrome light register normalized across all three themes (the --ns-color-* tokens are overridden on .page in @media print, so a dark theme prints identically to the light one), differences marked non-color-dependently (a solid left rule + a △ glyph + a legend, never a tint a printer may drop), chrome and every control hidden (nav/footer, filter, share, tray, dots, column edit/deep-links), sticky positioning flattened, the system-header row repeated per page, and break-inside: avoid keeping category groups intact where they fit. Allowed-value legends are forced open so citations stay legible on paper. Verified via print-media emulation on nanawall/graphite/linen.

StateBehavior
Pre-filledArriving from results with shortlist populated
Right-sizedResults over-spec hand-off (&crown=) crowns the cheaper-sufficient column; organic visits never crown
EmptyDirect visit, nothing selected → inviting picker, not a blank table
Sparse data"??" / missing cells rendered honestly (em-dash treatment), not as zero
OverflowMore systems than fit → horizontal scroll with sticky first column
Mobile <768pxPaged: scroll-snap columns + position dots, category accordions (default expanded), fixed bottom-bar tray, ≥44px targets (#834)
Share"Copy link" copies the canonical ?systems= URL (reproduces the selection exactly) with aria-live confirmation (#835)
PrintBrand-headed monochrome artifact, normalized across all 3 themes, differences marked non-color-dependently, chrome hidden (#835)
ErrorNo DB → 503

Admin surfaces (/admin/*) — P3

Shared register: dense, utilitarian, system font stack, compact radii (admin theme). Shared chrome: section nav sidebar + content pane. All are CRUD over the product knowledge base; the design must define the patterns (list table, detail form, empty state, destructive confirm, audit trail) more than per-screen art.

ScreenPurpose
/adminDashboard/landing — section directory
/admin/systems, /admin/systems/[id]The 24 systems: list + detail editing (attributes, tiers, media)
/admin/attributes, /admin/attributes/[id]The ~60 matrix attributes: definitions, enum values, descriptions
/admin/factors, /admin/factors/[id]Selection factors: options, education content, display order, retirement
/admin/right-sizing, /admin/right-sizing/[id]Right-sizing rules (the 645→640→SL45 encodings)
/admin/tracks, /admin/tracks/new, /admin/tracks/[id]Persona tracks: factor subsets, ordering, publish state, buyer-facing descriptions
/admin/tiersBudget/Mid/Premium/Ultra tier assignments
/admin/media/* (library, manage, upload, video)Entity media pipeline: browse, attach, upload, video
/admin/corpusKnowledge-corpus documents (ingestion, retrieval)
/admin/drupal-syncDrupal JSON mapping/sync status
/admin/eloquaEloqua lead-integration settings
/admin/auditAudit log of admin writes
/admin/themesPer-surface theme picker

Admin states the pattern library must cover: empty list (call-to-create) · loading · save success/failure feedback · validation errors inline on forms · destructive-action confirmation · retired/unpublished visual distinction.

Out of inventory

/api/* (JSON), /health, and /media/[id]/[spec] (image serving) have no UI. The login surface is HTTP-level (Cloudflare Access / basic auth), not a designed screen.