Layout Contract

Overview

This page is the short list of rules a screen must satisfy before anything screen-specific is designed. The detail lives in the pages it points to; where they disagree with this page, this page wins.

Principles

  • Maximise screen real estate. Content uses the full width and height of the window. No maximum content width, no decorative bands, no element that repeats what another element already says.

  • One place for each thing. One title, one scope indicator, one record count, one set of paging controls, one filter band.

  • Lists are consistent with each other. Two list screens differ only in their columns, toggles and actions — never in typography, band order or control style.

  • State is shown, not inferred. A selected toggle carries a tick; a disabled control says why.

Vertical Stack

Band Contents Specified by

Breadcrumb

Organisation › parent list › entity [status] date › screen [› child page]. Last crumb is the page’s <h1>.

C01 rev 8

Tab strip

Instance scope, with a leaf row only where a tab holds more than one sibling screen; or a tenant-scope section (see Section Tabs at Tenant Scope).

C01 rev 8, rev 9

Command row

Actions or the bulk bar, right-aligned, every button btn-sm; an optional line of context on the left for non-list screens, or a status pill on a detail screen. One row, and the only sticky band. Facts about the record go on a summary card on the content surface, not here. Omitted when the screen has neither.

C09 rev 2

Content surface

The screen body. For a list: filter band, table, pagination bar.

List screen affordances

Chrome above the content is at most two rows at instance scope and one at tenant scope, or two on a screen of a tenant-scope section.

Section Tabs at Tenant Scope

A sidebar row may anchor a section: several tenant-scope screens over the same data that share one tab strip. Numbers & Tags is the only section so far, with the tabs Stock status, Numbers, UNFIT and Activity.

  • The tab strip is the instance tab strip’s: the same component (ap-tabs in link mode), the same underline treatment, rendered by the shell beneath the breadcrumb so it does not re-mount between tabs.

  • The first tab is the landing, and the sidebar row leads to it. The row stays highlighted on every screen of the section, including child pages and detail pages.

  • The breadcrumb reads organisation › section › tab [› child page or detail]. A child page of the landing sits directly beneath the section crumb.

  • Commands that start a workflow are actions in the landing tab’s command row, and open child pages. They are not tabs and not sidebar rows.

  • Sections are declared in the navigation registry (SECTIONS in core/nav/scoped-screen.ts), so a second section needs data, not code.

Content Surface

Everything a screen shows sits on a white, 1px-bordered, 8px-radius surface inside a 16px gutter. A list has one surface; a dashboard or form may have several cards, each following the same treatment. Nothing sits directly on the page background except the command row.

What a Screen Must Not Do

  • Render its own title, eyebrow or entity name beneath the chrome.

  • Render a scope chip or an "Active filters" label for a filter the route already pins.

  • Show the record count anywhere but the pagination bar.

  • Use a filled-versus-outline button as the only signal of a toggle’s state.

  • Introduce a second tab idiom: in-page tabs use the same underline treatment as the instance tab strip.

  • Type an icon as a Unicode glyph. Icons are drawn with ap-icon; a glyph such as the circled-i has no rendering in several system fonts and shows as an empty box.