# Neutral product component system

## Approved decision

- ID: `neutral-product-components-2026-09-08`
- Scope: `project`
- Kind: `project_fact`
- Statement: Apply the approved Precision product hierarchy to Neutral's existing product through semantic tokens and component contracts, preserving existing product behaviour while normalising presentation, interaction and accessibility.
- Evidence: Manraj approved the product and data visualisation mock-up without major changes on 2026-09-08 and clarified that it must guide implementation in Michael's existing product.
- Provenance: `user-stated`
- Confidence: `high`
- Status: `approved`
- Created at: `2026-09-08`
- Reviewed at: `2026-09-08`
- Expires at: none

## Translation principle

**Map before replacing.**

The existing Neutral product owns feature behaviour, data contracts, routing, permissions, query semantics and operational terminology. The design system owns visual roles, spacing, typography, geometry, interaction feedback and accessibility.

An implementation agent must audit the product and map existing primitives to Neutral roles before restyling. Do not rebuild a working graph, table, range selector or inspector merely because its internal API differs from the reference classes.

## Fixed and adaptive rules

### Fixed

- Approved colours and mode mappings.
- Instrument Sans and Commit Mono roles and weights.
- Four-pixel spacing foundation.
- `0 / 2 / 4 / 8` role-based corner system.
- One-pixel structural rules, no decorative shadows and no gradients.
- Cobalt for selected and approved actions; semantic colours only for data state.
- Neutral icon source, sizing, rollover and motion rules.
- Visible focus, reduced motion and minimum target sizes.
- Data visualisation and inspection behaviour in [`data-visualisation.md`](data-visualisation.md).

### Adaptive

- Number of metrics in a row.
- Which supported time ranges a feature exposes.
- Sidebar depth and labels.
- Whether secondary detail is an inline pane, inspector or dialog.
- Table pagination, virtualization and column visibility.
- Framework, charting library and component implementation strategy.

Adaptive decisions must continue to use the fixed tokens and component anatomy.

## Product shell

### App shell

- Wide default: `240px` navigation, flexible main pane and optional `320px` inspector.
- The shell may be full-window. Structural panes have square corners.
- Pane boundaries use `1px` rules and must not produce doubled seams.
- Hide or overlay the inspector before collapsing primary navigation.
- On narrow layouts, show one pane at a time and preserve DOM reading order.

### Sidebar

- Use the approved symbol-only logo in an already branded product shell.
- Navigation rows use the current density token and a `4px` control radius.
- The selected row uses stable icon geometry, a clear surface change and a `2px` Cobalt leading indicator.
- Counts and machine values use Commit Mono 600.
- Hover never moves, replaces or enlarges the icon.

### Top bar

- Keep environment, location and global controls here.
- Use breadcrumbs for hierarchy and a labelled live/stale indicator for data freshness.
- Do not place page-local filters in the global top bar.

## Page anatomy

1. Context or breadcrumb.
2. Page title and one concise purpose statement.
3. Page-level actions.
4. Summary metrics when they materially describe the page.
5. Primary operational content.
6. Secondary evidence, table or inspector.

Use shared leading rails. Keep the title and primary content aligned. On narrow layouts, actions follow the title and become full-width only when their labels would otherwise collide.

## Component contracts

### Button

- Standard height `36px`; compact `32px`; dense `28px` only for expert data tooling; touch `44px`.
- Radius `4px`.
- One primary action per action group uses Cobalt with Paper text.
- Secondary actions use a transparent or mapped surface with a `1px` divider.
- Icon-only buttons require an accessible label and at least a `32 × 32px` pointer target or `44 × 44px` touch target.
- Disabled controls retain their label and cannot depend on opacity alone to explain why they are unavailable.

### Range selector and segmented controls

- Use for a short set of mutually exclusive values.
- Preserve the feature's existing values and ordering unless the product owner changes them.
- Selected state uses Cobalt with Paper text. Unselected options remain quiet and fully legible.
- Do not use a select menu merely to save a small amount of horizontal space; at narrow widths, wrap or use a labelled disclosure when necessary.

### Panel

- Use a panel only for a coherent task, visualization, inspector or bounded control region.
- Structural radius `0`; border `1px`.
- Header anatomy: title, optional one-line context, then local controls.
- Adjacent panels collapse shared borders.
- Do not turn every paragraph or metric into a card.

### Stat

- Use two to four peer metrics when they explain the operational state.
- Label: Instrument Sans 600. Value: Commit Mono with tabular numerals.
- Supporting comparison names its period or baseline.
- Semantic colour may mark a meaningful outcome; it never decorates a neutral number.
- Use `0h`, not `—`, when zero is an observed value. Use `—` only when the value is unavailable or not applicable, with an accessible explanation.

### Status

- Pair a label with a small semantic or Cobalt marker.
- Do not fill a large surface with a semantic colour.
- Healthy, warning and failure retain fixed semantic meanings.
- Active process states may use Cobalt and approved icon motion. Static states remain still.

### Timeline and process state

