ui.css
The tool language. 10/12/24px, compact density available. What a working surface is built from — panels, fields, tabs, lists, meters. demo.html is its kitchen sink; it opens directly off disk, no server.
Three stylesheets for dense tool interfaces. Stark black and white, monospaced, zero radius. Emphasis expressed by polarity, hairline weight and letter-spacing. No build step, no dependencies, no JavaScript.
npm i @amplib/ui
Stylesheets
Three languages, one page each — load exactly one. The tool file and the reference file define the same class names at different scales, so a page holding both gets whichever loaded last.
The tool language. 10/12/24px, compact density available. What a working surface is built from — panels, fields, tabs, lists, meters. demo.html is its kitchen sink; it opens directly off disk, no server.
The reference language — the same system spoken at reading distance. 12/14/20/32px, a fourth rung for section heads, code at body size, no compact mode. This page is set in it.
The exhibit language, and the opposite pole from the other two: serif, letter-spaced, black. Works hang dimmed and brighten under attention. gallery-demo.html shows it; stegassette: live is it in use.
Importing
The specifier depends on what is resolving it. Parcel reads a bare specifier in CSS as a relative path and does not consult exports, so it needs its own scheme and the filename. TypeScript resolves a CSS import through the bundler's ambient *.css declaration, which only matches a specifier ending in .css.
| where | specifier |
|---|---|
| CSS, via Vite or webpack | @import "@amplib/ui"; |
| CSS, via Parcel | @import "npm:@amplib/ui/ui.css"; |
| TypeScript or JavaScript | import "@amplib/ui/ui.css"; |
| no build step | cp node_modules/@amplib/ui/ui.css . |
Modes
Two orthogonal modes, both plain attributes, both settable on <html>, <body> or any subtree. color-scheme is set for you, so native scrollbars, pickers and the caret follow along.
| attribute | effect |
|---|---|
| — | dark: paper #000, ink #fff |
| data-theme="light" | light: paper #fff, ink #000 |
| data-theme="auto" | follows the system preference, no JavaScript |
| data-density="compact" | 11px tool density, tighter boxes (ui.css only) |
| .ht-surface-invert | crosses the ink/paper pair for a subtree |
Tokens
Only two literals exist — --ht-black and --ht-white. Everything else is a color-mix of the current pair, which is why flipping polarity recomputes the whole palette.
| --ht-ink / --ht-paper | current polarity |
| --ht-ink-dim / -faint | secondary and tertiary text; both clear 5:1 |
| --ht-ink-ghost | lines and texture only — never legible as type |
| --ht-line / -strong | hairline, and its hover weight |
| --ht-raised / --ht-sunken | button fill, input well |
| --ht-text-small | secondary — 10px tool, 12px reference |
| --ht-text-ui | everything else — 12px tool (11 compact), 14px reference |
| --ht-text-title | section names — reference only, 20px |
| --ht-text-display | the one page title — 24px tool, 32px reference |
| --ht-text-control-floor | 0, or 16px under (pointer: coarse) — the floor text-entry controls take, so iOS Safari does not zoom on focus |
| --ht-space-1 … -9 | 2 · 4 · 6 · 8 · 12 · 16 · 24 · 32 · 48px |
| --ht-gap / --ht-flow | inline and block rhythm — layout hypertokens read these, so one declaration retunes a region |
| --ht-hairline | 1px, the only border width |
| --ht-radius | 0, the only radius — do not raise it |
| --ht-control-size | 28px, or 22px compact |
Layers
A later layer wins outright, whatever the specificity — which is why base sits before hypertokens. Anything you write outside a layer beats all of it, so app CSS never needs !important. To override inside the system's order, declare your own layer after them.
@layer amplib.reset, amplib.tokens, amplib.base, amplib.hypertokens, amplib.components, amplib.utilities;
| tokens | values and modes |
| base | native element defaults — plain HTML already looks right |
| hypertokens | coordinated .ht-* fragments — type, arrangement, shape, surface, media, participation, time |
| components | recipes that earn a name — panel, field, toolbar, tabs, list, badge, status, meter, figure |
| utilities | single-purpose escapes |