The parts

Clearing is 7 routes and 27 parts on 120 design tokens, every one re-authored for dark. Every figure on this page and on every route resolves through one fixture file, so nothing here can disagree with anything there.

Fixture spine: 13 weeks, 3 closed, 10 open, 2 under the covenant floor — consistent.

Tokens

--background

--card

--surface-sunken

--surface-raised

--muted

--border

--border-strong

--foreground

--primary

--primary-hover

--primary-soft

--accent

--ring

--selection

--positive

--warning

--critical

--info

--horizon-actual

--horizon-forecast

--horizon-floor

--chart-3

--text-d4Cash position
--text-d3Thirteen weeks
--text-d2£4,352,940
--text-d1Payment run R-2634
--text-leadThe week the money runs short.
--text-bodyBody copy at the marketing size.
--text-smallThe console register — every screen inside the shell.
--text-captionCaptions, table meta, the line under a figure.
(label)Column label
(ref)GB29 LOYD 3096 5502 2201 14

rounded-themed-sm

rounded-themed

rounded-themed-lg

rounded-themed-xl

rounded-themed-pill

The signature

One thirteen-week horizon, drawn three times at three sizes. All three call weekFor(), which throws on a week outside the window, so no drawing can disagree with another about where the money runs out.

Horizon

src/components/ui/horizon.tsx

Closed weeks are solid, open weeks are hatched, a week under the covenant floor takes the breach ground. The distinction is a texture rather than a hue, so it survives greyscale and a projector.

HorizonStrip — inside a row or a card

HorizonColumn — the head of a page about one week

Closing, w/c 5 Oct

£1,084,780

£915,220 below the £2.0m floor

HorizonLegend

  • Closed — banked
  • Open — forecast
  • Below the £2.0m floor

HorizonGrid — the full instrument

Thirteen-week cash forecast. Weeks one to three have closed; weeks four to thirteen are forecast. The covenant floor is £2,000,000 of liquidity at each week end.
Week3 Augclosed10 Augclosed17 Augclosed24 Augopen31 Augopen7 Sepopen14 Sepopen21 Sepopen28 Sepopen5 Octopen12 Octopen19 Octopen26 Octopen
Receipts£4.1m£3.0m£3.7m£3.4m£2.9m£4.0m£3.2m£3.6m£2.9m£3.4m£3.9m£4.0m£3.7m
Payments−£3.9m−£4.4m−£3.2m−£3.2m−£4.0m−£3.3m−£3.4m−£3.7m−£4.1m−£6.4m−£3.0m−£3.2m−£3.5m
Closing£6.8m£5.4m£5.9m£6.1m£5.0m£5.7m£5.4m£5.3m£4.1m£1.1m£1.9m£2.8m£3.0m
Headroom£4.8m£3.4m£3.9m£4.1m£3.0m£3.7m£3.4m£3.3m£2.1m−£915k−£57k£775k£988k
v forecast+£122k−£271k+£128k

Primitives

ui

src/components/ui/ (primitives)

The primitives together, at the density the console actually uses them: a control bar, a figure column, the states a row can be in. Every interactive element shows rest, hover-equivalent, disabled and focus; focus is never transitioned.

a control bar

4 selected · £814,600

unavailable, with the reason in the title

the focus ring, on every control

what a row can say about itself

ApprovedAwaitingHeldReturnedClearedIn flight

a money column, tabular by construction

£1,842,300£90,514£2,486up £124,000down £41,800

Money

src/components/ui/money.tsx

A figure a reader compares is tabular; the one hero figure at the head of a card is not. Direction is never colour alone — every delta carries an arrow whose angle means what the colour means, and zero gets its own glyph.

DisplayFigure

£4,352,940

Figure — tabular

£1,842,300£90,514£2,486

Delta

up £124,000down £41,800unchanged £0up 4.2%

DualFigure — foreign currency

€1,236,410£1.1m$612,880£485k

Button

src/components/ui/button.tsx

