How the site is set
The colours, type, spacing and components this site uses. The values on this page are read from the site's stylesheet when the site is built, and the examples use the same styles as every other page, so this page always matches the rest of the site.
1Principles
- Text first
- The site exists to explain a specification. Anything that doesn't help with that is left out.
- Thin lines
- Thin rules separate rows and sections. Tinted backgrounds are used only for code, notes and the digits after the eighth.
- One accent colour
- Blue is used for things you can click or choose, and for the highlighted cell in figures.
- Numbers line up
- Numbers in columns use fixed-width digits. Stamps are set in the normal text font, not as code.
- No jumping
- Anything that loads late, like the live clock, has its space reserved, and its placeholder can't be mistaken for a real value.
2The mark
The logo is the name set in Public Sans at weight 720, with the letters spaced by hand, followed by a square full stop. The square is the same highlighted cell as in the zoom figure on the overview page, where it marks one part in 32.
- Use the shapes in
mark.svgrather than typing the name in a font.tools/mark.pygenerates the file. - Leave clear space around it of at least half its capital height. When the capitals would be smaller than 12px, use the square tile instead.
- The letters use the text colour and the full stop uses the accent colour. Don't recolour it in any other way.
- In a sentence, write the name as plain text: T32.
3Colour
The palette is an off-white background, near-black text, two greys and one blue. Dark mode has its own values, chosen to work on a dark background rather than inverted from the light ones. The contrast column is measured against the page background. The build fails if any text colour drops below 4.5:1 against either background colour, in light or dark mode.
| Token | Light | Dark | Use | On paper |
|---|---|---|---|---|
--paper | #fbfaf6 | #141413 | The ground of every page | |
--ink | #1b1b19 | #e8e5de | Text and headings | 16.5:1 · 14.7:1 |
--ink-2 | #55534d | #aaa69c | Ledes, captions, secondary text | 7.4:1 · 7.6:1 |
--ink-3 | #6c6962 | #8e8a81 | Labels, section numbers, axis ticks | 5.2:1 · 5.4:1 |
--rule | #e1ddd3 | #2e2c28 | Hairlines between rows | |
--rule-strong | #bdb7aa | #4a4740 | Rules that open or close a table or figure; input borders | |
--wash | #f3f1ea | #1c1b19 | Code, notes, fractional cells | |
--accent | #1d4f86 | #93b6df | Links, the primary action, the marked cell | 8.0:1 · 8.8:1 |
--accent-rule | #a9bdd4 | #3d5674 | Link underlines | |
--mark | #f4ecd0 | #2d2919 | Highlighted rows, selection | |
--err | #a3261d | #e5786d | Errors | 7.0:1 · 6.4:1 |
4Type
Families
Public Sans
Aa Bb Gg Rr 0123456789
Used for everything except code. It is based on Franklin Gothic and was made for the US government.
Roboto Mono
Aa Bb Gg Rr 0123456789
Used only for code. Set one step down the scale, its lowercase letters are the same height as Public Sans, so code lines up with the text around it.
| Weight | Text | Medium | Strong | Heading | Display |
|---|---|---|---|---|---|
| Specimen | Rg | Rg | Rg | Rg | Rg |
| Light | 400 | 500 | 620 | 660 | 700 |
| Dark | 370 | 500 | 600 | 630 | 670 |
Light text on a dark background looks heavier, so dark mode uses slightly lighter weights. The fonts are variable, so in-between weights like 620 are used exactly rather than rounded.
Scale
Each step is times the size of the one below it, so the size doubles every five steps. T32 has the same ratio: five bits make one character. Step 0 is 16px and step 5 is 32px.
| Step | Token | px | rem | Role | Specimen |
|---|---|---|---|---|---|
| −2 | --fs-m2 | 12.1 | 0.758 | Label | Atomic seconds |
| −1 | --fs-m1 | 13.9 | 0.871 | Small | Atomic seconds |
| 0 | --fs-0 | 16.0 | 1.000 | Text | Atomic seconds |
| 1 | --fs-1 | 18.4 | 1.149 | Lede, h3 | Atomic seconds |
| 2 | --fs-2 | 21.1 | 1.320 | h2 on phones | Atomic seconds |
| 3 | --fs-3 | 24.3 | 1.516 | h2 | Atomic seconds |
| 4 | --fs-4 | 27.9 | 1.741 | Atomic seconds | |
| 5 | --fs-5 | 32.0 | 2.000 | h1 on phones | Atomic seconds |
| 6 | --fs-6 | 36.8 | 2.297 | Atomic seconds | |
| 7 | --fs-7 | 42.2 | 2.639 | h1 | Atomic seconds |
| 8 | --fs-8 | 48.5 | 3.031 | Clock | Atomic seconds |
Roles
There are seven text styles, each on a step of the scale. Larger text gets tighter line spacing and letter spacing. Labels, which are in capitals, get wider letter spacing instead.
Display
h1
Step 5 → 7 · --h1
Leading 1.05
Tracking −0.028em
A compact universal timestamp
Section
h2
Step 3 · --h2
Leading 1.2
Tracking −0.018em
Conversion from UTC
Subsection
h3
Step 1 · --h3
Leading 1.2
Tracking −0.01em
Leap seconds
Lede
.lede
Step 1 · --lede
Leading 1.5
Tracking −0.006em
T32 writes any moment as eight characters.
Text
body
Step 0 · --text
Leading 1.625
A stamp stands for a span of time. Drop characters for a longer span, or add them for finer time.
Small
.small, table, .caption
Step −1 · --small
Leading 1.5
Each position divides the one before it by 32.
Label
.label, th, .meta dt
Step −2 · --label
Leading 1.35
Tracking 0.07em
Draft 0.3 · Specification
Figures
Numbers in sentences use proportional digits. Numbers in columns, and all stamps, use fixed-width digits so they line up, with a little extra letter spacing so a stamp's characters are easy to count.
Proportional
1,089 y
34 y
388 d
11.1 h
Tabular, .data
1,089 y
34 y
388 d
11.1 h
A stamp
G0S7G6B1 in textG0S7G6B1 in code
5Space
Spacing uses a 4px grid with nine steps, each roughly double the one before. The small steps are used inside components, the middle ones between components, and the largest above each section.
| Token | px | rem | Size |
|---|---|---|---|
--s1 | 4 | 0.25 | |
--s2 | 8 | 0.5 | |
--s3 | 12 | 0.75 | |
--s4 | 16 | 1 | |
--s5 | 24 | 1.5 | |
--s6 | 32 | 2 | |
--s7 | 48 | 3 | |
--s8 | 64 | 4 | |
--s9 | 96 | 6 |
6Frame
A page has a narrow side column and a main column, inside a fixed maximum width. Paragraphs are limited to about 70 characters per line, even when the column is wider.
| Token | Value | Holds |
|---|---|---|
--measure | 39rem | Running text: about seventy characters |
--page | 72rem | Header, page and footer |
--rail | 12.5rem | The contents and metadata column |
--gutter | 1.5rem, --s5 | The side margin; 16px on phones |
--section | 4rem, --s8 | The space above a section’s rule; 48px on phones |
--radius | 2px | Corners of controls and code |
This paragraph is set to that width. Lines of about 70 characters are long enough to read comfortably and short enough that your eye can easily find the start of the next line.
--measure: about 70 characters.7Parts
The components pages are built from. Each one is a plain HTML element or a CSS class.
Actions .btn .btn.primary button.link
Use at most one primary button per view. A text button looks like a link but acts on the page instead of going somewhere.
Links a
Read the specification, or the source. The underline is a light tint until you hover over the link.
Fields input select
Metadata dl.meta
Tables table .num .data tr.hl
| Prefix | Characters | Span |
|---|---|---|
| G0S | 3 | 388 days |
| G0S7G6B1 | 8 | 1 second |
Note .note
Use a note for something the reader would otherwise get wrong. Don't use one just for emphasis.
Code code pre
Inline, as in Stamp::parse("G0S7"), and as a block:
let utc: UtcDateTime = "2026-10-31T03:13:00Z".parse()?;
let stamp = Stamp::new(Instant::from_utc(utc)?, 8)?;
assert_eq!(stamp.to_string(), "G0S7G6B1");Quotation blockquote
A stamp keeps the same meaning once it is written.