Pumasi a commons of working software

Design

Console: the design system the whole Pumasi commons is built on. Monospace throughout, square corners, one accent in every product — with the tokens rendered live from the stylesheet in use.

Everything below is rendered from the same CSS custom properties the rest of this site uses. If a token is renamed and this page is not updated, this page breaks visibly. A style guide that can drift silently from its theme is worse than none.

One system, four surfaces#

This is not a website stylesheet that other repositories may borrow from. It is the design system for the commons — this site, Pumasi Sign, Pumasi Booking and Pumasi Tunnel — and the products are surfaces of it, not neighbours of it.

Before it was written down there were four palettes, four ideas of what a button was, and four corner radii; three of the four products had invented their own red because the shared theme had no failure colour at all. A reader arriving at a signing link from this site had no way to tell they were still in the same place.

The fix is one rule and one exception. The rule: the interaction colour is the same everywhere. --accent is green on this site, in Sign, in Booking and in Tunnel — every button, every link, every focus ring. The exception: each product carries a --signal — blue for Sign, clay for Booking, cyan for Tunnel — which marks which product you are in, on the mark and on one edge rule, and is never allowed near a control. Colouring by product is what made four brands in the first place.

The full written system, including the per-product themes and what an application surface is licensed to do differently, is DESIGN_SYSTEM.md in this repository. Everything below is the part of it this page can render live.

The idea#

Console. One typeface — the reader's own monospace — for headings, body and navigation alike. Square corners. Visible borders. Console punctuation: ## before a section heading, brackets around a navigation item, a block caret after the headline.

A commons whose whole argument is that it is legible to machines should look like the artefact it is. The site is a listing, a set of records, and a merge gate; setting it in the type those things are actually written in is the honest choice, and it happens to be where developer-facing design has landed.

Because there is one typeface, hierarchy cannot come from switching families. It comes from size, weight, rules and boxes — which is a constraint worth having, because it is impossible to fake emphasis with it.

Two files, one of them swappable#

/base.css is the structural layer: reset, layout, landmarks, accessibility, print. It holds not one colour, not one font and not one size — every visual decision is a token it reads.

/theme.css supplies those tokens, plus the components built on them. Swapping it swaps the design without touching a line of markup.

Tokens are named for their role: --accent, never --green. A token named for what it looks like has to be renamed when the look changes, which is how a theme layer stops being one. Green carries interaction here; amber carries in progress; those are the two states this project talks about most.

The pictures#

Every illustration is SVG generated at build time and inlined into the page. That buys four things at once: the drawing inherits the theme's custom properties, so one picture is correct in light and dark; there is no extra request at any size; it is sharp on every screen without a srcset; and the compositions are seeded from each page's own address, so every product and post has its own picture that is identical in every build.

Nothing drawn here has a curve in it, because nothing in the theme does.

A woven plot, seeded from this page's address. Change the address and the composition changes; rebuild the same page and it does not.

The marks#

Four marks, in /brand/, each on the same 32-unit grid with a 2-unit stroke and no curve anywhere. Every one was checked at 16 pixels before it was checked at 96 — which is why Booking's calendar has six cells and not thirty, and why the three product marks have deliberately different silhouettes rather than sharing the commons' brackets. Four bracketed glyphs would be indistinguishable in a tab strip.

Each file resolves its colours twice over: it reads the page's token when there is one, and falls back to a literal when there is not, with its own prefers-color-scheme block choosing which literal. One file is therefore correct inlined and correct in an <img>, in light and in dark — including the four architecture drawings, which are the same asset class at 960 units wide.

No web fonts#

A font request is a third-party request, a blocking paint and a layout shift, in exchange for a typeface most readers will not consciously notice. This theme wants the reader's own monospace in any case — the one they already read code in — so the stack is the one their device ships with.

That is a decision, not a law. Self-hosting one face would be a single file and one token change.

There is a second stack in the theme, --font-ui, and nothing on this site uses it. It is for the product applications, where a forty-row table set in monospace costs real columns. Those surfaces move --font-body to it and leave --font-display where it is, so every heading, label and number stays in the console face. The brand lives where the eye lands first; the density lives in the rows.

Colour

Every pair used for text meets WCAG AA in both schemes. Switch your system between light and dark and this page repaints — there is no toggle here, because there is no JavaScript here, and the operating system already knows the answer.

Neutrals

Warm, never grey-blue. Named by role, so a repaint does not require a rename.

--paper
--paper-raised
--paper-sunken
--line
--line-strong
--ink-faint
--ink-muted
--ink
--ink-strong

Accent — the one colour

Links, the primary action, and exactly one emphasis per view. One accent is a constraint, not a shortage: it means the accented thing is always the thing to do next.

--accent
--accent-strong
--accent-soft
--accent-line
--accent-contrast

Warn — in progress

Anything provisional: a limitation, a caution, a maturity that is not yet stable.

--warn
--warn-soft
--warn-line

OK — settled

Anything verified: a passing gate, a stable release, a machine affordance that works.

--ok
--ok-soft
--ok-line

Danger — failed, or destructive

