01 / Thesis
Black
The screen is a dark desk. Every number your payroll depends on is set on a white plate laid on top of it.
The one rule
Black is the desk. White is the paper.
Product data — punches, exceptions, approvals, revisions, Acumatica IDs — is always set on a white plate, never on the black ground. Colour exists only on paper, and only as status. The black ground is monochrome, always.
Field Time is bought by an operations manager who has to defend a payroll run to a controller. A black ground is the least decorated surface there is: nothing sits on it but the wordmark, a headline and hairlines, so attention has nowhere to go except the paper. It also matches what the buyer already sees — the app tile is a black rounded square and the loader is a white rivet-d spinning on black, so the site, the icon and the product are one object.
The risk in black is that it reads as a developer tool. The defence is not colour: it is a large display face with real negative tracking, long vertical rhythm (128 px between sections), body copy at a comfortable 16 px with room around it, and monospace confined to data. Nothing glows and nothing is neon.
02 / Logo
The white wordmark is the only warm object on the page.
Outlined URW Gothic Demi with the rivet-d. Solid white on black, never tinted, never re-typed.
Clear space — c on all four sides
Solid hairline = the wordmark’s ink box. Dashed hairline = the clear-space boundary. Nothing — type, rule, image or plate edge — enters the gap.
c = 0.656 × wordmark box height
at 320 × 64 px wordmark → c = 42 px
Minimum sizes — wordmark 96 px wide, mark 16 px
96 px — minimum. Below this the rivet crown fills in.
Mark at 16 / 24 / 32 / 48 px. 16 px is the floor (favicon, table avatar).
App icon — the same d, the same black
The tile ships black-on-black against the site ground; the hairline above is the kit’s measuring outline, not part of the icon. Platform masks may replace the radius.
Don’t
03 / Typography
Three faces, three jobs, no overlap.
White on black gains apparent weight, so body copy stays at Inter 400 with a little positive tracking (+0.005 em) and never goes to 600 for running text. URW Gothic Demi is a display face only: 20 px floor, tracking tightens as size grows.
Display
Defend
URW Gothic Demi 600
/brand/fonts/URWGothic-Demi.woff2 · /brand/fonts.css
Headlines, stat figures, section headings. 20 px floor. Never body, never UI labels.
Body
Defend
Inter 400 / 500 / 600
Google Fonts · Inter
All running copy, buttons, labels, chips, table headers, anything under 20 px.
Data
8h 19m
JetBrains Mono 400 / 500
Google Fonts · JetBrains Mono
Times, durations, geofence distances, revision hashes, Acumatica IDs, token values. Nothing else.
| Role | Live sample | Size / line / track |
|---|---|---|
| display-xl | Time your payroll can defend. | 76 / 78 / −0.035em |
| display | Nothing reaches payroll unapproved. | 52 / 55 / −0.030em |
| h2 | One gate before export. | 32 / 36 / −0.022em |
| h3 | Exception-first approval | 18 / 24 / −0.008em |
| lead | Field Time captures punches offline and surfaces the exceptions. | 20 / 30 / −0.008em |
| body | A supervisor reviews the four sessions that need a decision, not the forty that don’t. | 16 / 26 / +0.005em |
| small | Built for Acumatica 2026 R1. No middleware, no mapping screens. | 14 / 22 / +0.005em |
| caption | Outside geofence · supervisor review | 11 / 13 / +0.100em |
| mono-data | 8h 19m · Stop 15:32 · 412 m · 381e…c4e2 · EP00012 | 13 / 18 / 0 |
Numerals — tabular everywhere, mono for facts
| Stat figures, display face | 2,250 |
| Body numbers, Inter | 7h 58m · 8h 04m · 7h 46m |
| Times, distances, IDs, hashes | 15:32 · 412 m · 381e…c4e2 |
font-variant-numeric: tabular-nums is on for every numeral in the system, so a
column of durations never shifts between renders. Anything a supervisor might compare, cite or paste is mono.
Tracking curve — it tightens as size grows
Below 20 px the display face is replaced, not shrunk: the rivet-crown d and the tight counters fill in.
04 / Colour
The chrome is monochrome. Colour is a product signal, not a brand asset.
Nine greys build the whole site. The four hues below only ever appear on a white plate.
Grounds
Ink ramp on ground · lines on ground
Status — on paper only
Measured contrast
| Body ink #ffffff on ground #000000 | 21.0:1 · AAA |
| Secondary #b8b8b8 on ground | 10.6:1 · AAA |
| Caption #8c8c8c on ground | 6.2:1 · AA |
| Paper ink #0b0b0b on paper | 19.7:1 · AAA |
| Paper secondary #52525b on paper | 7.7:1 · AAA |
| Exception on its tint | 6.1:1 · AA |
| Warning on its tint | 6.6:1 · AA |
| Ok on its tint | 5.6:1 · AA |
| Pending on its tint | 10.4:1 · AAA |
Every ramp step clears AA at body size. Display may sit at 3:1; nothing here needs the allowance.
When colour is allowed
- AllowedInside a white product plate, to carry a status a supervisor must act on: exception, warning, ok, pending.
- AllowedAs a 2 px left edge on a table row that is the exception — the same red, used structurally.
- NeverOn the black ground. No coloured text, rule, chip or button in site chrome.
- NeverAs a brand accent, a hover state, a link colour, or a fill for a surface.
- NeverTwo statuses in one row. If a session is both late and outside the fence, the exception wins.
05 / Spacing and layout
Base unit 4 px. Everything else is a multiple you can name.
Space is the only luxury in a monochrome system, so the vertical scale runs long: 128 px between sections at 1440, 96 px below 760.
Spacing scale · --s1 … --s10
Container and gutters
| Content container | 1200 px |
| Side padding · 1440 / 1024 / 390 | 32 / 24 / 16 px |
| Columns · gutter | 12 · 24 px |
| Applied fold inner width | 1120 px |
| Body measure | 64 ch max |
Radii · rules · elevation
Rules are 1 physical pixel: 1px solid var(--line), never scaled. Elevation is
one step and it is not a shadow — it is paper. A white plate on black is already the highest surface the
system has, so there are no shadows, no blurs and no layered borders anywhere.
12-column grid · 1200 px · 24 px gutter
Marketing folds use 12 / 7 / 5 or 6 / 6. Product plates ignore the grid and set their own internal 16 px rhythm.
06 / Components
Rendered, with every state showing at once.
Rest, hover, focus and disabled are shown side by side so a developer can match them without hunting.
Buttons — primary · secondary · ghost, three sizes
Focus is a 2 px white ring on a 2 px black offset, identical on every control; on paper the ring inverts to
#0b0b0b. It is never removed, only re-coloured.
Text link
Read the approval gate walkthrough before you configure export.
Hover: approval gate walkthrough
Focus: approval gate walkthrough
Links are white with a grey 1 px underline that goes white on hover. There is no link colour in this system.
Input · select
Fields sit on --ground-raised with a --line-2 hairline: on pure black an unfilled field would otherwise disappear.
Status chips — paper only
22 px tall, 3 px radius, Inter 500 at 12 px, 1 px border in the status line colour. The triangle is part of the exception chip, so the state survives a greyscale print of the approval record.
Nav bar
Product plate — crew table, Ana’s row is the exception
| Employee | Hours | Status |
|---|---|---|
| Ana Ropata | 8h 19m | ▲ Outside geofence |
| Tama Wiremu | 7h 58m | Approved |
| Ria Kōhere | 8h 04m | Approved |
| Hemi Walker | 7h 46m | Approved |
07 / Motion
Motion confirms a state change. It never announces one.
One signature: the rivet-d spinning on black. Everything else is 120–280 ms of opacity or 1–2 px of position.
| Token | Value | Used for |
|---|---|---|
--m-fast | 120ms | Hover, focus ring, chip tint |
--m-base | 200ms | Menus, disclosure, tab change |
--m-med | 280ms | Plate enter, row commit |
--m-slow | 400ms | Sheet, drawer, route change |
--m-story | 600ms | Hero and approval-gate sequences only |
--ease-out | .22,1,.36,1 | Anything entering |
--ease-inout | .65,0,.35,1 | Anything moving between two held states |
--ease-emph | .2,0,0,1 | The gate: approve, release, export |
Bar length = duration, 1000 ms full width. No bounce ease exists in this system.
Signature loader
The rivet-d turning on its own black ground at 96 px. It needs no container and no ring because the site ground and the loader ground are the same black. Used only for waits over 400 ms — an ingest replay, an export to Acumatica.
What moves · what never moves
- MovesChips when a status resolves, 200 ms opacity.
- MovesA row leaving the exception queue: 280 ms, ease-emph, it collapses rather than slides away.
- MovesThe loader, and only the loader, loops.
- NeverThe wordmark, the mark, the nav, or any number once rendered.
- NeverA page-load fade of the whole hero. The headline is there when the page is.
- NeverParallax, scroll-jacking, counters that tick up. Payroll figures do not animate.
Reduced motion
prefers-reduced-motion: reduce shows the resolved state, paused, never removed.
The loader becomes a single held frame of the d; the row-collapse becomes an instant re-render; every
transition drops to 1 ms. Nothing that carried meaning disappears — it just stops moving.
08 / Applied
The fold, built from the tokens above.
Nav, hero, evidence, one plate, footer. No image, no illustration, no colour outside the plate.
Time your payroll can defend.
Field Time captures punches offline, surfaces the exceptions, and lets nothing reach Acumatica payroll unapproved.
Built for Acumatica 2026 R1. No middleware, no mapping screens.
events accounted for after eight fault scenarios replay through the real ingest path
mapping screens. Acumatica employees, projects and appointments are the canonical IDs everywhere
gate before export. An unapproved session cannot become a Time Activity, technically.
- Stop
- 15:32
- Distance
- 412 m outside the fence
- Crew note
- “Walked to the van for fittings.”
- Approved
- 15:51 · M. Ropata
- Revision
- 381e…c4e2
- Released
- 16:00 → Acumatica
09 / Tokens
The whole option, copy-pasteable.
:root{
/* ground */
--ground:#000000; /* oklch(0% 0 0) the desk */
--ground-raised:#111111; /* oklch(18.4% 0 0) inputs */
--paper:#ffffff; /* oklch(100% 0 0) plate */
--paper-well:#f7f7f8; /* oklch(97.7% 0.001 286) */
/* ink on ground */
--ink:#ffffff; /* 21.0:1 on ground */
--ink-2:#b8b8b8; /* 10.6:1 */
--ink-3:#8c8c8c; /* 6.2:1 */
/* lines on ground */
--line:#262626;
--line-2:#3d3d3d;
/* ink and lines on paper */
--paper-ink:#0b0b0b; /* 19.7:1 on paper */
--paper-ink-2:#52525b; /* 7.7:1 */
--paper-line:#e3e3e6;
/* interactive — monochrome, no accent hue */
--action:#ffffff; --action-ink:#000000;
--action-paper:#0b0b0b;
--focus:#ffffff; --focus-paper:#0b0b0b;
/* status — white plates only */
--exception:#b42318; --exception-tint:#fef3f2; --exception-line:#f4cfcb;
--warning:#92400e; --warning-tint:#fdf6ec; --warning-line:#efdcbf;
--ok:#0f7038; --ok-tint:#edf7f0; --ok-line:#c9e4d4;
--pending:#3f3f46; --pending-tint:#f4f4f5; --pending-line:#e0e0e3;
/* type */
--display:"URW Gothic","Century Gothic",system-ui,sans-serif; /* Demi 600, ≥20px */
--body:"Inter",system-ui,-apple-system,"Segoe UI",sans-serif;
--data:"JetBrains Mono",ui-monospace,Menlo,monospace;
--t-display-xl:clamp(38px,6.4vw,76px); /* 1.02 / -0.035em */
--t-display:clamp(30px,4.2vw,52px); /* 1.06 / -0.030em */
--t-h2:clamp(26px,2.6vw,32px); /* 1.12 / -0.022em */
--t-h3:18px; /* 1.32 / -0.008em Inter 600 */
--t-lead:clamp(17px,1.5vw,20px); /* 1.50 / -0.008em */
--t-body:16px; /* 1.60 / +0.005em */
--t-small:14px; /* 1.55 / +0.005em */
--t-caption:11px; /* 1.20 / +0.100em uppercase */
--t-mono:13px; /* 1.40 / 0 tabular */
/* space — base unit 4px */
--u:4px;
--s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px;
--s6:32px; --s7:48px; --s8:64px; --s9:96px; --s10:128px;
--container:1200px;
--gutter:24px;
/* radii and rules — no shadows in this system */
--r-0:0px; --r-chip:3px; --r-control:4px; --r-plate:6px; --r-tile:22%;
--hair:1px;
/* motion */
--m-fast:120ms; --m-base:200ms; --m-med:280ms; --m-slow:400ms; --m-story:600ms;
--ease-out:cubic-bezier(.22,1,.36,1);
--ease-inout:cubic-bezier(.65,0,.35,1);
--ease-emph:cubic-bezier(.2,0,0,1);
}