Console — the system
One set of markup, two palettes. Every colour below is a token, so the light and dark artboards on this canvas are byte-identical except for the twelve lines that define the palette. Status hues and the violet accent are the values already shipping in ClickPay’s token file.
Type
Screen title
Restock
17 / 600 / -1.5%
Section
Inventory
14 / 600
Nav item
Marketplaces
12.5 / 400
Table cell
Coil Spring Toy, jumbo
12 / 400
Figure
4,000 $7,120 28.1%
Plex Mono, tabular
Column head
Order qty
10 / 500 / 6% caps
Band label
Decision
9.5 / 10% caps
Controls — 28px, one step tighter than today’s 32
Create PO
Export
Disabled
Delete
Received
Landed
138d late
Staged
Dismissed
⌘K
esc
g i
Table
|
UID |
Product |
Cover |
Runway |
Order qty |
Value |
| ▣ |
PB038 |
Coil Spring Toy — selected row |
6d |
|
4,000 |
$7,120 |
| □ |
PB224 |
Therapy Putty — default row |
34d |
|
— |
— |
| □ |
SW043 |
Baby Scale Tray — healthy row |
128d |
|
— |
— |
row 26pxcell pad 0 / 10head 10px capsdivider edge2band divider on group changefigures right, tabular
A column is never narrower than the value it holds
A figure that renders as 184,2… is worse than no figure at all: it reads as data while being unreadable. Column widths are therefore derived, not chosen by eye — each one is sized from the widest string its formatter can produce, plus the 10px padding either side, plus the uppercase header label, which is often the widest thing in the column.
When the derived widths will not fit the window, columns come out — they stay reachable through the Columns control and the horizontal scroll — rather than every column shrinking until the numbers break. Only free text may ever truncate, and it truncates with the full value on hover.
What the density buys
today, 36px rows18 rows
console, 26px rows27 rows
Half again as many products in view before scrolling, on the same 900px window — and the column bands mean 42 columns can stay available without reading as one undifferentiated run.
Added after the first round
Six rounds of revision added five controls and four patterns that appear on more than one screen. Anything used twice belongs here, or the next screen invents its own version of it.
The two filter exits
where
The filter bar of all 22 tables, immediately after the last chip.
save as view
Keeps the filter. Appears in the context column under Saved views with a live count. Writes nothing, ever.
make a rule
The same filter, but it acts. Arrives pre-filled and stays bound to the filter — edit one, the other follows.
A filter you cannot keep is a filter you retype. One fork, one place, every table.
Three temporal controls, not one
window
A measurement over a span. Always carries what it is compared against, and an amber dot while the range includes days whose fees have not settled.
event date
A record with several dates of its own. Asks WHICH date before the range, because a PO is ordered, expected, received and closed.
basis window
Changes a computed figure rather than filtering rows. Move Restock’s velocity window and the reorder quantity moves with it.
21 screens carry one of the three. Rules, the tab map and this sheet carry none, because nothing on them is a measurement.
The sidebar is yours
resize
Drag the right edge: 148px to 320px. Remembered per person, not per screen — a navigation width that changes as you move screens is worse than no setting at all.
collapse
The chevron in the heading folds it to the 56px rail. The content area takes the 188px, which on a 1440 board is the difference between scrolling a table and not.
peek
While collapsed, hovering the rail slides the column out at the width you dragged it to — overlaying the content, never pushing it.
Peek overlays on purpose. If it reflowed, the table would jump sideways every time the cursor crossed the rail and the row under the pointer would move out from under it.
When a row opens
aligned sub-rows
Only when the children are the same shape as the parent — a purchase order’s lines, a run’s actions. They sit under the parent’s own columns and are part of the same table.
a detail panel
When they are not. Restock’s velocity derivation, a per-marketplace grid and a 21-month forecast have no business pretending to be columns, so the panel breaks the grid completely and the parent stays a row.
never a nested table
A nested <table> silently breaks every column measurement in the repo, so the guard refuses to build one.
Getting this wrong is what made the first Restock panel unreadable.
What the AI is allowed to do
it proposes
An agent reads and proposes. Not one of the eight has write access to a marketplace, and the permission columns exist so that can be checked rather than believed.
a rule writes
Every path to Amazon runs through the same rule, the same read-back and the same three gates as a hand edit. There is no second path.
it shows its evidence
Every answer carries the rows it came from, every rewrite arrives as a diff, and what it refused to do is listed next to what it did.
An AI that never says no is one you have to check line by line anyway.
An empty table
four causes
Nothing yet, nothing matched, something broke, not permitted. Only the first is benign, so they must not look alike.
name the filter
An empty result is a fact about the filter. The condition doing the excluding is named.
a red zero
A dead feed returns 0, and a grey blank would read as “no shipping”. It is drawn in red.
A number you do not have
skeleton
Real column heads, unknown values, real row height so nothing jumps.
stale
Fourteen-minute-old values beat a spinner — but only labelled. An unlabelled stale number is worse than none.
partial
A partial total is a wrong total, so it is withheld rather than shown.
A bulk action
per row
Before and after for every selected row, plus the total change. A count is not a consequence.
the exception
Rows where the action means something different — the only active campaign for an ASIN — are flagged in the list.
A failure
what survived
Six of nine applied and kept. Calling that “failed” would be a lie about six of them.
success is not enough
A 200 with an empty payload and no change on read-back is recorded as a failure. It is the worst error class there is.