Foundations
Elevation
The name is German for both halftone and semitone — a half-step, the smallest interval that still changes the chord. Elevation is where that idea is structural rather than poetic.
There are no shadows
Not softened ones. None. A shadow is a claim about a light source, and once a system makes that claim it has to keep it consistent across every surface, both themes, and every screen someone has turned the brightness down on. Most systems do not, which is why dark-mode shadows so often read as smudges.
Halbton separates layers with a change in surface colour and a 1px border, and nothing else. Both are theme-aware by construction, because both come from tokens that already invert.
The ladder, measured
Four layers. The step between each is deliberately small — small enough that people ask whether it is doing anything, which is the right question and has a measurable answer.
| Step | From | To | Ratio |
|---|---|---|---|
| 1 | --ht-canvas-sunken | --ht-canvas | 1.08:1 |
| 2 | --ht-canvas | --ht-surface | 1.00:1 |
| 3 | --ht-surface | --ht-surface-raised | 1.01:1 |
| Step | From | To | Ratio |
|---|---|---|---|
| 1 | --ht-canvas-sunken | --ht-canvas | 1.03:1 |
| 2 | --ht-canvas | --ht-surface | 1.06:1 |
| 3 | --ht-surface | --ht-surface-raised | 1.09:1 |
Those numbers are small on purpose. A conventional card sits at something like 1.4:1 against its page plus a shadow; Halbton's sits nearer 1.02:1 plus a border. Over a working day the border is enough to say this is a distinct region without the page reading as a pile of boxes.
The four layers
Which layer to use
| Token | Use | Never |
|---|---|---|
| --ht-canvas-sunken | Code blocks, wells, the inset a preview sits in. | As a page background. |
| --ht-canvas | The page. One per theme. | On anything that is not the page. |
| --ht-surface | Cards, panels, table rows, the sidebar. | Nested inside another surface — use a border instead. |
| --ht-surface-raised | Things that float over the page: modals, popovers, menus. | Anything that scrolls with the page. Raised means detached. |
State changes are half-steps too
The same argument applies to hover and active. A control moves by one ramp step, not two, and it does not move in space at all — no lift, no scale, no translate. A button that jumps under the cursor is a micro-interruption, and on a dense screen there are hundreds of them an hour.
.btn--secondary {
background: var(--ht-surface);
border: 1px solid var(--ht-border-interactive);
}
/* One step. No transform, no shadow, no scale. */
.btn--secondary:hover {
background: var(--ht-neutral-surface);
} Focus is the deliberate exception. A focus ring is the one signal that must never be subtle, so it uses a dedicated token held to 3:1 against every surface it can land on — the full reasoning is on Accessibility.