Cross-border freight: 140 open consignments, their customs status, and the ones that have stopped.
Direction
| Lever | Decision |
|---|---|
| Archetype | Shell. Ant Layout.Sider at 208px, collapsing to a 64px icon rail under 992px; one scroll region for the table. |
| Data stance | Table-first at maximum density. Fourteen columns, the checkbox and the reference frozen, the horizontal scroll held inside the table. Filters live in the column headers. |
| Density | Ant small: 8px cell padding on 14px text, 43px rows measured, 24px header controls, 32px page controls. |
| The bold thing | An exception is a sentence, not a colour. The row keeps its own background and gains a second line naming what stopped it. That sentence is sticky: past the frozen columns on a desktop, and at the left edge of the scroll box below 992px, where it wraps to as many lines as it needs. |
Generator
ant_palette.py "#0B5FFF" # tokens.css (committed, never edited)
ant_palette.py "#0B5FFF" --contrast # the audit, below
ant_palette.py "#0B5FFF" --dark # the ramp under the dark algorithm
ant_palette.py --map # neutrals, status, dimensions, motion
ant_palette.py --map --dark
ant_palette.py --presets # the gray ramp, which is special-cased
tokens.css holds the seeded ramp alone. tokens.support.css holds everything else and is generated the same way: a script reads the four commands above and emits it, so nobody typed a value into either file.
The contrast audit, and what it changed
step hex on white on black use
5 #3381ff 3.67:1 5.72:1 hover state of the primary
6 #0b5fff 5.13:1 4.10:1 THE primary — colorPrimary
7 #0045d9 7.36:1 2.85:1 active / pressed
Step 8 (text) on white: 9.88:1 passes 4.5:1
White on step 6 (primary button): 5.13:1 passes 4.5:1
- White on step 6 passes at 5.13:1, where Ant's own
#1677fffails at 4.10:1. The primary fill carries text unchanged and needs no darker step. - The hover does need one. Ant lightens a primary button to step 5 on hover, which drops white text to 3.67:1. Hover is step 7 (7.36:1) and pressed is step 8 (9.88:1) instead, so the label holds AA through the whole press.
- Ant's Tag pairs step 7 on step 1 and three of the five hues used here fail: green 3.37:1, cyan 3.39:1, gold 4.25:1. Every tag reads step 9 on step 1, which measures 5.44:1 (green), 5.83:1 (cyan), 6.53:1 (gold), 7.04:1 (red) and 10.94:1 (geekblue).
colorBorderis 1.41:1 on white and bounds every control. The generator's gray ramp replaces it, picked by rule rather than by eye: the first step clearing 3:1 against that theme's container — gray 3 (#8c8c8c, 3.36:1) in light, gray 7 (#6a6a6a, 3.41:1) in dark.
- Target size (SC 2.5.8). Row checkboxes are 16px, which the spacing exemption carries: 43px between vertical neighbours and 40px to the reference link. The empty saved view carries no select-all, since a table with no rows has nothing to choose — and that also removes the only pair of 16px targets whose centres fell inside 24px of each other.
- The empty saved view carries no filter and no sort either, on the same argument, and it had to: those four controls shared ids and handlers with the open table above, so filtering from the empty header re-sorted and re-filtered a table 660px off the top of the screen while opening its popover at
top: -193px, where nobody could see it.
- Measured at 390px: the sentence wraps to six lines and 100% of it is visible, sticky at the left edge of the scroll box. Before the critique round it was one 1264px line inside a 308px box — 9% of it showed.
Deviations from CONTRACT.md
- A second generated stylesheet.
tokens.csscarries only the ten brand steps, and a page needs neutrals, status hues, spacing, type, radius and motion. Those come fromant_palette.py --map,--map --darkand--presetsthrough a script intotokens.support.css, rather than being written into the page as raw values. - Ant ships no typeface, so the page loads no web font and uses the
fontFamilyandfontFamilyCodeseeds verbatim.