Anything that failed or that destroys something. New in the v1 system: its absence is exactly why three products each invented their own red.

--danger
--danger-soft
--danger-line

Product signals — identity, never interaction

One hue per product, matched at roughly 6:1 on paper. A signal marks which product a surface belongs to — the mark, one edge rule, the live path in a diagram — and never colours a control. The thing you click is green in all three products, which is the whole reason these exist.

--signal-sign
--signal-booking
--signal-tunnel

Illustration

Fills for the art system. Tuned to sit behind text without competing with it.

--art-ground
--art-1
--art-2
--art-3
--art-4
--art-ink

Type

System stacks only, and on this site one of them: the reader's own monospace, for headings, body and navigation alike. No font is fetched, so nothing blocks the first paint and nothing shifts after it. JetBrains Mono and Geist Mono are named first, so a developer who already has one installed gets it for free.

A second stack, --font-ui, exists in the theme and is used by nothing here. It is for the product applications — a signing canvas, a calendar grid, a request log — where a forty-row table in monospace costs real columns. Those surfaces move --font-body to it and leave --font-display where it is, so the console voice stays in every heading, label and number.

Every step is fluid — clamp() between a phone and a desktop — so the scale never needs a breakpoint to stay readable.

--text-3xl
A commons of working software
--text-2xl
Built by agents, governed by people
--text-xl
What actually exists
--text-lg
The merge gate, in four requirements
--text-md
A lede: slightly larger than body, and quieter.
--text-base
Body text. The measure is capped so a line never outruns the eye.
--text-sm
Metadata, captions, and the footer.
--text-xs
LABELS AND BADGES

Space

A 4px base on roughly a 1.5 ratio. A one-off value is a bug.

--space-3xs
--space-2xs
--space-xs
--space-sm
--space-md
--space-lg
--space-xl
--space-2xl

Components

The pieces this site is assembled from, rendered live.

Buttons

Four ranks, and a screen is allowed exactly one primary. Every rank keeps the prompt caret, so a quiet button still reads as the same kind of object as a loud one. Danger is outlined rather than filled: a delete button that is the loudest thing on the screen gets pressed by accident.

Primary Secondary Tertiary Delete

Small Large Disabled

The stage ladder

One badge, five rungs, the same object in every Pumasi repository. The brackets are drawn by CSS and never typed. The ladder gets louder as the claim gets stronger — [LAUNCHED] is the only filled badge in the system, so it cannot be reached by accident.

planned seed alpha beta launched

Elevation

Four steps, and this surface spends none of them on blur: a thing that is higher here is higher because its border is heavier. The application layer re-expresses the same four steps as real shadows, because a menu opening over a table has to look like it is floating. Same tokens, same markup, different surface.

Card

Elevation 2. The commons' one container: square, one visible border, and its whole hover state is that border going accent.

Signal card

The same card with one edge rule in a product's signal colour. A card is identified along one edge and nowhere else.

Callouts

Warn — in progress. Used for a limitation a reader must know before adopting something.
OK — settled. Used for something verified: a gate passed, a claim checked.
Accent — attention. Used sparingly, and never twice on one screen.

The marks

Every mark is a 32-unit grid, a 3-unit margin, a 2-unit stroke, and no curve anywhere — because nothing in this theme has one. Each was checked at 16 pixels before it was checked at 96, which is why Booking's calendar has six cells and not thirty. Exactly one element per mark is saturated, and it is that product's signal.

The Pumasi lockup: the bracketed mark beside the wordmark.

The Pumasi commons mark: three bars of unequal length inside a pair of brackets.
commons
The Pumasi Sign mark: a page with a turned corner and a diamond seal.
sign
The Pumasi Booking mark: a calendar of six cells with one taken.
booking
The Pumasi Tunnel mark: three lanes collapsing into one outbound stream.
tunnel

Each file resolves its colours twice: it reads the page's token when there is one, and falls back to a literal when there is not — with its own prefers-color-scheme block choosing which literal. So one file is correct inlined and correct in an <img>, in light and in dark. The architecture drawings work the same way: commons, sign, booking, tunnel.

Taking the theme

Tokens are named for their role — --accent, never --green. A token named for what it looks like has to be renamed when the look changes, which is how a theme layer stops being one. Another Pumasi product can link this file and inherit the palette, the type scale and the spacing without inheriting this website's layout:

<link rel="stylesheet" href="https://pumasi.ai/theme.css">
<link rel="stylesheet" href="https://pumasi.ai/base.css">
<link rel="stylesheet" href="https://pumasi.ai/brand/product-theme.css">
<body data-product="sign">

The third file is optional and is for applications rather than documents: it moves body text to the proportional stack, turns the four elevation steps into real shadows, and adds the form controls a website does not have. It changes no colour, no type scale and no corner. data-product binds --signal, and a signal never colours a control.

Or copy the file. It is Apache-2.0, it has no dependencies, and it is under three hundred lines. Copying it is the expected thing to do — this is a commons, and a vendored copy that cannot break when someone else deploys is worth more than a shared URL that can.