orenbj.com

Design System

Two stylesheets and one rule about when not to use them. This page is built from the system it documents — every example below is a live element, not a screenshot.

How it is put together

brand.css holds the tokens and the header styles. The build stamps both into every page, so the bar is in the HTML on first paint rather than waiting on a script — which matters on a page whose head loads a blocking CDN script.

ui.css is the component layer, opted into per page. Build a page from these classes and it matches the home page by construction, and inherits the contrast results below rather than re-earning them.

The build stamps the header and brand.css into every page. A page that wants the component layer adds one line:

<link rel="stylesheet" href="/assets/ui.css">

Colour

One dark ground, three accents drawn from a single gradient. Contrast was measured against --ob-bg, not estimated; the lowest result on the site is 7.4:1 against a 4.5:1 requirement.

Ground--ob-bg · #030712
Surface--ob-surface · card fill
Text--ob-fg · 19.3:1
Muted text--ob-muted · 7.9:1
Orange--ob-orange · 8.9:1
Purple--ob-purple · 7.6:1
Blue--ob-blue · 7.9:1
Gradient--ob-gradient · display only

Purple is the interaction colour: hover, focus, and the primary button. Orange marks the thing you are on. Blue is reserved for the gradient and the particle field. Keeping those roles fixed is what stops the palette reading as decoration.

Type

System UI throughout — it costs no request, renders natively on every platform, and a personal site does not need a webfont to have a voice. The gradient display face is the one bold move, reserved for a page title.

Oren Ben-Joseph

Section heading — .ob-h2

Subsection — .ob-h3

Lead paragraph, one step up from body copy.

Body copy sits at the browser default, with a measure kept near 65 characters so a line stays readable.

Small print and captions — .ob-small .ob-muted

Tabular figures 1,204,880 · 3,957 KB · 19.3:1

Cards

A card animates on hover only when it is a link or a button. A static card that lifts under the cursor promises an interaction it does not have, so .ob-card stays still and a.ob-card moves.

Interactive card

An a.ob-card — lifts, borders purple, and goes somewhere.

Static card

A plain .ob-card — holds still, because nothing happens if you click it.

Controls

One focus treatment across every control: a two-pixel purple outline, offset so it never crowds the element it marks.

Data

Figures line up with tabular numerals and numeric columns align right, so a column can be scanned rather than read. A wide table scrolls inside .ob-table-scroll instead of pushing the page sideways.

PageSelf-hostedThird-partyStatus
Census Mobility Map1,660 KB0 KBBundled
3-Lane LA898 KB0 KBVendored
Metric Equinox144 KB509 KBExempt
Transit Fares27 KB731 KBRebuild
DiSC Assessment72 KB3,957 KBRebuild

Which pages adopt it

A shared look is worth having up to the point where it starts erasing what makes a project worth showing. The header and palette go everywhere. The component layer goes where pages are genuinely alike.

Home & 404 Source These are the brand; the tokens were taken from them.
3-Lane LA Header only A full-bleed map. Chrome places it on the site; the map needs nothing else.
Census Mobility Map Header only Same — a map application with its own control surface.
Metric Equinox Exempt Its decimal-time palette and type are the substance of the project. Flattening them into the site style would remove the reason it is worth showing.
Transit Fares Adopt on rebuild A dashboard of cards, controls and tables — exactly what the component layer is for.
DiSC Assessment Adopt on rebuild A form-driven tool. Same components, no bespoke styling needed.

Rules worth keeping

Accent roles are fixed. Purple means interactive, orange means current, blue stays decorative. A palette reads as a system when its colours mean something and as decoration when they do not.

Motion is optional. Everything that animates is wrapped in a reduced-motion query. The home page particle field settles to a static frame rather than stopping blank.

Contrast is measured, not judged. Every pair above was computed. Substituting an untested colour forfeits the result.

The gradient is spent once per page. On the title, and nowhere else.