Every state is a token, never an alpha modifier: the hover and active steps move lightness in the direction that raises the label's contrast, and they move a different way in each mode.

variants

Open forecast

sizes

disabled and pending

Badge

src/components/ui/badge.tsx

Status colour is reserved: it is never a chart series and never a brand surface. Every badge carries an icon whose shape differs from its neighbours', so the row still reads with the colour removed. 'Awaiting' is deliberately not a status colour — it is the absence of a decision, not a warning.

payment state

ApprovedAwaitingHeldReturned

tones

ClearedIn flightApproved

covenant

Covenant held across the windowBelow the floor in w/c 5 Oct

Eyebrow and FigureLabel

Operations

Liquid today

Panel

src/components/ui/panel.tsx

The console's one container: a hairline, a card ground, one radius, and no shadow. Every header carries a mark, because on a route with six panels of identical weight the icon is what lets the eye find the table it wants. A coloured ground is earned — it appears only when the panel is reporting a condition this theme already colours.

Panel with a header and actions

Meta line — what the panel is of

Panel body.

The quiet strip: one clause, and the rest behind the mark.

A header that earned its colour

Only when the panel reports a condition the theme already colours

€356,400 is past terms. The ground is the critical soft, the same one the Overdue badge takes, because the panel is that status — not because a header wanted decorating.

PageHeading

Small on purpose — on a console the page title is a wayfinding label, and the largest thing on screen should be a number the reader came for.

Table

src/components/ui/table.tsx

Numeric columns are right-aligned and tabular in one decision, because separating them is how a column ends up right-aligned with proportional digits. The empty state names the filter that produced it — an empty result is not an empty run.

rows, totals

BeneficiaryAmountState
Solvay Chemicals BV€612,400Approved
Brenntag UK£286,400Awaiting
Total£814,600

empty

No held instructions

The run has 12 instructions in it. Nothing matches this filter — the run is not empty, the view is.

DashboardLayout

src/components/ui/dashboard-layout.tsx

Three navigation planes, picked in the header and remembered. The theme shipped two for a day on the argument that a desk uses one shape — which was right about the desk and wrong about the buyer, who is building their own console and needs the shell to be the part they can decide.

sidebar

Header

Main

rail

Header

Main

topbar

Top bar

Header

Main

the picker itself

Navigation layout

Sections

AppShell

src/components/app-shell.tsx

Navigation, the freshness line, and the covenant count riding the Forecast item — a standing fact in a standing place, never a dismissible notification. Rendered here at panel scale; on a route it claims the viewport.

Cash position

Balances as at 09:14 on 27 Aug

The route’s own content.

AccountIndex

src/components/account-index.tsx

The page's top edge on / — hero archetype A9. The column that makes it an index rather than a list is 'what it is for'.

Where the money is

Seven accounts · five banks · three currencies

AccountCleared
Lloyds · Operating£1,842,300
Lloyds · Deposit£3,500,000
BNP Paribas · Operating EUR€1,236,410£1.1m
BNP Paribas · Collections EUR€864,220£745k
Wells Fargo · Operating USD$612,880£485k
HSBC · Duty deferment£248,600
Handelsbanken · Payroll£905,140
Total, sterling equivalent£8,792,595
Converted at this morning’s fix, not a live feed.

PositionSummary

src/components/position-summary.tsx

Each card is one number, its movement, and one clause saying what it excludes — the part most stat rows leave out and the part a treasurer needs.

Position summary

Liquid today

£5,043,995

up £225,780this week to date

£3,748,600 on notice or ring-fenced, and not counted here

Committed, not yet moved

−£1,536,707

 

Payroll, duty deferment and the approved half of run R-2634

Releases Thursday

−£1,429,920

 

Two held items and one returned item are outside this figure

Lowest week in the window

£1,084,780

down £915,220against the floor

w/c 5 Oct, and 1 more under the floor

Thirteen weeks from w/c 3 Aug

Trough £1,084,780 in w/c 5 Oct · floor £2,000,000

