Every component on one page, one section each: what it is for, its variations and states, its sizes.
Every component the screens of Valere CRM are drawn with: the standard set, the product’s own — the record, the AI layer and the decisions on it — and a reserve. Each says what it is for, its variants, states, sizes and properties, and where it comes from: a component of the pilot (web/shared/components), a slide of the design concept, or proposed.
Button
Variants and sizes; hover, focus, disabled and loading; with an icon.
Source:web/shared/components/Button
A button starts an action: create, save, move a Site on, remove. The rule that matters: one primary button to a view, and everything else is secondary or ghost; an action that removes something is red and says what it removes.
Stretches to the width of its container; a sign-in form’s button.
disabled
boolean
false
Not available. A grey fill and a not-allowed cursor; it is also off the tab order.
disabledReason
string
—
Shown under the button while it is disabled and tied to it with aria-describedby, so a screen reader hears why.
reasonAlign
start | end
start
The edge the button and its reason line up on; end for a button at the right edge of a header.
type
button | submit
button
A button inside a form that submits it says so; every other button is button.
children
ReactNode
—
The label, in sentence case; an icon goes before it.
Text field
Label, hint and error; disabled and read-only; password; the text area.
Source:web/shared/components/TextField
A text field takes one line of free text, or several in the text area. The rule that matters: the label is visible text above the field, never only a placeholder, and the hint and the error sit under the field and are tied to it, so a screen reader reads them with it.
A name, an email, a figure: one line of free text.
Password type="password"
As text; a Show / Hide button in --color-primary sits inside the field’s right edge
Sign-in and a new password; Show reveals the text and says what it did to a screen reader.
Text area c-input--area
As text, 88 px at least, resizable up and down
A note, a reason, a meeting summary.
With a prefix c-input--prefixed
As text; the symbol in --color-muted inside the left edge
Money in £: a fee, a land value.
States
Default
Hover
Focus
Filled
Enter a Site Code like CE-014.
Error
Disabled
Read only
An error is the red border and a line under the field with an icon and the words: what is wrong and what to do. It is never the colour alone. A disabled field leaves the tab order; a read-only one stays in it, so its value can be selected and copied. A field another function owns is a read-only field with its owner named: see Locked field.
Sizes
Default, 36 px
Compact, 32 px
proposedThe compact size is proposed, for a field in a toolbar next to a small button. The pilot’s field is 36 px, the height of a button.
Properties
Name
Type
Default
What it does
label
string
—
The visible label, in sentence case, tied to the field with for.
hint
string
—
A line of help under the field, such as “Today when left empty”.
error
string | boolean
—
A string shows under the field with a warning icon; true only marks the field, for a form-level alert that already says what is wrong.
readOnlyHint
string
—
On a read-only field: names the function that owns it, with a lock (see Locked field).
type
string
text
text, email or password; a password gets the Show / Hide button.
readOnly
boolean
false
Grey fill; the value can be selected and copied but not changed.
disabled
boolean
false
Not available; out of the tab order.
value, onChange, placeholder, id
input props
—
Passed on to the input. A field without an id gets one, so label, hint and error always join it.
Select
The own combobox (ADR-0040): a labelled field and a compact filter, the list that opens, the keyboard.
Source:web/shared/components/Dropdown, Selectand the crm app’sLabelledSelect (ADR-0040)
A select chooses one value from a list. The product draws it itself (ADR-0040): a field-looking button and a panel on the tokens, never the browser’s or the system’s list, which ignores the theme. The rule that matters: it works from the keyboard as a native select does, and the list opens above the field when there is no room below.
Variants
Fee Discussion
Site Review
Instruction Approval
Acceptable Offer
Under Offer
Legals
Exchanged
Completed
Dead
Land moves a Site on.
Region: All
Region: South & West
Region: Central
Region: London & East
Compact filter: no label, each option carries it
Variant
Look in tokens
Used for
Labelled field LabelledSelect
A field’s look: --color-emphasis border, --radius-control, 36 px; the label above; hint or error under. The list is --color-surface with --shadow-overlay and --radius-card.
Forms: Stage, Region, Site, Landowner.
Compact filter Select
The same control without a label: each option carries it (“Region: All”), so the chosen filter reads on its own. At least 160 px wide.
Filter bars over a table or a board; the label is also the accessible name.
The list that opens
Both are live: open them with the pointer or the keyboard. The first holds nine stages; the second holds fourteen registered providers, so it scrolls and type-ahead earns its place: try typing “ma”.
Fee Discussion
Site Review
Instruction Approval
Acceptable Offer
Under Offer
Legals
Exchanged
Completed
Dead
Tab to it, then use ↑ ↓ or type a letter.
Calder Valley Homes
Ashby Rural Housing
Northfield Partnership
Bramley Housing Trust
Harbourside Homes
Kestrel Living
Linden Park Housing
Marlow & District Homes
Oakridge Communities
Pennine Rural Homes
Quayside Partnership
Redwood Housing
Severn Vale Housing
Thornbury Homes
A long list scrolls inside the panel.
Region: All
Region: South & West
Region: Central
Region: London & East
Open, drawn
The same list held open. Groups have a quiet title and a divider; the highlighted option is in the brand’s soft tint; the chosen one is semibold with a check; an option that cannot be chosen is grey, says why, and is skipped by the arrows.
Pipeline
Fee Discussion
Site Review
Instruction Approval
Acceptable Offer
Under Offer
Legals
ExchangedAfter Legals
Closed
Completed
Dead
Open below the field
Site Review
Instruction Approval
Acceptable Offer
Open above, when there is no room below
Keyboard
Key
What it does
↑↓
Closed: opens the list. Open: moves the highlight one option; it stops at the ends and skips an option that cannot be chosen.
HomeEndPgUpPgDn
The first or last option; ten options up or down in a long list.
Letters
Type-ahead: the letters typed in a row find the option that starts with them; the same letter again steps to the next. Open, it moves the highlight; closed, it chooses.
EnterSpace
Closed: opens the list. Open: chooses the highlighted option and closes.
Esc
Closes the list and keeps the focus on the field. The value stays as it was.
Tab
Closes the list and moves on; nothing is chosen.
Pointer
A click opens and closes; the option under the pointer is highlighted; a click outside closes. The focus never leaves the field.
ARIA: the field is role="combobox" with aria-haspopup="listbox", aria-expanded and aria-controls; the highlighted option is named by aria-activedescendant, so the focus stays on the field; the panel is role="listbox", each option role="option" with aria-selected.
States
Fee Discussion
Site Review
Instruction Approval
Acceptable Offer
Under Offer
Legals
Exchanged
Completed
Dead
Default
Fee Discussion
Site Review
Instruction Approval
Acceptable Offer
Under Offer
Legals
Exchanged
Completed
Dead
Empty
Fee Discussion
Site Review
Instruction Approval
Acceptable Offer
Under Offer
Legals
Exchanged
Completed
Dead
Hover
Fee Discussion
Site Review
Instruction Approval
Acceptable Offer
Under Offer
Legals
Exchanged
Completed
Dead
Focus
Fee Discussion
Site Review
Instruction Approval
Acceptable Offer
Under Offer
Legals
Exchanged
Completed
Dead
Choose a stage to move the Site on.
Error
Fee Discussion
Site Review
Instruction Approval
Acceptable Offer
Under Offer
Legals
Exchanged
Completed
Dead
Disabled
Open is its own state, drawn above. A disabled select leaves the tab order; one that is read-only because another function owns the value is the locked select of Locked field.
Sizes
Region: All
Region: South & West
Region: Central
Region: London & East
Region: All
Region: South & West
Region: Central
Region: London & East
Size
Height
Used for
Default
--size-control
A field in a form; the options are 36 px as well.
Small c-select--sm
--size-control-sm
A filter beside small buttons in a toolbar.
proposedThe small size is proposed; the pilot’s select is 36 px.
Properties
Name
Type
Default
What it does
label
string
—
The control’s name, on the field and on its list. The visible label above the field reaches the button through for.
value
string
—
The chosen option’s value. The empty string is the placeholder or “All”.
options
{ value, label, typeahead? }[]
—
What the list holds; typeahead is what typing matches when it is not the label (the filter’s “Region: Central” is found by “c”).
onChange
(value) => void
—
Called when another option is chosen.
disabled
boolean
false
Not available; out of the tab order.
invalid
boolean
false
The red border and aria-invalid; the message sits under the field.
required
boolean
false
Sets aria-required; the label carries the asterisk.
className
string
—
The width of the field: a form’s full width, a filter’s minimum.
Checkbox, radio, switch
One or many of a list, one of a few, on or off.
Source:web/packages/crm/src/pages/NewLead.tsx, RecommendedBuyers.tsxandLandTermsCard.tsx(the pilot draws them with the browser’s own checkbox and radio; the look here is proposed)
Checkboxes choose any of a list, radios choose one of a few, a switch turns one thing on or off. The rule that matters: the whole label is the target, the group has a legend, and a switch always carries the word for its state, so it never depends on colour or position alone.
Variants
Land terms agreedOff
Set by Land. Heads of Terms needs it.
Variant
Look in tokens
Used for
Checkbox type="checkbox"
16 px box, --radius-sm, --color-emphasis border; ticked: --color-primary fill with a white tick; mixed: a dash instead of the tick
Zero, one or many of a list; a single yes: “Hide buyers already in the journey”.
Radio type="radio"
Round, 16 px; chosen: --color-primary fill with a dot
One of a few, all shown at once: Deal type, Landowner. More than about five go in a Select.
Switch role="switch"
44 × 24 px pill; off: --color-subtle, knob left; on: --color-primary, knob right; the word On or Off beside it
A setting that takes effect at once: Land terms agreed. A choice that needs a Save is a checkbox.
States
Checkbox
Unchecked
Hover
Focus
Checked
Mixed
Disabled
Disabled, checked
Tick to confirm before moving on.
Error
Radio
Unchecked
Hover
Focus
Checked
Disabled
Disabled, checked
Switch
Land terms agreedOff
Off
Land terms agreedOn
On
Land terms agreedOff
Hover
Land terms agreedOff
Focus
Land terms agreedOff
Disabled
Land terms agreedOn
Disabled, on
A disabled choice is grey and at half strength, and leaves the tab order. When it is disabled because another function owns it, name the owner beside it: see Locked field.
Sizes
Control
Size
Target
Checkbox and radio
16 × 16 px
The whole label line, at least 20 px high.
Switch
44 × 24 px
The switch itself; the label names it with aria-labelledby.
Properties
Name
Type
Default
What it does
label
string
—
The text beside the control; clicking it toggles the control.
hint
string
—
A line under the label that says more, in --color-subtle.
checked
boolean
false
The state of a checkbox or a radio. A radio group shares one name, and the arrow keys move within it.
indeterminate
boolean
false
A parent checkbox whose children are some on and some off; it is set from script and turns every child on or off.
disabled
boolean
false
Not available; out of the tab order.
aria-checked
boolean
false
On a switch (role="switch"): the state; the switch is a button, so Space and Enter toggle it.
aria-invalid
boolean
false
The red border; the message sits under the control and names what to do.
Date picker
A date and a range; the calendar and its keyboard; UK dates.
proposedThe pilot uses the browser’s date input, type="date" in TextField; this is the product’s own calendar, on the model of its lists (ADR-0040).
A date picker takes a day, or a start and an end. Dates are UK ones: dd/mm/yyyy, weeks from Monday. The rule that matters: the field can always be typed in, the calendar is only the other way in, and the month and year are lists drawn by the product, with the keyboard of a Select.
Variants
January
February
March
April
May
June
July
August
September
October
November
December
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
Now choose the end date.
Mo
Tu
We
Th
Fr
Sa
Su
Today when left empty.
Enter a date as dd/mm/yyyy, for example 09/11/2026.
Choose a date from 01/01/2026 to today.
Exchange window
–
January
February
March
April
May
June
July
August
September
October
November
December
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
Now choose the end date.
Mo
Tu
We
Th
Fr
Sa
Su
Church Farm, CE-014: from the exchange date to the longstop.
Enter a date as dd/mm/yyyy, for example 09/11/2026.
The end date is before the start date.
Variant
Look in tokens
Used for
Date mode="single"
A text field with a calendar button inside its right edge; the calendar is a --radius-card panel on --color-surface with --shadow-overlay; the day chosen is --color-primary, today has a ring
One day: Instructed on, a meeting date, a longstop.
Date range mode="range"
Two date boxes in one field frame; the days between are in --color-primary-soft, the ends in --color-primary
From and to: an exchange window, a reporting period.
The calendar, drawn
The calendar held open, as it looks. Left: a date, with today ringed and the days after today out of reach. Middle: a range being chosen, with its two ends and the days between. Right: the month list open, the same panel as a Select’s.
January
February
March
April
May
June
July
August
September
October
November
December
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
Now choose the end date.
Mo
Tu
We
Th
Fr
Sa
Su
A date, not in the future
January
February
March
April
May
June
July
August
September
October
November
December
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
Now choose the end date.
Mo
Tu
We
Th
Fr
Sa
Su
A range, both ends chosen
January
February
March
April
May
June
July
August
September
October
November
December
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
Now choose the end date.
Mo
Tu
We
Th
Fr
Sa
Su
The month list open
Keyboard
Key
What it does
←→
The day before or after; past the month’s edge, the calendar turns to the next month.
↑↓
The same weekday a week earlier or later.
HomeEnd
The Monday or the Sunday of the week.
PgUpPgDn
The previous or next month, on the same day; with Shift, the previous or next year.
EnterSpace
Chooses the day. A date closes the calendar; a range keeps it open for the second date.
Esc
Closes the calendar, or the month or year list if one is open, and puts the focus back.
Tab
Moves to Today and Clear; leaving the calendar closes it.
In the field: type 09/11/2026 (a full stop or a hyphen works too). The calendar follows when the field is left or Enter is pressed; text that is not a real date marks the field and says what to type. The month and year lists open from their buttons and keep a Select’s keys.
ARIA: the calendar button is aria-haspopup="dialog" with aria-expanded; the calendar is a role="dialog" holding a role="grid" of days, each a button named by its full date and aria-selected when chosen; today is aria-current="date"; month and year are the comboboxes of Select.
States
Today when left empty.
Enter a date as dd/mm/yyyy, for example 09/11/2026.
Choose a date from 01/01/2026 to today.
Default
Today when left empty.
Enter a date as dd/mm/yyyy, for example 09/11/2026.
Choose a date from 01/01/2026 to today.
Focus
Today when left empty.
Enter a date as dd/mm/yyyy, for example 09/11/2026.
Choose a date from 01/01/2026 to today.
Error
Today when left empty.
Enter a date as dd/mm/yyyy, for example 09/11/2026.
Choose a date from 01/01/2026 to today.
Disabled
Days in the calendar
12A day
12Hover
12Focus
9Today: a ring
5Chosen: filled
20Between the ends
30Another month
14Out of reach: struck through
Sizes
Part
Size
Used for
Field
--size-control
36 px high, 280 px wide for a date and 320 px for a range.
Calendar
276 px
Seven 36 px days across and six weeks down, so the panel never changes height from one month to the next.
Properties
Name
Type
Default
What it does
label
string
—
The visible label; for a range it names the group of two boxes.
mode
single | range
single
A day, or a start and an end. A range takes its first click as the start and its second as the end, swapping them if they come the wrong way round.
value
yyyy-mm-dd | [start, end]
—
The day, as the browser’s date input would hold it; it is shown as dd/mm/yyyy.
min, max
yyyy-mm-dd
—
The days out of reach: struck through and not choosable; typing one gives the range message. Instructed on stops at today.
onChange
(value) => void
—
Called with the new value, or empty when cleared.
hint, error
string
—
As the Text field: help under the field, and the message that names what to type.
disabled
boolean
false
Not available; both the boxes and the button leave the tab order.
Locked field
A field another function owns: read only, with the owner named.
Source:web/shared/components/TextField (readOnlyHint, LockedHint), role rules FR-25
A locked field shows a value that another function owns. The rule that matters: the field stays on the screen and says who owns it and who may not change it, in the same words everywhere (FR-25); it is never hidden, because a missing field only raises the question where it went.
Variants
Seen by Land
The Site this opportunity is on.
Seen by Construction
Land and Partnerships create opportunities. Read only for Construction.
Fee Discussion
Site Review
Instruction Approval
Acceptable Offer
Under Offer
Legals
Exchanged
Completed
Dead
Land moves this deal on. Read only for Construction.
Land terms agreedNot agreed yet
Set by Land. Read only for Construction.
Set by Back Office. Read only for Land.
Variant
Look in tokens
Used for
Locked text field readOnly + readOnlyHint
--color-surface-muted fill, --color-default border, --color-muted text; focusable and selectable; the hint under it has a lock icon in --color-muted
A value another function owns: Site Code, Fee basis, Land value.
Locked select aria-readonly
The field look above, with no chevron; it does not open
The Stage, for a role that cannot move it.
Locked switch disabled
The switch at half strength with its state in words; the hint beside it
Land terms agreed, for Construction.
The hint alone LockedHint
A lock icon and a line in --text-xs and --color-muted, under or beside the control
Next to a button, a tab or a switch that the role cannot use.
The words
Every locked thing names its owner the same way: who sets it, then who may only read it.
Pattern
Example
Used for
Set by {owner}. Read only for {role}.
Set by Partnerships. Read only for Construction.
A field the user does not own.
{Owner} moves this deal on. Read only for {role}.
Land moves this deal on. Read only for Construction.
The stage move, and the buttons that make it.
{Owner} and {owner} create {things}. Read only for {role}.
Land and Partnerships create opportunities. Read only for Construction.
A form the user may open but not submit.
Read only.
Read only.
When no role is known; for example before the session has loaded.
In a form
Locked fields sit among editable ones at full width, so the form keeps its shape; only the fill, the border and the hint set them apart.
Seen by Land
Edit Site
Set by Back Office. Read only for Land.
States
Set by Partnerships. Read only for Construction.
Locked
Set by Partnerships. Read only for Construction.
Focus
Set by Partnerships. Read only for Construction.
Locked, no value yet
You set this one.
For its owner: editable
A locked field has no hover change: it does not invite a click. It keeps the focus ring, so a keyboard user can reach it and a screen reader reads its value and its hint. An empty one says so in the field.
Sizes
Default, 36 px
Compact, 32 px
The sizes are the Text field’s: a locked field is the same control with another state.
Properties
Name
Type
Default
What it does
readOnly
boolean
false
Makes the field read only: grey fill, value selectable, aria-readonly.
readOnlyHint
string
—
The owner’s sentence, shown under the read-only field with a lock and joined to it by aria-describedby.
LockedHint → children
string
—
The same line on its own, for a control that is not a field: a stage move, a switch, a tab’s buttons.
LockedHint → id
string
—
What the control points at with aria-describedby.
role
Role
—
The viewer’s role: the line ends “Read only for” and the role’s name, or is just “Read only.” when none is known.
Badge and status
Neutral badges and the status tones with their icons.
A badge is a small pill that names a state or a category. A status badge pairs its tone with an icon and a word, so a status is never read from colour alone: an icon and a label always stand beside the colour.
Variants
Land & BuildNeutral tag
S106Neutral tag
12Count
Fee DiscussionStage chip
Under OfferStage chip
Acceptable OfferStage chip
LegalsStage chip
CompletedCompleted
DeadDead
On trackStatus pill, good
At riskStatus pill, warning
Stalled: no contact 21 daysStatus pill, critical
AwaitingInfo pill
ActiveActive status
72Deal HealthHealth chip, good (70 and above)
55Deal HealthHealth chip, fair (40–69)
34Deal HealthHealth chip, poor (below 40)
Variant
Look in tokens
Used for
Neutral tag
--color-surface, --color-default border, --color-muted text
A plain label: a deal type, a count, a category.
Stage chip
--color-stage-tint on --color-stage-text, a dot before the word
The stage a Site is in. In a table cell the border and the dot go.
Stage, completed and dead
--color-stage-done-* and --color-stage-dead-*
A Site that closed: Completed in green, Dead in grey.
Status pill
--color-success-soft, --color-warning-soft, --color-danger-soft with their text colours, and an icon
On track, At risk, Stalled; the stalled pill names the rule that fired.
Info pill
--color-info-soft on --color-info-text
A state that is neither good nor bad: Awaiting, Not started.
Health chip
--color-health-good-*, --color-health-fair-*, --color-health-poor-*, the band’s icon and the score
The Deal Health score at a glance; as a button it opens the breakdown.
States
Default
Hover
Focus
—No score: the deal is closedNo score
A badge on its own is not interactive and has no hover. Only the health chip is a button; it takes the hover tint and the focus ring.
Sizes
LegalsDefault, 24 px
12Small, 20 px: counts in tabs
Properties
Name
Type
Default
What it does
tone
'neutral' | 'good' | 'warn' | 'crit' | 'info'
'neutral'
The status tone; every tone but neutral shows its icon.
kind
'tag' | 'stage' | 'dealType' | 'function'
'tag'
A record’s state is a pill with a dot; a function is a tinted label.
icon
string
the tone’s icon
Replaces the icon of a status pill.
children
ReactNode
—
The word. A stalled pill carries the rule: “Stalled: no contact 21 days”.
score
number (0–100)
—
Health chip: the number, whose band picks the tone and the icon.
onClick
() => void
—
Makes the chip a button, with expanded and controls for the popover it opens.
Avatar
Initials in the function’s tint, sizes, a stack of them.
Source:web/shared/components/Sidebar, Chip(function colours); the stack: design concept, app shell top bar
An avatar is a person’s initials in a circle, in the tint of the function they work in, so one function has one colour everywhere. The rule: initials and function colour only, and the name sits beside it or in a tooltip, because the colour alone does not say who.
The function whose tint the avatar takes; none gives the neutral one.
size
'sm' | 'md' | 'lg' | 'xl'
'md'
Diameter: 24, 32, 40 or 48 px.
max
number
4
Stack: how many avatars show before the “+n” count.
onClick
() => void
—
Makes it a button, as the avatar of the account menu.
Card
Title only, with actions, with an edge-to-edge table.
Source:web/shared/components/Card
A card is a white panel with a hairline border, a 12 px radius and a shadow that holds one subject. The rule: a title bar of 56 px with the title at the left and the actions at the right, a body of 20 px padding, and a table runs edge to edge with no padding of its own.
Variants
Church Farm, Rugby
Site Code
CE-014
Units
28
Deal type
Land & Build
Title only
Actions
Chase the draft contractHadley & Finch LLP · due Tue 10 Nov
Confirm the exchange date with Calder Valley HomesDue Fri 13 Nov
A fact sheet: the Site’s details, a position, a fee stream.
With actions
the same, buttons btn--sm in the bar
A list the user adds to: actions, activity, key contacts.
Edge-to-edge table
body padding: 0, the table’s head on --color-surface-muted
A short table that belongs to a card: My deals on the dashboard.
States
Actions
Loading…
Loading: skeleton lines, aria-busy
Actions
No open actions for your function.
Empty: one quiet sentence
Actions
Actions couldn’t be loaded. Refresh the page to try again.
Error: what failed and what to do
A card is not interactive; a card that opens a record is a link inside it, not the card itself. The default state is the variants above.
Sizes
Church Farm, Rugby
Site Code
CE-014
Units
28
Deal type
Land & Build
Standard: 56 px bar, 20 px body
Key dates
Site Code
SW-031
Units
33
Deal type
S106
Compact: 48 px bar, 16 px body
Properties
Name
Type
Default
What it does
title
string
—
The card’s title, in the bar; it names the card for a screen reader.
actions
ReactNode
—
Buttons at the right of the bar.
children
ReactNode
—
The body.
flush
boolean
false
Takes the body’s padding away, for a table.
size
'md' | 'sm'
'md'
Standard or compact.
isLoading
boolean
false
Shows the skeleton lines and sets aria-busy.
Stat tile
A figure, its delta against the previous period, a sub-caption; loading.
Source:web/packages/crm/src/pages/overview-parts (Tile); the delta pill: design concept, KPI tiles
A stat tile gives one figure its name, its movement and its comparison. The rule: the arrow shows the direction and the colour shows whether that is good, so a fall in days to exchange is green and a fall in Deal Health is red; the figure and the pill always carry their numbers.
The list table is how the product shows many records of one kind: the Sites, the Leads, the Accounts. The rule: it always says which of its four states it is in (loading, error, empty or filled), the record’s name is the link, and every status in a row is a chip with its icon or word.
Variants
Variant
Look in tokens
Used for
List table
head --color-surface-muted, 13 px --color-subtle; rows split by --color-default
A page of records with a pager under it, in a bordered, scrolling frame.
Sortable head
the head’s word is a button with an arrow, aria-sort
A column the user may order: Site Code, Fee.
Row on hover
--color-surface-muted behind the cells
Shows which record the pointer is on.
In a card
no frame of its own, edge to edge
A short table inside a card (see Card).
States
Sites
Site
Stage
Deal Health
Owner
Fee
Loading Sites…
Loading: skeleton rows, aria-busy on the table
Sites
Site
Stage
Deal Health
Owner
Fee
Sites couldn’t be loaded. Refresh the page to try again.
Filled: Sites from the sample; row 2 on hover, the pager line under the rows
Sizes
Sites
Site
Stage
Fee
Heron Fields
Under Offer
£310,000
Hatch Farm
Fee Discussion
£145,000
Default: 8 × 16 px cells
Sites
Site
Stage
Fee
Heron Fields
Under Offer
£310,000
Hatch Farm
Fee Discussion
£145,000
Compact: 6 × 12 px cells, for a card
Properties
Name
Type
Default
What it does
caption
string
—
The table’s name for a screen reader, drawn hidden.
columns
Column[]
—
Heading, alignment (numbers right) and the cell for each column.
rows
T[]
[]
The records of the page.
state
'loading' | 'error' | 'empty' | 'ready'
'ready'
Which of the four the body shows.
sort
{ column, direction }
—
The ordered column; its head carries aria-sort.
emptyMessage
string
—
Says whether a filter or nothing at all caused the empty state.
onRetry
() => void
—
The error state’s button.
footer
ReactNode
—
The pager under the rows.
Pagination
First, middle and last page.
Source:web/shared/components/Pager; the numbered pages:proposed
Pagination sits at the foot of a paged table and says where the user is in it. The rule: it always shows the range and the total in words, past page 1 the buttons stay so a page number that went stale can still be left, and when everything fits on one page there are no buttons at all.
Variants
First page: Previous is off
Middle page
Last page: Next is off
With numbered pages: first, middle, last
Variant
Look in tokens
Used for
Previous and Next
btn--secondary, range in --color-subtle
The pager of every Overview: the range, then two buttons.
Numbered pages
current page --color-primary-soft on --color-primary-strong, aria-current
A long list where the user jumps: Accounts, the activity log.
States
Loading: the range is blank and both buttons are off
Everything on one page: the range, no buttons
Nothing to show
Sizes
Standard: 56 px high, for a page-wide table
Compact: 48 px, inside a card
Properties
Name
Type
Default
What it does
page
number
1
The page on show, counted from 1.
pageSize
number
25
Rows to a page.
total
number
—
Every row there is, for the range and for the last page.
noun
string
—
What is counted, in the plural: “Sites”.
isLoading
boolean
false
Blanks the range and turns the buttons off.
onPage
(page: number) => void
—
Asks the caller for another page; the page number lives in the URL.
Progress and meter
How far along; how full.
Source:design concept (the fee stream and the checklist); the bands ofweb/shared/components/HealthChipproposed
A progress bar shows how far a task has got and only grows; a meter shows a level against a range and may change band. The rule: both say their number in words beside the bar, and a band or a failure is named with an icon or a word, never left to the colour.
Variants
Instruction Approval checklist3 of 5
Progress bar, with its label and number
78%
Site Review, 78% complete
Progress ring
Deal Health72Good
04070100
Deal Health55Fair
04070100
Deal Health34Poor
04070100
Meter: Deal Health against its three bands
Fee stream, Church Farm£262,000
Collected£65,500
Invoiced, not yet collected£65,500
Not yet invoiced£131,000
Stacked meter: a fee stream, collected within invoiced within the fee
Variant
Look in tokens
Used for
Progress bar
fill --color-chart-actual on --color-chart-track
A checklist, an upload, a step count: how far along.
Progress ring
the same colours, drawn as a ring with the figure inside
A completion share where there is no room for a bar.
Meter with bands
--color-health-poor-tint, --color-health-fair-tint, --color-health-good-tint behind a marker
A level with meaning in its range: Deal Health 40 and 70.
Stacked meter
--color-chart-actual, --color-chart-forecast, the track, each named in a legend
Parts of one whole: a fee collected, invoiced, still to invoice.
States
Uploading CSA draft62%
In progress
Uploading CSA draftDone
Complete: the check beside the number
Uploading CSA draftFailed at 62%
Error: danger tone and the word
Reading the email…
Not known yet: indeterminate, aria-busy
Sizes
Key dates40%
Small, 4 px: inside a card or a row
Key dates40%
Default, 8 px
Key dates40%
Large, 12 px: a hero figure
40%
40%
40%
Rings: 32, 56 and 80 px
Properties
Name
Type
Default
What it does
value
number | null
—
Progress: how far along, 0 to max; null is indeterminate.
max
number
100
The end of the range.
label
string
—
The name, drawn above the bar and used as its accessible name.
valueText
string
n %
The number in words: “3 of 5”, “Failed at 62%”.
tone
'default' | 'good' | 'bad'
'default'
Complete or failed; the word beside it says so too.
size
'sm' | 'md' | 'lg'
'md'
Bar height 4, 8 or 12 px; a ring is 32, 56 or 80 px.
bands
{ poor, good }
{ 40, 70 }
Meter: where the bands change; Deal Health uses 40 and 70.
A tooltip is a hint that appears on hover and on keyboard focus; a popover is a small panel the user opens with a click to read more. The rule: a tooltip never holds the only way to learn something or anything to click, and a popover keeps focus, closes on Escape, hands focus back to its trigger and may hold more than a line.
Variants
Download the signed CSATooltip on an icon button: hover or focus it
Land and Partnerships create opportunities. Read only for Construction.Tooltip on a locked button: the reason it is locked
Deal Health 72(100 less each component; 70 and above)
Recent contact9 days since the last contact; points off from 7 days−10
Overdue actions2 open actions past due−8
Stage duration34 days in this stage; limit 28 days−10
Next action1 open action0
Legals0 critical tasks past deadline (counted in the Legals stage)0
Popover from the health chip: the breakdown
Heads of Terms (HoTs)
The commercial terms agreed with the buyer before the solicitors draft the contract.
Popover from an info button
Variant
Look in tokens
Used for
Tooltip
--color-surface-inverted with --color-inverted text, 12 px, --radius-control
A name for an icon button; the reason a control is locked.
More than a line: the Deal Health breakdown, a short definition.
Open, drawn statically
Download the signed CSATooltip, open
Deal Health 72(100 less each component; 70 and above)
Recent contact9 days since the last contact; points off from 7 days−10
Overdue actions2 open actions past due−8
Stage duration34 days in this stage; limit 28 days−10
Next action1 open action0
Legals0 critical tasks past deadline (counted in the Legals stage)0
Popover, open: the Deal Health breakdown of Heron Fields
States
Tooltip: hidden by default; shown on hover and on focus after a short pause; Escape hides it while the pointer or focus stays. It stays while the pointer moves onto it. Popover: closed by default; open on a click or Enter or Space on its trigger, which carries aria-expanded; Escape, a click outside or focus leaving closes it.
Trigger, default
Trigger, hover
Trigger, focus
Locked control: aria-disabled, still focusable, so the reason can be read
Sizes
Part
Width
Used for
Tooltip, one line
fits its text
A name: “Download the signed CSA”.
Tooltip, wrapped
240 px at most
A reason, in a sentence or two.
Popover, small
240 px
A definition.
Popover, large
384 px
The Deal Health breakdown and other tables of lines.
Properties
Name
Type
Default
What it does
content
string
—
Tooltip: the hint, in a sentence at most.
placement
'top' | 'bottom' | 'left' | 'right'
'top'
Where it opens; a popover opens below, or above when there is no room.
trigger
ComponentType
—
Popover: the button, which gets onClick, expanded and controls.
label
string
—
Popover: the panel’s accessible name.
children
ReactNode
—
Popover: the panel’s content.
width
number
320
Popover: the panel’s width in px.
Tabs
Segmented: the white pill on a grey bar, with counts.
Source:web/shared/components/TabBar
Tabs switch between the views of one record or one list. They sit on a grey bar, the open one raised as a white pill, and every tab keeps the same medium weight, so choosing one never moves the others.
Variants
Fill, with counts: the Site page. Click a tab to open it; Risk & Actions carries its count in the alert tone.
Fit: filters of one list, as buttons
Fit, with counts
Variant
Look in tokens
Used for
Fill
The bar spans its row and spreads its tabs when they fit; narrower, they pack from the start and wrap
The sections of a record: the Site page
Fit
The bar is as wide as its tabs: --color-surface-muted track, --radius-card, 4 px padding; the open tab --color-surface with --shadow-card
Filters of one list: the Activity filter, the actions by status
With count
A pill after the label: --color-surface on the bar, --color-surface-muted on the open tab; the alert tone --color-danger-soft and --color-danger-text
How many there are: Buyers 14, Contractors 5; what needs a look: Risk & Actions 3
Links or buttons
The same look. Links go to another page and carry aria-current="page"; buttons filter the page and are grouped
Links for the Site page; buttons for filters
States
Idle
Hover
Focus
Open
Disabled
With count
Sizes
One size: a 32 px tab (--size-control-sm) with the label in 14 px medium, 12 px side padding, 4 px between tabs. When the row is too narrow the tabs wrap onto a second row.
The same bar in 360 px
Properties
Name
Type
Default
What it does
label
string
—
What a screen reader calls the bar
as
'nav' | 'group'
'nav'
nav when the tabs go to other pages, group when they are filter buttons on one page
fill
boolean
false
Spans the row and spreads the tabs, instead of sizing to them
tab.label
string
—
The tab’s text, in sentence case
tab.count
number
none
A pill after the label; leave it out for a tab with nothing to count
tab.alert
boolean
false
Draws the count in the alert tone, for what needs a look
tab.current
boolean
false
The open tab: the white pill, with aria-current
tab.disabled
boolean
false
Greyed out and out of the tab order
Breadcrumbs
Where the user is; a long path that folds.
Source:web/packages/crm/src/pages/OpportunityDetail (Breadcrumb); proposedthe fold and the truncation
Breadcrumbs say where the user is and the way back up. The last crumb is the page itself: plain text, not a link, marked aria-current="page"; every crumb before it is a link one level higher.
Variants
Default: the Site page
A deeper path: one buyer’s position on the Site
Folded: the pages in between sit behind the three dots; click them to unfold
In a narrow place the last crumb is cut short with an ellipsis; its full name is the tooltip
Variant
Look in tokens
Used for
Default
Links in --color-subtle, the current page in --color-foreground medium, a › in --color-subtle between them; 14 px, 8 px apart
The top bar of every record page
Folded
From five crumbs up the middle ones are replaced by a button with three dots, in the link’s look, that unfolds them in place and moves the focus to the first
A path deeper than four levels
Truncated
The current crumb is the only one that shrinks: one line, an ellipsis at the end, the full name in its title
One size: 14 px on a 20 px line, with 8 px between a crumb and its separator. The row never wraps; it folds, then it truncates.
Properties
Name
Type
Default
What it does
items
{ label, href }[]
—
The path from the top; the last item has no href and is the current page
label
string
'Breadcrumb'
What a screen reader calls the navigation
foldAfter
number
4
A path with more crumbs than this folds its middle ones behind the button
Dropdown menu
Actions on a thing; a destructive one set apart.
Source:web/packages/crm/src/components/HeaderMenu (the popover); proposedthe keyboard menu, the groups and the destructive item
A dropdown menu lists the actions on one thing; to choose a value for a field use a Select. The destructive action comes last, set apart by a divider and written in the danger tone with its own icon, so it is never told by colour alone, and it asks for confirmation before it acts.
Variants
Site
Stage
Live: open it with a click or the arrow keys
Icon button, opening to the left: the menu of a table row
Last chosen:—
Site
Stage
Open, drawn: the highlighted item, a disabled one, the destructive one set apart
The secondary button with a chevron that turns over when the menu is open
Actions on the page’s record: Site actions
Icon button
The secondary button with three dots and a name for screen readers; the panel opens to its left
A row of a table: the buyer, the contractor
Group heading and divider
A 12 px heading in --color-subtle; a 1 px --color-default line
Telling Site actions from stage moves
Destructive item
--color-danger-text with its icon; highlighted in --color-danger-soft; always after a divider
Mark as Dead, Remove buyer
Opening above
With no room below the button the panel opens above it, on the same offset
A button near the foot of the window
States
Default
Hover or arrow key
Keyboard focus
Disabled
Destructive, highlighted
Keyboard
Keys
What happens
↓EnterSpace
On the button: open the menu and focus the first item
↑
On the button: open the menu and focus the last item
↑↓
Move between items, round from the last to the first
HomeEnd
The first or the last item
A–Z
Type-ahead: the next item whose label starts with what was typed
EnterSpace
Choose the item, close the menu, focus back on the button
EscTab
Close; Esc puts the focus back on the button, Tab carries it on
Sizes
Items are 36 px high (--size-control); the panel is at least 220 px wide, 4 px below its button, and scrolls from 360 px high, so a long list never leaves the window.
Properties
Name
Type
Default
What it does
trigger
'text' | 'icon'
'text'
A button with a label, or an icon button that must carry aria-label
align
'start' | 'end'
'start'
Which edge of the button the panel lines up with
items
(action | separator | heading)[]
—
What the panel holds, in order
item.label
string
—
The action, as a verb and what it acts on
item.icon
IconName
—
The icon before the label
item.danger
boolean
false
Draws the item as destructive; the action then opens a confirm dialog
item.disabled
boolean
false
Dimmed and inert, but still reached by the arrow keys so its label can be read
item.onSelect
() => void
—
Runs when the item is chosen; the menu closes and the focus returns to the button
Stepper
Steps done, current and to come.
proposed
A stepper shows where the user is in a sequence that has a fixed order: what is done, the step in hand and what is still to come. Each step says so in words and in its marker, a tick, a number in a ring or a plain number, so the state is never told by colour alone.
Variants
Site detailsDoneCurrentTo come
2
Fee streamDoneCurrentTo come
3
TeamDoneCurrentTo come
4
ReviewDoneCurrentTo come
Horizontal: add a Site. Step through it with the buttons.
Site detailsName, Site Code, region and unitsDoneCurrentTo come
2
Fee streamBasis and trigger of the feeDoneCurrentTo come
3
TeamWho owns the Site in each functionDoneCurrentTo come
4
ReviewCheck it and create the SiteDoneCurrentTo come
Vertical, with a line under each title: for a side panel
Step 2 of 4Fee stream
Compact: for a narrow place, the count and the step in hand
Variant
Look in tokens
Used for
Horizontal
A marker and a line per step, the title and its status under it; the line is --color-emphasis, --color-primary once the step is done
A form in several steps, across the page
Vertical
The same, down the side, with a description under each title in --color-muted
A side panel, a drawer
Compact
“Step 2 of 4” in 14 px semibold, the step’s title in --color-muted and a track of four segments in --color-primary and --color-chart-track
A narrow window
States
Fee streamDoneCurrentTo come
Done: a tick in a --color-primary disc
2
Fee streamDoneCurrentTo come
Current: the number in a ring, the title in medium weight
3
Fee streamDoneCurrentTo come
To come: a plain number on --color-emphasis
Sizes
One size: a 28 px marker with a 2 px line. The titles are 14 px, the status 12 px. Four to six steps fit a page; more should be a list.
Properties
Name
Type
Default
What it does
steps
{ title, description? }[]
—
The steps in order; the description shows in the vertical stepper
current
number
0
The index of the step in hand: those before it are done, those after it are to come
orientation
'horizontal' | 'vertical' | 'compact'
'horizontal'
How the steps are laid out
label
string
—
What a screen reader calls the list; the current step carries aria-current="step"
App shell
The grouped sidebar, the top bar and the page, as components.
The shell is what every signed-in screen sits in: the sidebar that groups the product’s pages, the top bar that says where you are and what you can do about it, and the page. The page on show is the one item in the grey --color-nav-active; the sidebar folds to a rail of icons and remembers the choice.
Sidebar
Expanded, 240 px: the logo tile and name with the fold button; search with its shortcut; the signed-in user; the groups; Settings at the foot
Folded, 64 px: icons only, a rule in place of each group name, the name of an item in a tooltip on hover and on focus. The fold buttons work here.
Top bar
Updated 12 m ago
JMDWCH+2
The path to the page on the left, 56 px high. On the right: when the record was last updated, who is working on it, Share and the primary action.
In place
Updated 12 m ago
JMDWCH+2
Church Farm, Rugby
CE-014·CentralLegals
Live: fold the sidebar with its button, open the tabs. The page keeps its width within 1200 px.
Variants
Variant
Look in tokens
Used for
Sidebar, expanded
240 px (--size-sidebar) on --color-sidebar, 1 px --color-default on its right; group names 12 px uppercase in --color-subtle; items 36 px, --color-muted
The default, on desktop
Sidebar, folded
64 px rail; each item a 36 px square; a tooltip in --color-surface-inverted with --shadow-overlay
More room for the page; remembered per user
Item on show
--color-nav-active with --color-nav-active-text, medium weight, aria-current="page"
Sites, while a Site is open
User card
--color-surface with --shadow-card, the avatar in the function’s tint, the name and the role under it
Who is signed in; a link to the profile
Top bar
56 px (--size-header) on --color-surface with a 1 px --color-default line below; the avatars overlap by 4 px, each ringed in --color-surface
Sidebar 240 px expanded, 64 px folded; top bar 56 px; the page has 24 px of padding and stops at 1200 px. Desktop first and usable on a tablet; there is no phone layout in V1.
Properties
Name
Type
Default
What it does
productName
string
—
Set beside the logo tile; the tile alone when the sidebar is folded
groups
{ id, label, items }[]
—
The groups of pages; a group with no item the user may open is left out
item
{ label, href, icon, active }
—
One page; the active one carries aria-current="page"
user
{ name, role, initials, fn } | null
null
The user card; none until the session has loaded
collapsed
boolean
false
Folds the sidebar to the rail; kept between visits
crumbs
Breadcrumbs
—
The path in the top bar
updated
string
none
How long ago the record changed, in the viewer’s time
people
Avatar[]
[]
Who is working on the record, as a stack with the count of the rest
actions
Button[]
—
Share, then the one primary action
children
ReactNode
—
The page
Alert and toast
Inline alerts in four tones; toasts that confirm or report.
Source:web/packages/crm/src/components/form.tsx(FormError and FormSuccess: tinted box, icon, one sentence). The four tones, the info tone and the toast stack areproposed
An alert is a message that stays on the page, in one of four tones, beside the thing it speaks about. A toast is the same message after an action: it confirms or reports and then leaves by itself. The one rule: a tone is never colour alone, the icon and the words carry it too, and an error that needs a decision is an alert, never only a toast.
Variants
Tone
Look in tokens
Used for
Info
Background --color-info-soft, title and icon --color-info-text, the info icon
A fact the user should know, nothing to fix: documents live in SharePoint, a read-only field.
Success
Background --color-success-soft, title and icon --color-success-text, the check-circle icon
An action went through: an offer recorded, a quote read, a Site moved to Under Offer.
Warning
Background --color-warning-soft, title and icon --color-warning-text, the warn icon
Something needs attention soon, nothing is broken: unsigned Heads of Terms, a longstop coming up.
Error
Background --color-danger-soft, title and icon --color-danger-text, the x-circle icon
An action failed or a value is rejected. Read by a screen reader at once (role alert).
Documents stay in SharePointValere CRM links the files of a Site and reads its quotes and planning documents. It keeps no copy.
Offer recordedCalder Valley Homes’ offer on Heron Fields (LE-022) is on the Site.
Heads of Terms are not signedChurch Farm (CE-014) is due to exchange on 20 Nov 2026.
Offer not recordedThe offer on Heron Fields (LE-022) could not be saved. Check the amount and try again.
States
Heron Fields (LE-022) moved to Under Offer on 9 Nov 2026.
Text only: a one-line fact
The longstop on Church Farm (CE-014) is in 12 days.
With one action
Offer recordedClick the cross: the alert goes and can be shown again.
Dismissible: the cross is a 32 px target
Offer not recordedBoth states of the cross, drawn side by side: hover and keyboard focus.
Close button: hover and focus together
Sizes
Documents stay in SharePointValere CRM links the files of a Site and reads its quotes and planning documents. It keeps no copy.
Default: 14 px, icon 18 px, fills its column
Documents stay in SharePoint; the CRM keeps the link.
Compact: one line, 13 px, inside a card or a table head
Toast
Offer recordedCalder Valley Homes on Heron Fields.
Confirms what was just done
Offer not recordedThe connection dropped. Nothing was saved.
Reports an error
Reminder sent to Hadley & Finch LLP
Title only
Quote read41 lines are ready to review.
With one action
Live: toasts appear at the bottom right, stay five seconds and wait while the pointer is on them.
Rule
What it does
Placement
Toasts stack at the bottom right above everything else (--z-toast), 384 px wide at most; alerts sit inside the page, above the thing they speak about.
Time
A toast stays 5 seconds and waits while the pointer is on it. An alert stays until the cause is gone or the user dismisses it.
Announcement
The toast stack is a polite live region (role="status"); an error alert is role="alert".
Which one
A result the user caused and can forget: toast. A state of the page or an error that needs a decision: alert. Never only a toast for an error.
Properties
Alert
Name
Type
Default
What it does
tone
'info' | 'success' | 'warning' | 'danger'
'info'
Sets the tint, the text colour and the icon.
title
string
—
A short headline in medium weight; optional.
children
ReactNode
—
The sentence: what happened and what to do about it.
action
ReactNode
—
At most one small secondary button.
onDismiss
() => void
—
Shows the close button. Without it the alert is permanent.
compact
boolean
false
One line, 13 px; for tight places.
Toast
Name
Type
Default
What it does
tone
'info' | 'success' | 'warning' | 'danger'
'info'
The icon and the stripe on the left.
title
string
—
What happened, in a few words: “Offer recorded”.
text
string
—
The record it happened to; optional.
duration
number
5000
Milliseconds before it leaves by itself; the pointer on it holds it.
action
ReactNode
—
At most one ghost button, such as Review or Undo.
Modal
A dialog with a title, a body and two actions; the confirm-before-leaving case.
Source:web/shared/components/ConfirmDialog(the Remove flows boards). The leaving variant and the form variant areproposed
A modal stops the page to ask one thing or to say one thing. It has a title, a sentence, an optional grey box and two buttons, the safe one first. The one rule: the page behind it is untouched until the user chooses; nothing is written before the confirm button.
Variants
Variant
Look in tokens
Used for
Leaving
Brand circle (--color-primary-soft); the discarding button is btn--danger
Confirm before leaving a form or a page with unsaved changes. “Keep editing” comes first and takes the focus.
Confirm (the pilot’s ConfirmDialog)
Danger circle (--color-danger-soft), grey box of what goes and what stays, red confirm
Removing a record or taking a relation off a Site. Nothing is written until the red button.
Blocked
Warning circle (--color-warning-soft), plain rows, one button
The action is refused and the dialog says why; there is nothing to confirm.
Form
No circle, fields under the body, primary button (btn--primary)
A form of two or three fields. Anything longer opens in a Drawer.
Leave without saving?
Your changes to the offer on Heron Fields (LE-022) have not been saved.
Leaving: unsaved changes
Take Calder Valley Homes off Heron Fields?
The buyer is no longer one of the offers on this Site. Nothing else is deleted.
The offer of 3 Nov 2026 stays in the history
Calder Valley Homes stays in Accounts
Documents stay in SharePoint
Confirm: what goes and what stays
Calder Valley Homes cannot be removed
These Sites still have an offer from this buyer. Take it off each Site first.
Heron Fields (LE-022), Under Offer
Hatch Farm (SW-031), Fee Discussion
Blocked: informs only
States
Take Calder Valley Homes off Heron Fields?
The buyer is no longer one of the offers on this Site.
Busy: both buttons off while the write is in flight; Escape is ignored
Take Calder Valley Homes off Heron Fields?
The buyer is no longer one of the offers on this Site.
The server refused: Heron Fields is Under Offer and needs one offer on the record.
Error: the refusal stays in the dialog, so nothing is lost by closing it
Leave without saving?
Your changes to the offer on Heron Fields (LE-022) have not been saved.
Focus: Cancel, the safe choice, takes it on opening
Try it
Live: Escape, the dark area or a button closes it, and focus goes back to the button that opened it.
Leave without saving?
Your changes to the offer on Heron Fields (LE-022) have not been saved.
Take Calder Valley Homes off Heron Fields?
The buyer is no longer one of the offers on this Site. Nothing else is deleted.
The offer of 3 Nov 2026 stays in the history
Calder Valley Homes stays in Accounts
Documents stay in SharePoint
Sizes
Size
Width
Used for
sm
400 px
A question with two buttons and no list.
md
520 px
The pilot’s ConfirmDialog, with or without a grey box. The default.
lg
640 px
A short form.
Keyboard and focus
Opening moves focus to the first button, Cancel; Tab stays inside the dialog.
Escape and a click on the dark area close it, except while a write is in flight.
Closing returns focus to the button that opened it, and the page behind does not scroll.
role="dialog", aria-modal, and the title and the sentence named by aria-labelledby and aria-describedby.
Properties
Name
Type
Default
What it does
open
boolean
false
Shows the dialog and the dark area.
icon
'remove' | 'unlink' | 'blocked' | 'close'
—
The picture in the circle and its tone: danger, danger, warning, brand.
title
string
—
A question or a statement, in semibold.
description
string
—
The one sentence under the title: what the action does.
items
ReactNode[]
[]
The grey box: lines ticked (what goes and what stays), or plain rows when checked is false.
checked
boolean
true
Ticks each line of the box.
error
string | null
null
The server’s refusal as a sentence, in the dialog.
confirmLabel
string
—
The red button. Without it the dialog only informs.
busy
boolean
false
Turns both buttons off and shows the spinner while the write runs.
cancelLabel
string
'Cancel'
The safe button, first, with the focus.
onClose
() => void
—
Called by Cancel, Escape and the dark area.
Drawer
A panel from the side for details and forms.
Source:proposedThe pilot opens details on their own pages; the drawer keeps the list in view, as the Monday meeting needs.
A drawer is a panel from the right edge for details and forms about something in the list behind it. The one rule: the user keeps their place; the list is still there, dimmed, and closing the drawer returns focus to the row or the button that opened it.
Variants
Variant
Look in tokens
Used for
Details
Panel on --color-surface, border --color-default, --shadow-overlay; a list of labelled values, actions in the foot
Reading one thing without leaving the list: a Next Action, a buyer’s position, an activity.
Form
The same panel; fields stacked in the body, Cancel and the primary button in the foot
Creating or editing something with more than three fields: a Next Action, a contact.
Details of a Next Action
The form for a new Next Action
The owner and the due date are drawn as plain fields here; in the product they are the Select and the Date picker components.
Try it
Live: slides in from the right; Escape, the dark area or the cross closes it.
States
State
Look
Closed
Not in the page; the list behind it stays as the user left it.
Open
Slides in from the right over --duration-base; the page behind is dimmed with --color-overlay and does not scroll. Under reduced motion it simply appears.
Unsaved changes
Closing a form with edits asks first, with the Modal’s leaving variant.
Sizes
Size
Width
Used for
sm
360 px
A short list of values.
md
440 px
Details and short forms. The default.
lg
640 px
A longer form or a table inside the panel.
Properties
Name
Type
Default
What it does
open
boolean
false
Shows the panel and the dark area.
size
'sm' | 'md' | 'lg'
'md'
The width of the panel; it is always full height.
title
string
—
The heading, with the record it belongs to under it.
children
ReactNode
—
The body; it scrolls when it is long.
footer
ReactNode
—
The actions, right-aligned; the primary one last.
onClose
() => void
—
Called by the cross, Escape and the dark area.
Empty state
A picture, a sentence and the one thing to do next.
Source:proposedThe Data table has its own empty state; this component is the one it and every other list share.
An empty state fills the space where a list would be: a picture, one sentence and the one thing to do next. The one rule: say why it is empty and give one action, never two; a list that is empty because the work is done gets the sentence and no button.
Variants
Variant
Look in tokens
Used for
First use
Circle --color-primary-soft, icon --color-primary-strong; one primary button
A list nobody has filled yet. The button does the thing that fills it.
No match
Circle --color-surface-muted, icon --color-muted; one secondary button
A search or a filter that finds nothing. The button undoes the filter.
All clear
Circle --color-success-soft, icon --color-success-text; no button
A list that is empty because the work is done: no overdue actions, no unmatched emails.
No offers on Heron Fields yet
When a buyer makes an offer, record it here and it joins the comparison.
First use: Offers of a Site
No Sites match these filters
Try another region or stage, or clear the filters to see every Site.
No match: the Sites list
Nothing overdue
Every Next Action on your Sites is on time this week.
All clear: the Monday meeting
The circle with an icon stands in for a picture until the Illustrations exist; the box it fills does not change when they arrive.
States
No buyers on the register
Add the first buyer to start matching.
Default
No buyers on the register
Add the first buyer to start matching.
Action: hover
No buyers on the register
Add the first buyer to start matching.
Action: focus
No offers on Lea Bridge Works yet
Only Land and Partnerships can record an offer. Read only for Construction.
Without the right: the action is off and the sentence says why
Sizes
No documents linked yet
Link the planning documents and quotes from SharePoint.
Full: a page or a panel, 64 px circle
No actions match
Clear the function filter to see them all.
Compact: inside a card or a table, 40 px circle
Properties
Name
Type
Default
What it does
icon
IconName
—
The picture in the circle. Until Illustrations exist it is a 24 px icon.
tone
'neutral' | 'brand' | 'success'
'neutral'
The circle’s tint.
title
string
—
What is empty, in a few words.
children
string
—
One sentence: why it is empty or what fills it.
action
ReactNode
—
At most one button. None when the list is empty because the work is done.
compact
boolean
false
Less padding and a smaller circle, for inside a card.
File upload
Drop zone, progress, the file list, an error.
Source:proposedThe pilot has upload in its base storage and no document screen (S-05 OPP-16); in the product the file is handed to SharePoint.
A file upload hands a document over to be filed and read: a drop zone, a progress bar while it travels, a list of what was sent and an error when it could not be. The one rule: a document never lives in the CRM. The file goes to SharePoint and the product keeps the link, so every row says where it was filed.
Variants
Variant
Look in tokens
Used for
Drop zone with list
Dashed border --color-emphasis, --color-primary-soft when a file is over it; rows in a bordered list below
Filing a returned quote or planning document against a Site: the main way.
Button only
A btn--secondary with the upload icon; the rows are the same
A row of a table or a card where a zone does not fit.
Westbrook-quote-CE-014-v2.pdf1.8 MB
Uploading62%
Westbrook-quote-CE-014-v1.xlsx640 KBSent to SharePoint. Reading the quote…
Westbrook-quote-CE-014-v0.pdf2.4 MBRead41 lines ready to review
Westbrook-scan.pdf38 MBNot uploaded: larger than 25 MB, the limit set by an admin.
Westbrook-quote-CE-014-v3.docx310 KBCould not reach SharePoint. Nothing was filed.
A quote from Westbrook Construction for Church Farm (CE-014): uploading, reading, read, and two errors.
Button only: opens the same file picker
Documents live in SharePoint. The drop zone hands the file over, the row says where it was filed, and only the link is kept in the CRM. A quote in Excel, PDF or Word is read into cost headings once it is filed.
States
Default
A file is over it (or the pointer, on hover)
Keyboard focus: the hidden input shows the ring on the zone
Disabled: the hint says what is missing
Only PDF, Excel or Word files can be read. “plan.dwg” was not added.
Error: the file type is refused; the message names the file
Try it
Live: choose or drop a PDF, Excel or Word file. Nothing leaves your computer: the progress is simulated. Any other type, or a file over 25 MB, shows its error.
Sizes
Part
Size
Drop zone
Full width of its column, 560 px at most; 32 px padding above and below the 40 px circle.
File row
36 px icon tile, name in medium weight, size and status under it; actions at the right, 32 px targets.
Progress bar
6 px high on the chart track token; it carries role progressbar and its percentage as text beside it.
Properties
Name
Type
Default
What it does
accept
string[]
['.pdf', '.xls', '.xlsx', '.doc', '.docx']
The types a quote can arrive in; anything else shows the type error.
maxSize
number
26214400
Bytes: 25 MB, an admin setting; a larger file shows the size error.
multiple
boolean
true
Several files at once; each gets its own row.
disabled
boolean
false
Turns the zone off; the hint says what is missing.
files
{ name, size, status, progress, error }[]
[]
The rows. Status is uploading, reading, read or error.
onFiles
(files: File[]) => void
—
Called with the files chosen or dropped; the parent hands them to SharePoint.
onRemove
(name: string) => void
—
The cross on a row.
onRetry
(name: string) => void
—
The Try again button on an error row.
Function chip
The owning function in its colour, on every record and action.
Source:web/shared/components/Chip(kind function) · avatar tiles: the app shell,web/shared/components/AppLayout
Shows who owns a record, an action or a stage, in the function’s own colour and always with its name. The one rule: the name is always written — the colour only helps the eye, so a chip is never a bare dot.
Variants
One colour per function, the same everywhere: the chip, the avatar of a person, the owner of a stage, the clock.
Contractors, tenders, the build price and the CSA. Owns the Contractor stage. Shown only where Construction applies.
Legal
--color-fn-legal · --color-fn-legal-tint
The Partners / MD and Admin roles. The neutral slate of the set.
Sizes
Small in a table cell or a stage bar, medium on a record, large in a page header.
LandSmall · 20 px
LandMedium · 24 px, the default
LandLarge · 28 px
With an avatar
The person’s initials in a round tile that takes the function’s colours reversed, with or without the person’s name.
JMLandInitials and function
DWPartnershipsInitials and function
CHConstructionSmall
PNPriya Nair ·Back OfficeLarge, with the person’s name
States
A chip is a label, not a control: it has no hover, focus or disabled state. To filter by function use the Select. Shown as the owner of a record, alone or jointly.
LandOne owner
LandPartnershipsConstructionJoint owners: Legals and Exchange
LandPartnershipsConstruction not shown where it does not apply
Site
Stage
Owner
Church Farm, Rugby
Legals
LandPartnershipsConstruction
Heron Fields, Colchester
Under Offer
Partnerships
Hatch Farm, Sindlesham
Fee Discussion
Land
Properties
Name
Type
Default
What it does
fn
backoffice | land | partnerships | construction | legal
—
The owning function; sets the colour and the written name.
size
sm | md | lg
md
Height 20, 24 or 28 px; the text and the avatar follow.
avatar
text
—
The initials of a person; draws the round tile before the name.
person
text
—
The person’s name, written before the function.
Stage bar
The Site’s eight-segment lifecycle; the buyer and contractor journeys.
Source:web/packages/crm/src/pages/lead-detail/StageBar · design concept, Opportunity Overview;owners, captions and journeysproposed
Shows where a Site, a buyer or a contractor stands on its path and who holds it now. The one rule: position is never colour alone — every segment has its name, and the current one says the day it is on.
Variants
Variant
Look in tokens
Used for
Site lifecycle
--color-primary · --color-emphasis · .c-fnchip
The Site header and the Opportunity Overview: Lead, Appraisal, Instructed, Buyer agreed, Contractor stage, Heads of Terms, Legals, Exchange, with the function that owns each.
Buyer journey
--color-primary · --color-emphasis
One buyer on a Site, on the Buyers tab: Coverage, Teaser, Pitched, Interested, Offered, Agreed, Board, Approved. Owned by Partnerships.
Contractor journey
--color-primary · --color-emphasis
One contractor on a Site, on the Contractors tab: Coverage, Longlist, Tender Sent, Bids Returned, Priced, Preferred, Appointed. Owned by Construction.
Site lifecycle
The design concept’s eight segmented bars: done solid, the current one part-filled with the day it is on, the ones ahead grey. Each stage names its owning function; the pill says whether Construction applies.
Church Farm, RugbyCE-014
Construction applies — Deal Type: Land & Build
Lead(done)Done · 12 daysBack Office
Appraisal(done)Done · 9 daysBack Office
Instructed(done)Done · 3 daysLand
Buyer agreed(done)Done · 41 daysPartnerships
Contractor stage(done)Done · 28 daysConstruction
Heads of Terms(done)Done · 22 daysPartnerships
Legals(current)Day 35 · nowJoint
ExchangeTarget 14 NovJoint
Joint: Land, Partnerships and Construction together, in Legals and at Exchange.
Heron Fields, ColchesterLE-022
Construction does not apply — Deal Type: Land
Lead(done)Done · 12 daysBack Office
Appraisal(done)Done · 9 daysBack Office
Instructed(done)Done · 3 daysLand
Buyer agreed(done)Done · 41 daysPartnerships
Contractor stageNot applicable
Heads of Terms(current)Day 12 · nowPartnerships
LegalsTarget 3 DecJoint
ExchangeTarget 18 DecJoint
Buyer and contractor journeys
The same bar for one buyer’s or one contractor’s path on a Site; the current stage carries the fact that matters.
Buyer journeyCalder Valley Homes
Partnerships
Coverage(done)
Teaser(done)
Pitched(done)
Interested(done)
Offered(current)Offer £3,640,000
Agreed
Board
Approved
Contractor journeyWestbrook Construction
Construction
Coverage(done)
Longlist(done)
Tender Sent(done)
Bids Returned(current)Returned 2 Nov
Priced
Preferred
Appointed
States
A segment is one of four. When the Site is past the bar the whole bar is done.
State
Look in tokens
What the text says
--color-primary
Done · 41 days — how long the stage took. Read aloud as “done”.
--color-primary-soft + --color-primary
Day 35 · now — the day in the stage; the fill is how far through its clock. Read aloud as “current”.
--color-emphasis
Target 14 Nov — the target date when one is set, otherwise nothing.
--color-emphasis
Not applicable — a stage that Deal Type or Construction Involved removes for this Site; the outline is dashed.
Church Farm, RugbyCE-014
Completed
Lead(done)Done · 12 daysBack Office
Appraisal(done)Done · 9 daysBack Office
Instructed(done)Done · 3 daysLand
Buyer agreed(done)Done · 41 daysPartnerships
Contractor stage(done)Done · 28 daysConstruction
Heads of Terms(done)Done · 22 daysPartnerships
Legals(done)Done · 38 daysJoint
Exchange(done)Exchanged 12 NovJoint
Sizes
Size
Look in tokens
Used for
Default
6 px track, 12 px names, captions and owners
A card on a record page.
Compact
4 px track, names only
A row of a table or a card of a list, where only the position matters.
Lead(done)
Appraisal(done)
Instructed(done)
Buyer agreed(done)
Contractor stage(done)
Heads of Terms(done)
Legals(current)
Exchange
Properties
Name
Type
Default
What it does
segments
{ name, state, note?, owner? }[]
—
The stages in order; state is done, current, future or not applicable.
current
stage
—
The stage on show; past the last segment marks them all done.
fill
0–100
50
How far through the current stage, from its clock; 50 when there is none.
owners
boolean
true
Shows the owning function under each stage; joint owners as dots.
constructionApplies
boolean
true
Draws the pill and the Contractor stage; false marks that stage not applicable and drops Construction from the owners.
label
text
Site lifecycle
The accessible name of the list.
size
md | sm
md
Default with captions, or compact.
Deal clock
Days left on a function’s clock, and the overdue flag.
Source:proposed— the clocks ofblueprint/modules/views-scores-dashboards.md (VIW-C21)
Shows how many days a function has left on its clock for a Site, and flags it when the clock has run out. The one rule: the count says “left” or “overdue” in words, and the length applied is one click from the clock.
Variants
One clock per function; the Back Office and Land clocks count working days, the others every day.
Variant
Length
Look in tokens
Used for
Back Office
5 working days
--color-fn-backoffice
From the appraisal request to the appraisal.
Land
15 working days
--color-fn-land
From the appraisal to the instruction.
Partnerships
28 days, first offer within 21
--color-fn-partnerships
From instruction to an acceptable offer.
Construction
21 days to a bid, 30 to the CSA
--color-fn-construction
From the handover to Construction, only where Construction applies.
Partnerships
Under 100 days
--color-fn-partnerships
From the latest signed Heads of Terms to exchange.
Pill
The compact form, in a table row or a Site header.
Back Office2 working days leftBack Office · 5 working days
Land5 working days leftLand · 15 working days
Partnerships8 days leftPartnerships · 28 days
Construction3 days leftConstruction · 21 days
Partnerships65 days leftHoTs to exchange · under 100 days
Card
The full form, with the clock’s dates and the length applied with the date it last changed.
Back OfficeAppraisal clock
2working days left
Appraisal requested 4 NovDue 11 Nov
Length applied: 5 working days · changed 12 Oct 2026
LandInstruction clock
5working days left
Appraised 26 OctDue 16 Nov
Length applied: 15 working days · changed 12 Oct 2026
PartnershipsAcceptable offer clock
8days left
Instructed 20 OctDue 17 Nov
Length applied: 28 days, first offer within 21 · changed 12 Oct 2026
ConstructionAcceptable bid clock
3days left
Handed over 22 OctDue 12 Nov
Length applied: 21 days · changed 12 Oct 2026
ConstructionAcceptable CSA clock
12days left
Handed over 22 OctDue 21 Nov
Length applied: 30 days · changed 12 Oct 2026
PartnershipsHeads of Terms to exchange
65days left
HoTs signed 5 Oct · day 35Due 13 Jan 2027
Length applied: under 100 days · changed 12 Oct 2026
States
On track, due soon, overdue and paused. A closed Site shows no clock.
5 working days leftOn track
3 days leftDue soon: a quarter of the length or less is left
2 working days overdueOverdue
PausedPaused: the Site is Parked
LandInstruction clock
2working days overdue
Appraised 15 OctWas due 5 Nov
Length applied: 15 working days · changed 12 Oct 2026
Properties
Name
Type
Default
What it does
fn
function
—
The function whose clock it is; sets the chip.
length
number
—
The length applied, from the Admin’s setting.
unit
days | working days
—
Working days follow the working-day calendar; the others count every day.
startedOn
date
—
The handoff that started the clock; a Parked Site pauses it, a closed Site stops it.
state
ok | soon | over | paused
ok
Worked out from the days left; the words say it as well as the colour.
size
pill | card
pill
A pill in a table or a header, or a card with its dates.
Deal Health
The 0–100 score in its band, its breakdown, the stalled badge that names its rule.
Shows how healthy a Site is as one number from 0 to 100, in its band, and lets anyone see how it is made up. The one rule: the number is always beside its icon, and the breakdown names every input and its points — the formula is never hidden.
Variants
Three bands, each with its own icon; the bands are the pilot’s.
The popover that opens from the score: each input, its points and the fact behind it, then the stall rules that fired. Shown open, and live below it (click the score; Escape closes it).
Deal health 55(100 less each input; 40 to 69)
Recent contact
3 days since the last contact
0
Overdue actions
3 open actions past due
−30
Stage duration
35 days in Legals; no limit for this stage
0
Next action
2 open actions
0
Legals
1 critical task past deadline
−15
Open flags
No open flags
0
Stall rules fired
critical Legals task past deadline
Proposed weights, not yet approved by Valere. The Admin can edit them.
Deal health 55(100 less each input; 40 to 69)
Recent contact
3 days since the last contact
0
Overdue actions
3 open actions past due
−30
Stage duration
35 days in Legals; no limit for this stage
0
Next action
2 open actions
0
Legals
1 critical task past deadline
−15
Open flags
No open flags
0
Stall rules fired
critical Legals task past deadline
Proposed weights, not yet approved by Valere. The Admin can edit them.
Inputs and weights
The score starts at 100 and loses each input’s points. The weights are the pilot’s proposal; the Admin edits them in Settings.
Input
What it counts
Weight
Recent contact
3 points a day after 5 days without contact, up to 30
−3 a day
Overdue actions
10 points for each overdue action, up to 30
−10 each
Stage duration
1 point a day past the stage’s limit, up to 20; Legals has no limit
−1 a day
Next action
20 points when no next action is named
−20
Legals
15 points for each critical Legals task past its deadline
−15 each
Open flags
8 points for each open flag, up to 24
−8 each
Expectation gap
Leads: 1 point for each whole % the landowner’s figure is above the appraisal, up to 20
−1 a %
Stalled badge
Appears beside the score when a stall rule fires, and names the rule.
Stalled: no progress 14 daysOne rule, named
Stalled: no progress 14 days+1First rule named, “+1” for the others
Stalled: Heads of Terms open 30 daysThe rule that fired decides the words
Hover or focus shows the threshold applied and the date it last changed.
Properties
Name
Type
Default
What it does
score
0–100
—
The Deal Health score; rounded and kept between 0 and 100. No score on a closed deal.
components
{ input, points, fact }[]
—
The inputs behind the score, each with its points and the fact they come from. A missing input is named, not hidden.
stallRules
rule[]
[]
The stall rules that fired; the badge names the first and counts the rest.
size
md | lg
md
24 or 32 px high.
onClick
function
—
Makes the chip the button that opens the breakdown; Escape or a click outside closes it and Escape gives the focus back.
Key dates
Exchange, completion and longstop, each with its countdown.
Source:web/packages/crm/src/pages/opportunity-detail/KeyDatesCard · the thin bar and the tags:proposed
Shows the dates a deal turns on — exchange, completion and the longstop — each with the days left. The one rule: the count is a phrase (“39 days left”, “4 days overdue”), and the tag says whether the date is a target or a hard date.
Variants
Variant
Look in tokens
Used for
ExchangeTarget
--color-primary-soft · --color-primary-strong
The date Valere is working to. It moves, and each move is kept.
CompletionTarget
--color-primary-soft · --color-primary-strong
The date the sale completes.
LongstopHard date
--color-surface · --color-default
The date in the contract that must be met; passing it is a legal blocker.
On the Site record
Church Farm on Monday 9 Nov 2026, 35 days after Heads of Terms were signed: the thin bar shows how much of the time to each date has gone.
Key dates
ExchangeTarget14 Nov 20265 days left
CompletionTarget4 Dec 202625 days left
LongstopHard date18 Dec 202639 days left
States
Key dates
ExchangeTarget14 Nov 20265 days left
Key dates
ExchangeTarget5 Nov 20264 days overdue
Key dates
ExchangeTarget12 Nov 2026Exchanged
Key dates
ExchangeTargetNot set
On track: 14 days or more left. Due soon: a week or less, with a clock icon. Overdue: the date has passed and the step is not recorded, with a warning icon. Met: the step is recorded.
Properties
Name
Type
Default
What it does
label
text
—
Exchange, Completion or Longstop.
date
date
—
UK date; “Not set” when empty.
tag
target | hard
target
Target for the dates Valere works to, Hard date for the longstop.
startedOn
date
—
Where the thin bar begins; it fills toward the date.
state
on-track | soon | overdue | met
on-track
Worked out from the days left, with its words and icon.
Position card
The buyer’s or the contractor’s position on a Site at a glance.
Shows who is on the other side of a Site right now — the agreed buyer, the appointed contractor — with the one figure that matters. The one rule: the status is a labelled pill, and when nobody is agreed the card says so and counts who is in play.
Variants
Variant
Look in tokens
Used for
Buyer position
--color-stage-tint · --color-stage-text · .card
The agreed buyer of a Site: name, status, the offer and its quality. The full list is the Buyers tab.
Shows one stream of Valere’s income on a Site: how much, how sure, what triggers it and how far it has got to being collected. The one rule: every active stream names its trigger, and a fee that will never be paid says so, with who approved it, instead of just disappearing.
Variants
The four streams. A Site can hold several at once and shares one fee agreement.
Where the fee is: triggered, invoiced, collected, or never to be paid.
owner
function
—
The function that records and chases it; shown as a chip.
Source and confidence
Where an AI-read value came from and how sure the reading is.
proposedEvery AI-read value carries it (N-08); the pilot has no AI layer yet.
A chip on every value the system read from a document, an email or a web page: the source with its page or address, how sure the reading is, or “Not found”. The one rule: nothing takes effect until a named person approves it.
The chip
Not found
Left to right: read with high, medium and low confidence from a document and page; read from a web address; nothing found.
Variants
Variant
Look in tokens
Used for
High
Three bars filled, success text on the success tint
A value the document states plainly: a figure, a date, a name
Medium
Two bars filled, warning text on the warning tint
A value inferred from the wording or read from a poor scan
Low
One bar filled, danger text on the danger tint
A guess the person must check before relying on it
Not found
Dashed border, muted text, no bars, a search icon
A field the system looked for and could not find; the field stays empty
Nothing takes effect until a named person approves
The AI only reads; a person decides. The chip stays on the value after approval, so anyone can see where it came from.
Read, awaiting approval
Planning statusOutline consent grantedAwaiting approval by Jamie Morgan
Approved
Planning statusOutline consent grantedApproved by Jamie Morgan, 9 Nov 2026
Nothing found
Affordable homesNo value yetNot foundLand fills this in by hand
A read value is shown apart from the record: dashed edge, the sparkles mark and the approver named. Approving makes it the record’s value and keeps the source beside it; until then no stage, score or report uses it (N-08).
States
Default
Hover
Focus
Not foundNot found
The chip is a button: it opens the document at the page, or the web address in a new tab. “Not found” opens nothing, so it is not a button.
Sizes
Default: beside a field
Compact: in a table cell
Properties
Name
Type
Default
What it does
source
string
required
The document and page, the email, or the web address the value was read from
confidence
'high' | 'medium' | 'low'
required
How sure the reading is; shown as bars and as a word, never colour alone
found
boolean
true
When false the chip says “Not found” and has no source
compact
boolean
false
The smaller chip for a table cell: the source is shortened, the confidence stays
approvedBy
person | null
null
The named person who approved the value; empty means it still waits
Proposed update
A change read from an email or a meeting, beside its source, to accept or discard.
proposedDesign concept, Buyers; the Pending proposals list on the home page is the pilot’s nearest.
A change the system read from an email or a Teams meeting, shown beside the email it came from: the field, the old value and the new one, who proposed it, and Accept or Discard. The one rule: it changes nothing on the record until a named person accepts it, and accepted and discarded are final.
Beside its source email
Source email
From
Hadley & Finch LLP
Subject
Church Farm, Rugby: exchange date
Received
Fri 6 Nov 2026, 09:14
Further to our call, the buyer’s solicitors have confirmed they are ready to exchange onFriday 11 December 2026. Completion would follow on Friday 18 December.
Proposed update
ProposedAcceptedDiscarded
Exchange dateFri 27 Nov 2026Fri 11 Dec 2026
Site
Church Farm, Rugby · CE-014
Proposed by
The system, from an email logged by Dana Whitfield
Source
Approver: the owner of this field, Dana Whitfield (Partnerships). Nothing changes on the record before then.
Written to the record with the email linked, by Dana Whitfield, 9 Nov 2026, 10:02. Final.
Discarded by Dana Whitfield, 9 Nov 2026, 10:02. The record is unchanged; only the audit log remembers. Final.
Live: Accept and Discard both settle the proposal; a settled proposal is final, so the sample offers only a reset.
States
Proposed update
Proposed
Exchange dateFri 27 Nov 2026Fri 11 Dec 2026
Waiting for the approver. It also appears in their Pending proposals on the home page.
Proposed update
Accepted
Exchange dateFri 27 Nov 2026Fri 11 Dec 2026
Written to the record by Dana Whitfield on 9 Nov 2026; the source email stays linked to the change.
Proposed update
Discarded
Exchange dateFri 27 Nov 2026Fri 11 Dec 2026
Discarded by Dana Whitfield on 9 Nov 2026. The record is unchanged.
Proposed update
Superseded
Exchange dateFri 27 Nov 2026Fri 11 Dec 2026
A newer proposal for the same field from the same thread replaced it: Fri 18 Dec 2026.
Proposed update
Lapsed
Exchange dateFri 27 Nov 2026Fri 11 Dec 2026
Nobody decided within 14 days, or the Site was closed. It can no longer be accepted.
Variants
Variant
Look in tokens
Used for
Beside the email
Two columns on the surface: the source email, then the update; a border and the card shadow
The approver’s screen: decide with the email in view
Compact
The update column alone, one line of outcome under the change
A list of proposals, the Lead page and the Site stage bar’s display line
From a meeting
The same, with the passage of the transcript in place of the email
A change read from a Teams meeting; the chair approves them in one go
The five states
State
Look in tokens
What it means
Proposed
Info tone, clock icon; Accept and Discard shown
Read from the email; it changes nothing yet
Accepted
Success tone, check icon; no actions
A named person accepted it: final
Discarded
Neutral, x icon; no actions
A named person discarded it: final, no trace on the record but the audit entry
Superseded
Neutral, arrow icon; no actions
A newer proposal for the same field from the same thread replaced it
Lapsed
Warning tone, clock icon; no actions
It waited past the admin-set age, or its Site was closed
Properties
Name
Type
Default
What it does
field
string
required
The record’s field the proposal would change
from / to
string
required
The current value, struck through, and the proposed one
The log of what happened on a Site, Account or Contact: calls, emails, meetings, notes and stage changes that people logged, and the entries the system wrote when a rule fired. The one rule: entries are only ever added, newest first, and a system entry looks different from a person’s.
The timeline
Today · Mon 9 Nov 2026
Dana WhitfieldPartnershipsCall
Spoke to Calder Valley Homes about Heron Fields. They will confirm their interest by Friday.
SystemSystemRule
Stalled: no progress logged on Lea Bridge Works for 14 days. Rule: stalled after 14 days.
Fri 6 Nov 2026
Jamie MorganLandMeeting
Fee discussion with the landowner at Hatch Farm. Fee basis to be confirmed with Rhys Calloway.
Conor HigginsConstructionEmail
Sent the tender pack for Church Farm to Westbrook Construction.
Dana WhitfieldPartnershipsStage change
Heron Fields moved from Acceptable Offer to Under Offer.
Thu 5 Nov 2026
Jamie MorganLandNote
Landowner would like to complete before Christmas. Ask Hadley & Finch LLP about the longstop date.
No entries for this function yet. Log a call, email, meeting or note to start.
Dana WhitfieldPartnerships
Filled dot: a person logged it, in their function’s colourHollow dot: a system rule wrote it
Variants
Variant
Look in tokens
Used for
Person entry
Filled dot in the function’s colour, name in semibold, function chip in its tint, type tag in neutral
A call, email, meeting, note or stage change someone logged
System entry
Hollow dot with a muted ring, the name “System”, the System chip in neutral, type Rule or Stage change
A stall rule or another rule firing; the entry names the rule
Day header
Semibold caption in muted text over a hairline, one per day
Entries grouped by day, newest first
Composer
A text area on the surface with a segmented type choice and a primary Log button
Logging by hand at the top of the Activity & Risk tab, an Account or a Contact
States
State
Look
What the user sees
Filled
Day headers, entries newest first
All is the default; a pill filters by function, and a day with nothing left disappears
Filter on
The pressed pill takes the primary tint and keeps its label
Only the entries of that function; the pill is aria-pressed
Empty
One sentence under the composer
No entries yet, or none for the function chosen; the log action stays offered
Focus
Ring on a pill, the type choice, the text area or Log
Keyboard users move through the pills, then the composer
Properties
Name
Type
Default
What it does
entries
Activity[]
[]
The log, newest first; nothing is ever overwritten
A recommended buyer for a Site: the score out of 100 with its label, the reason in words, the four criteria as chips and, behind Why, the arithmetic. The one rule: a gap is never hidden in the score; a criterion with no data is shown as not recorded, with a dashed edge.
Takes S106, and 28 homes fits their 10 to 30 range; active next door in South & West. Turnkey appetite is not recorded.
Scored on 3 of 4 criteria. Completing turnkey appetite on the account can raise the score to 80.
Region: half pointsUnits: full pointsS106: full pointsTurnkey: not recorded: not recorded, no points
Criterion
Result
Why
Points
Region
Partial
South & West is next to Central, one of their active regions
20 / 40
Units
Match
28 homes is inside their 10 to 30 range
30 / 30
S106
Match
They take S106; the site has 8 affordable homes
15 / 15
Turnkey
Not recorded
Turnkey appetite is not recorded on the account
0 / 15
Criteria from the Ashby Rural Housing account, updated 21 Oct 2026.Open account
65 / 100
Scored out of 100 by rules with the admin’s weights: Region 40, Units 30, S106 15, Turnkey 15. A partial match earns half the points. Below 50 a buyer is counted under the list, not shown in it. The score is arithmetic, never the AI.
Criteria chip key
Regionfull pointsRegionhalf points: a neighbouring region, or units within 10% of the rangeRegionno pointsRegion: not recordedno data, 0 points
Variants
Variant
Look in tokens
Used for
Strong, 80 and above
Success text on the success tint, in a round figure
A buyer worth pitching first
Fair, 50 to 79
Warning text on the warning tint, in a round figure
A buyer worth a conversation; the Why shows what holds the score back
Below 50
Muted text on the muted surface; not listed, counted under the list
Shown only on request: “2 buyers scored under 50”
Criterion: full
Success tint and text, check icon
Full points
Criterion: half
Warning tint and text, info icon
Half points: a neighbouring region, or units within 10% of the edge
Criterion: no
Muted surface and text, x icon
No points
Criterion: not recorded
Dashed border on the surface, minus mark, “not recorded”
No data on the buyer’s account: the gap stays visible and scores 0
States
State
Look
What the user sees
Why closed
The row: score, buyer and reason, the four chips, Why and Add to journey
The recommendation at a glance
Why open
The Criterion, Result, Why and Points table under the row, with the total and the date the buyer’s criteria were updated
The arithmetic behind the number; the button’s chevron turns
Incomplete criteria
A dashed chip and the line “Scored on 3 of 4 criteria”
What to complete on the account to raise the score
Read only
Add to journey locked, a note naming Partnerships
Land, Construction and Back Office read scores; only Partnerships adds a buyer
Properties
Name
Type
Default
What it does
buyer
Account
required
The buyer: name, type and funding, linked to its account
score
number (0–100)
required
The total; the band and its label follow: Strong from 80, Fair from 50
reason
string
required
The score in words, one clause per criterion
criteria
{ result, points, max }[]
required
Region, Units, S106 and Turnkey; result is full, half, no or not recorded
criteriaUpdated
date
required
When the buyer’s criteria were last updated; shown in the Why panel
canAdd
boolean
true
False for every role but Partnerships: Add to journey is locked
Comparison table
Offers or bids side by side, like for like, with the grade and the rank.
proposedBuilt on the data table; the pilot’s Buyer journey table is the nearest.
Offers from buyers, or bids from contractors, in one table so that they can be read against each other: the same Site, the same columns, every version kept. The one rule: the system suggests the grade, a person confirms it, and both are shown.
Offers, like for like
Heron Fields, Colchester · LE-022 · 46 homes · GDV £10,350,000 · every version of every offer priced against the same Site
The system calculates % of GDV and suggests the band: Exceptional 75% or more, Good 73% to under 75%, Acceptable 71% to under 73%, Weak under 71%. The PM confirms or changes it; a changed grade is marked. With no GDV the cell is grey and no grade is suggested.
Bids, like for like
Church Farm, Rugby · CE-014 · 28 homes · 24,640 sqft · every bid is base price plus itemised abnormals
Ranked on base price, lowest first. £ per sqft is the only area unit. A withdrawn bid leaves the rank and stays on record; a bid with no itemised abnormals is flagged for Construction’s review.
Variants
Variant
Look in tokens
Used for
Offers
The data table on the surface; figures right-aligned and tabular; the grade chips in their category tokens
Buyers and Offers: every version of every offer, with the suggested grade beside the one the PM confirmed
Bids
The same table; the rank in a round badge; a withdrawn row muted
Contractors and Tenders: base price and abnormals side by side, with the CSA status and the rank
Grade chip
Exceptional, Good, Acceptable, Weak in the --color-grade-* text and tint
The suggested and the confirmed grade; the word is always shown
States
State
Look
What the user sees
Confirmed
Both grades filled; a check and “Matches suggestion”
The PM agreed with the system
Changed
Both grades filled; a pencil and “Changed from suggestion”
The PM chose another band; the earlier suggestion stays visible
Not yet confirmed
Dashed muted text in the Confirmed column
The system has suggested; nobody has chosen
Missing data
A grey dash in % of GDV and no suggestion; “None stated” in Abnormals
The figure the comparison needs is not on record
Withdrawn
The row muted, a Withdrawn badge, “Out of the rank”
The contractor withdrew or was moved to the Removed list
Properties
Name
Type
Default
What it does
kind
'offers' | 'bids'
required
Chooses the columns
rows
Offer[] | Bid[]
[]
One row per version; earlier versions stay on record
suggestedGrade
grade
null
The band the system calculated from % of GDV; a suggestion only
confirmedGrade
grade | null
null
The PM’s choice; empty shows “Not yet confirmed”
rankBy
'basePrice'
'basePrice'
How bids are ranked; withdrawn bids leave the rank
canEdit
boolean
false
Only Partnerships grades an offer and only Construction a bid; everyone else reads
Approval checklist
The Instruction Approval gate: each item’s evidence, reviewer and date, or a partner’s exception.
proposedThe gate is in the brief; the pilot has no checklist component.
The final gate before a Site is instructed: every item with its evidence, its reviewer and the date, or a partner’s named exception. The one rule: Record instruction stays locked until every item is complete or excepted.
Locked: items still open
Instruction Approval
Hatch Farm, Sindlesham · SW-031
3 of 5 closed
Complete
Technical pack reviewed (title and covenants, drainage, rights of way)
Success tone, check icon; the evidence link, the reviewer’s avatar and name, the date
An item closed with its evidence
Open
Neutral badge, clock icon; a line that says what evidence is needed; two actions
An item not yet closed; it blocks the Instruction
Excepted
Info tone, lock icon; a block under the item naming the partner, the date and the reason
An item a partner approved a named exception for; it counts as closed and stays visible as excepted
Record instruction
Primary button; locked is disabled with a lock icon and the reason beside it
The last step: it unlocks only when every item is complete or excepted
States
State
Look
What the user sees
Locked
Disabled button, lock icon, a sentence naming the open items
Why the Instruction cannot be recorded, and what to close
Ready
Active primary button, a check icon in the sentence
The gate is open; Land records the Instruction and Deal Type
Exception withdrawn
The item returns to Open; the exception stays in the log
The button locks again
Focus
Ring on the evidence link, the actions and the button
The locked button stays reachable and its reason is read with it
Properties
Name
Type
Default
What it does
items
Item[]
required
The gate’s items: technical pack, planning comments, unit mix, construction route and cost, fee agreement
item.state
'open' | 'complete' | 'excepted'
'open'
Open until closed with evidence or excepted by a partner
item.evidence
link | note
null
A SharePoint document link or a note; an item cannot close without it
item.reviewer / date
person / date
null
Who closed it and when; audited
item.exception
{ by, date, reason } | null
null
Only a Partner / MD approves one; it names the item, the reason and the date
onRecord
() => void
required
Records the Instruction; refused by the system while any item is open and not excepted
Reserve
Components the product may need later, each with why.
proposed
These four are not in the first release. Each carries the reserve tag and one line of why it may be needed. The rule: none is built until a flow asks for it, and each is made of the tokens and components above, so it arrives looking like the rest.
Site map
reserve
May be needed when Land wants to see where the pipeline sits by region. PostGIS already holds every Site’s location, so a map is a new view, not new data.
Pin: a Site, by Site Code and Deal Health
70 and above
40 to 69
Below 40
The figure on a pin is the Site’s Deal Health. A drawing of the idea: the product would draw its own map over the PostGIS locations.
Variantspins by Site (default); clustered when zoomed out; coloured by Deal Health or by Site stage; filtered by region or function.
Signature status
reserve
May be needed once Adobe Sign is connected: the PM sees where a fee agreement or Heads of Terms is without opening the envelope.
Fee agreement· Hatch Farm (SW-031)Waiting for Valere
Sent4 Nov 2026To Edward Marsh, the landowner
Viewed5 Nov 2026Opened by Edward Marsh
Signed by landowner6 Nov 2026Edward Marsh
Signed by ValereNot yet signedWaiting for Rhys Calloway since 6 Nov 2026
Sent through Adobe Sign; the status comes back by itself.
Variantsfull card on a record; a single badge in a table row; declined or expired, with the step in the danger tone and the reason.
Comment thread on a record
reserve
May be needed if the team wants to talk on the Site itself instead of in email; today a note is an entry in the Activity timeline.
Comments2Hatch Farm (SW-031)
JM
Jamie MorganLand9 Nov 2026, 09:40
Edward Marsh confirmed 33 units on the revised layout. Drawings follow on Thursday.
DW
Dana WhitfieldPartnerships PM9 Nov 2026, 10:05
Thanks, Jamie. I will hold the Fee Discussion until the drawings are in.
RC
The person mentioned is notified.
Variantson a Site, a Contact or a Buyer; with @mentions; a resolved thread folds to one line.
Kanban of Sites by stage
reserve
May be needed for the Monday meeting, if the partners want the pipeline as columns beside the table.