- One vertical rail connects causally linked events.
- Completed steps use Success, the active step uses Cobalt and future steps remain neutral.
- Every step shows a readable label. Timestamp and evidence detail use technical typography.
- State changes use the phase-aware icon handoff; never stop or reverse a loop abruptly.

### Data table

- Right-align quantitative columns and use tabular numerals.
- Header labels use sentence case.
- Default row height `44px`; compact `36px`; dense `32px` for logs and expert surfaces.
- Use horizontal dividers without decorative vertical gridlines unless column separation is essential.
- Preserve sorting, filtering, pagination, virtualization and row actions during migration.
- Narrow layouts remove nonessential visible columns and disclose them in row detail; they do not shrink important text.

### Progress and budget

- Use a `3–4px` track for compact SLA or capacity context.
- The filled amount uses Cobalt unless the value itself carries Warning or Error meaning.
- Do not add a border, gradient or rounded decoration to the track.
- Always expose the current value and bounds to assistive technology.

### Tooltip and popover

- Tooltip: concise supplementary content only.
- Popover: detached interactive content with an `8px` radius and explicit border.
- Never hide essential actions or status meaning behind hover.
- Data inspection tooltips follow [`data-visualisation.md`](data-visualisation.md).

### Form controls

- Label every field visibly.
- Use `4px` radii and the active density height.
- Error text uses Error and explains the correction in words.
- Keep the user's value when validation fails.
- Use native semantics before custom interaction code.

### Empty, loading and error states

- Empty states explain what is absent and offer one relevant next action when available.
- Skeletons mirror real component geometry and appear only before first useful content.
- Background refresh preserves valid content.
- Errors remain inside the affected scope and do not erase unaffected evidence.

## Complete baseline catalogue

The system must cover every baseline product pattern below. [`component-catalogue.json`](component-catalogue.json) is the machine-readable index and contains copy-ready reference markup for each one. [`tokens/components.css`](tokens/components.css) is the matching reference implementation.

| Pattern | Canonical reference | Primary rule |
| --- | --- | --- |
| Button | `.neutral-button` | One primary action per action group |
| Link | `.neutral-link` | Navigation uses links; mutation uses buttons |
| Input | `.neutral-field` | Keep the label visible and preserve invalid values |
| Checkbox, radio and switch | `.neutral-control-set` | Use native controls and explicit labels |
| Badge | `.neutral-badge` | State is written as text, never colour alone |
| Pill | `.neutral-pill` | Reserve capsules for compact filters and selections |
| Card | `.neutral-card` | One coherent object; do not card every region |
| Table | `.neutral-data-table` | Preserve semantics, behaviour and numeric alignment |
| Note | `.neutral-note` | Keep scoped qualification beside affected content |
| Dialog | `.neutral-dialog` | Use only for focused blocking decisions |
| Toast | `.neutral-toast` | Confirm a completed non-blocking action |
| Empty state | `.neutral-empty` | Explain what is absent and offer one next action |
| App shell and navigation | `.neutral-app-shell` | Persistent product structure, never marketing pages |
| Page header and toolbar | `.neutral-page-header` | Context, page title and page-level actions |
| Stat | `.neutral-stat` | Two to four peer operational metrics |
| Description list | `.neutral-description-list` | Attributes of one record, not multiple records |
| Skeleton | `.neutral-skeleton` | First useful load only; preserve valid content on refresh |
| Density and sizes | `[data-density]` | Use named modes rather than ad hoc shrinking |
| Tabs | `.neutral-tabs` | Two to six sections of one record or workspace |
| Menu and tooltip | `.neutral-menu` | Secondary actions and concise supplementary labels |
| Pagination and forms | `.neutral-pagination`, `.neutral-form-grid` | Page long tables and preserve logical source order |

## Existing-product migration

Before editing, produce an inventory with these columns:

| Existing primitive | Locations | Current behaviour | Neutral target | Token mapping | Risk | Migration layer |
| --- | --- | --- | --- | --- | --- | --- |
| Example: chart range tabs | List actual files | Query, URL and cache behaviour | Range selector | Action, control radius, range motion | Medium | Shared chart adapter |

Then migrate in layers:

1. **Capture:** record light/dark screenshots and interaction behaviour for representative routes.
2. **Foundations:** install fonts and semantic tokens without changing component behaviour.
3. **Shared primitives:** map existing buttons, fields, panels, status and focus states.
4. **Data primitives:** map chart axes, series, thresholds, range controls and inspection.
5. **Compositions:** migrate page headers, metrics, tables, timelines and inspectors route by route.
6. **Exceptions:** document justified local additions using a `neutral-` name and existing scales.
7. **Verification:** compare behaviour, keyboard access, responsive layout, themes and reduced motion.

Do not combine a visual migration with data-query, state-management or routing rewrites unless separately requested. Small, reviewable layers are the default.

## Implementation contract

- Reference component CSS: [`tokens/components.css`](tokens/components.css)
- Canonical machine-readable tokens: [`tokens/tokens.json`](tokens/tokens.json)
- Installation and migration instructions: [`agent.md`](agent.md)

The CSS classes are a reference implementation. React, Vue, native or utility-class adapters may expose different APIs, but their computed result and interaction contract must match.