Below the floor in 2 weeks, from w/c 5 OctOpen the forecast
  • Closed — banked
  • Open — forecast
  • Below the £2.0m floor

MovementsTable

src/components/movements-table.tsx

Movements, last two days

8 entries · newest first

DateEntryAmountState
27 Augw/c 24 AugCustomer receiptIneos Compositesup £842,000Cleared
27 Augw/c 24 AugPayroll fundingHandelsbanken sweepdown £882,000In flight
26 Augw/c 24 AugCustomer receiptCroda Europeup €416,000Cleared
26 Augw/c 24 AugDuty defermentHMRCdown £248,600In flight
25 Augw/c 24 AugSupplier paymentSolvay Chemicals BVdown €182,400Cleared
25 Augw/c 24 AugFX settlementLloyds Marketsup $392,000Cleared
24 Augw/c 24 AugCustomer receiptSynthomerup £624,000Cleared
21 Augw/c 17 AugSupplier run R-263342 beneficiariesdown £2,914,000Cleared
In flight means posted, not settled.

PaymentRun

src/components/payment-run.tsx

The theme's state surface: selection, a filter whose empty state names itself, an approval that leaves a durable receipt rather than a toast, a hold that carries its reason, and a permission boundary written as a sentence.

Supplier run R-2634 · releases Thursday 27 August

£1,429,920

12 instructions · 2 awaiting approval

You can approve individual instructions. Releasing the run needs a second signature — Paul Osei, Financial controller — under the two-eyes policy for runs above £250k.

Instructions

Filtered: All

SelectBeneficiaryAmount
Not selectable in this stateSolvay Chemicals BVINV-88214 · caustic soda Q3Approved€612,400£528k
Not selectable in this stateWarrington Borough CouncilBusiness rates, SeptApproved£48,200
Brenntag UKINV-31907 · solvent recoveryAwaiting£286,400
Not selectable in this stateKuehne + NagelFreight, week 34Approved€121,800£105k
Not selectable in this stateRedhill EngineeringPO-4471 · reactor sealsHeldGoods receipt not matched — 40 of 60 seals£89,400
Not selectable in this stateUnivar SolutionsINV-77301 · glycolApproved$194,200£154k
Not selectable in this stateSellafield AnalyticsQ3 testing retainerApproved£31,500
Aker Insulation ASINV-2211 · plant laggingAwaiting€73,600£63k
Not selectable in this stateNorthgate Vehicle HireFleet, AugustApproved£22,800
Not selectable in this stateEllesmere Port TerminalsStorage, Aug — disputed volumeHeldVolume queried with the terminal, 18 Aug£117,000
Not selectable in this stateGrieg MaritimeCharter, MV TorstenApproved$241,000£191k
Not selectable in this stateHays Specialist RecruitmentContract shift cover, wk 33–34ReturnedBeneficiary account closed — new details requested£56,400
Held and returned instructions are outside the release figure.

AccountStatement

src/components/account-statement.tsx

Lloyds · Operating

£1,842,300

GB29 LOYD 3096 5502 2201 14

Uncleared
−£318,422
Projected
£1,523,878
This week
up £124,000
Group horizon
Receipts in, supplier run out · counts towards the covenant

Statement

4 entries · running ledger balance, in the account's own currency

DateEntryAmount
27 AugPayroll fundingHandelsbanken sweep · in flightdown £882,000
27 AugCustomer receiptIneos Compositesup £842,000
24 AugCustomer receiptSynthomerup £624,000
21 AugSupplier run R-263342 beneficiariesdown £2,914,000
Ledger balance, so it leads the bank by £882,000.

Queued against this account

6 instructions · £595,300

  • Warrington Borough Council

    Business rates, Sept

    £48,200

    Approved

  • Brenntag UK

    INV-31907 · solvent recovery

    £286,400

    Awaiting

  • Redhill Engineering

    PO-4471 · reactor seals

    £89,400

    Held

  • Sellafield Analytics

    Q3 testing retainer

    £31,500

    Approved

  • Northgate Vehicle Hire

    Fleet, August

    £22,800

    Approved

  • Ellesmere Port Terminals

    Storage, Aug — disputed volume

    £117,000

    Held

