Style guide
Everything the site is made of.
One page carrying every part in every state. The rules are in apps/web/app/globals.css and nowhere else: change a token or a class here and it changes on every page, because pages compose these parts rather than restyling them.
The five rules
- Every action is a button; every navigation is a link. If it does something — submits, opens the demo, starts the path — it takes
.btn. If it takes you somewhere to read, it stays a link. - One page shell.
<main>for a reading page,<main className="wide">for a marketing page,<main className="app">for the club, and each opens withsection.heroor anh1. - Controls are styled by element. An
input,select,textareaorbuttonneeds no class to look right; classes only say which kind of button it is. - Nothing is styled inline. No colours, sizes or spacing in the page — they belong to a token or a class.
- Write to the reader, not about the work. Say what they can do, in the order they would do it, in the second person. Why a thing works the way it does belongs in the wiki — unless they need it to make a choice (what is kept, what needs a licence, what costs nothing). Cut any sentence whose subject is we, the platform or this, and any comparison to a product they may never have used.
Colour
--bgpage--bg-raisedcard, control--bg-sunkenband, hover--inktext--ink-2secondary text--ink-3quiet text--linehairline--line-strongcontrol border--primaryaction--accenthighlight, the mark--accent-inksignpost line--okgood--warncaution--dangerbadEvery colour is a token, and every token has a dark value that the OS switches. Nothing in a page names a hex.
Roster workspace
Saved.
| Callsign | Role | Member since |
|---|---|---|
| N0CALL Example operator | Net control | Sep 7, 2026 |
Search above the roster; labeled rows on small screens; saving and connection status beside the work.
Type
Heading one, the page’s claim
Heading two, a section
Heading three, a thing within it
The lead: one paragraph under the heading that says what this page is for, in plain words.
Body text sits on a measure of 50rem so a line stays readable. Bold for the word that matters, an underlined link for somewhere to go, and code for a name from the machine.
Muted: the aside, the caveat, the row under a control.
The face is Atkinson Hyperlegible Next, served from this site and nowhere else: its zero is slashed the way a callsign is written — K02ABC reads as K02ABC in running text too — and it was drawn to stay legible at a small size on a phone.
Buttons
A link doing an action takes the same classes, so the two never look different: A link as a primary button
Form controls
A label is a block and its field sits under the text; fields that belong side by side sit in a .row and share the width. A text field and a choice are the same height, so the labels above a row of them line up. Two text-area heights, three rows and six, and no cols: the width comes from the layout.
Rows of controls
- Field Day · Sep 27, 2026, 2:00 pm · Prospect Park
More
The buttons under a list item sit in one .row-actions line that wraps when it must. A row keeps the controls a thumb lands on every time and puts the rest one tap away behind .row-more — nothing is removed, and no more than four sit in the open. There is no button that reads as a link: a control that removes a row or dismisses a hint is a small button, not underlined text.
States
Empty: what is missing, and the one thing to do about it. Never a blank list.
Pills carry status: On the air Needs height Expires in 40 days Neutral
Cards and grids
Near you · Brooklyn
Terrain checked between where you stand and the site.
A hero with its screen
The signpost line
The claim, with the proof beside it.
A marketing page opens with the screen it promises next to the sentence that promises it, so nobody scrolls to find out whether the thing is real.
Your first contact
The signpost line above the claim is a sentence in --accent-ink, never a tracked label in capitals; a heading carries its own weight.
Feature rows and the audience list
One claim, one screen
Each row pairs a heading, a sentence and its action with the screen that proves it; the sides alternate. Three claims are three rows, never three equal cards.
Its actionNear you · Brooklyn
Terrain checked between where you stand and the site.
One reader
A short column over a rule, for a list of who a page is for.
Another
No card chrome: the rule and the heading do the work.
A third
Three across on a laptop, one under the other on a phone.
Call-to-action band
Band
One invitation, one button
Used where a page raises a question another page answers. Never two in a row.
Tables and lists
| Callsign | Class | Paid to | Role |
|---|---|---|---|
| N2PYZ | General | 01/2027 | |
| KB1QRP | Technician | 11/2026 |
On a phone a table scrolls inside its own box; on a laptop it behaves as a table. A control inside a cell is the cell’s size, not a form field’s. Dates are US format and distances are in miles on screen; the API answers in metric.
Working on this
A designer changes the tokens at the top of globals.css for colour and scale, the class blocks below them for a part, and this page to see the result. A new page picks parts from here; if something is missing it is added here first, with a name, and then used. The reasoning behind each part is on the Design System wiki page.