Open the payment run to approve or hold.

CounterpartyDetail

src/components/counterparty-detail.tsx

One name, both ledgers, one net. A disputed invoice is in the exposure and out of the forecast — it counts against the credit limit because the money is still ours, and it is absent from the horizon because we cannot name a week we expect to bank it.

Rotterdam, NL · EUR · 45-day terms

Solvay Chemicals BV

Customer and supplierTrading since 2019 · Marieke de Vries · credit control

They owe us

€701,100

£605k

We owe them

€612,400

£528k

Net exposure

€88,700

in our favour

Receivable against a €750,000 credit limit

93% used · €48,900 of headroom

Supplier and customer — the exposure nets.

Which weeks this name moves

The thirteen-week horizon, with only this counterparty's weeks marked

3 Aug

10 Aug

17 Aug

24 Aug

31 Aug

7 Sep

14 Sep

21 Sep

28 Sep

5 Oct

12 Oct

19 Oct

26 Oct

  • Money in, above the line
  • Money out, below it
  • 4 of 13 weeks touched
The €72,400 dispute is not in here.

Ledgers with this name

45-day terms · EUR throughout

InvoiceDueAmount
BC-4471compound BX-40, 12tOverdue11d16 Augw/c 10 Aug€284,000£245k
BC-4488compound BX-40, 8tOpen11 Septw/c 7 Sep€196,500£169k
BC-4502compound BX-55, 6tOpen28 Septw/c 28 Sep€148,200£128k
BC-4460compound BX-40, 3tCertificate of analysis rejected on batch 22-114; retest booked for 2 SeptemberDisputed2 Augoutside the window€72,400£62k
Outstanding€701,100
Disputed invoices are in this total.

Ageing

Against 45-day terms, as at 27 Aug

current
€344,700
1-30d
€356,400
31-60d
60+d
€284,000 is 11 days past terms.

Console menus

src/components/console-menus.tsx

Every standing condition is derived — the covenant count from breachWeeks(), the overdue receivable from the sales ledger, the approval count from the run. Nothing here is dismissible: these are conditions, not events, and a dismiss button teaches people to clear the list rather than the condition.

Exposure charts

src/components/exposure-charts.tsx

No hex reaches a recharts prop — every series is a CSS variable, which is why a rebrand recolours the charts and why both modes are right without a second chart config. Every chart has its numbers in text one disclosure away.

Closing liquidity, thirteen weeks

Group, sterling equivalent · the dashed line is the covenant floor

The same thirteen figures, as text
WeekClosingAgainst the floor
w/c 3 Augclosed£6,832,000£4,832,000
w/c 10 Augclosed · Q3 VAT, £1.42m£5,394,000£3,394,000
w/c 17 Augclosed£5,876,000£3,876,000
w/c 24 Augforecast · Run R-2634 goes Thursday£6,101,780£4,101,780
w/c 31 Augforecast · August payroll, £882k£4,975,780£2,975,780
w/c 7 Sepforecast£5,679,780£3,679,780
w/c 14 Sepforecast£5,422,780£3,422,780
w/c 21 Sepforecast£5,314,780£3,314,780
w/c 28 Sepforecast · September payroll£4,132,780£2,132,780
w/c 5 Octforecast · EIB development loan, €4.10m£1,084,780−£915,220
w/c 12 Octforecast£1,942,780−£57,220
w/c 19 Octforecast£2,774,780£774,780
w/c 26 Octforecast£2,987,780£987,780
Three weeks closed, ten forecast, no facility assumed.

Receipts and payments by week

What comes in against what goes out — the shape behind the closing line

Green in, red out.

Currency cover, next thirteen weeks

Net position by currency, sterling equivalent, split by what is already bought

The open leg still moves with the rate.

Positions and marks

Struck rate against this morning's fix

CurrencyNet positionHedgedCoverMark
EURNet payer−€4,128,000−€3,300,00080%−£47,190
USDNet receiver$1,284,000$640,00050%−£6,976
Policy is 75% on a net payer; USD is under it by decision.

Popover · Hint

src/components/ui/popover.tsx · ui/hint.tsx

The control behind this theme's helper rule: a panel's helper text is one clause, and the reasoning lives one press away. A popover and not a tooltip, because this holds sentences — a tooltip is for a label too short to fit, is unreachable on touch, and is hostile to a screen reader when it holds a paragraph.

the surface

in place — a helper line and its hint

Converted at this morning’s fix, not a live feed.

DropdownMenu

src/components/ui/dropdown-menu.tsx

Behaviour vendored from tt-ui 1.4.0; every class is this theme's. The hover surface is the achromatic accent, because a tinted row would be the only brand-coloured surface on a screen whose argument is that colour means money — and a disabled row keeps its reason under the list, where an explanation long enough to be useful actually fits.

the surface, opened

live — drive them

Dialog

src/components/ui/dialog.tsx

The console's own card, raised by one shadow token and stopped behind a neutral scrim — no bounce, no scale-up from nothing. The width is `surface`'s and the ground is `panel`'s, which is what lets the photograph below sit at the live width instead of a layer's.

the surface, no layer

live — open it

ConfirmDialog

src/components/ui/confirm-dialog.tsx

`ui/dialog`'s recipe plus three slots for the typed gate, so there is one dialog appearance in this theme rather than two that drift. What is typed is the run's own id — the second signature is a policy this product printed on three routes and never actually asked for.

the surface, gate unsatisfied

This needs the second signature

3 instructions · £441,900

Above £250,000 the two-eyes policy applies: Paul Osei, Financial controller, countersigns before the run releases. Approving here records both names against these instructions.

live — the run's own gate

Tabs

src/components/ui/tabs.tsx

Selection is a 2px rule under the tab, not a pill: every other selected thing in this console is identified by a ground, and a fourth ground would make the strip compete with the panel it sits in. The travelling indicator stays off — it measures wrong for one frame on mount, and these strips are at the top of a panel that renders on load.

the strip, at rest

Four open invoices, one of them disputed.

a tab out of play

Four open invoices.

live — the counterparty's three ledgers

€701,100 open, €284,000 of it past terms.

Field

src/components/ui/field.tsx

The label is always there and never a placeholder. The supporting line and the message share one row, so a field does not grow when it fails — a form whose rows jump as they validate moves the control the reader was about to fix.

rest

What the month-end hold report counts this under.

invalid

Choose the category this hold is counted under.

valid

Checked against the bank's directory this morning.

read-only

Set when the run opened; it cannot be changed from here.

disabled

Assigned by policy, not by this form.

Form

src/components/ui/form.tsx

Not a visible object — a `<form>` around fields that already know how to look. `core/form` owns the flow: validate on submit, focus the summary or the first invalid control, keep every valid value, disable the fieldset while in flight, refuse a second submit, and name where focus goes when the receipt arrives.

live — submit it empty, then fill it

What the month-end hold report counts this under.

FormErrorSummary

src/components/ui/form-error-summary.tsx

The only alert region in the theme, and the one panel a failed submit puts focus into. The links are underlined rather than coloured-and-bare: everything in this list is already critical, so colour cannot also be what says clickable.

two fields still owed

SearchInput

src/components/ui/search-input.tsx

The console's field, sat on the list it searches rather than in the shell's header — a search 200px above its own results is a worse control even when it works. The clear is a real button with a name that returns focus to the input; WebKit's native one has none of the three, so it is hidden.

live — type, then clear it

rest

filled

1 of 12 instructions match \u201csolvay\u201d

no result

0 of 12 instructions match \u201cineos\u201d

disabled