Basics

The tokens everything else is built from: the colour scale, the type system and the grid of space.

Colour roles

In Ingot a colour is not written as a value but as a role. The accent has four, and each answers a different question:

  • --accent — the colour itself. Actions, filled buttons, icons, the focus ring; it is also a text colour, so it has to stay readable on surfaces.
  • --accent-ink — the darker step of the accent. Hover on actions, and the colour of links.
  • --accent-bg — the tint under a selected row, a badge and a callout. Never text.
  • --accent-border — the accent line, the outline of that tint. Decorative; it carries no information on its own.

A screen reaches for the variable, never the value. That is what makes both the family and the theme swappable without touching screens.

Accent families

The accent is one of four colour roles a screen takes through a variable — never as a hex. There are five families and they differ only in the values of those four variables; a component never knows which one is in effect.

Accent families
FamilyValue--accent--accent-ink--accent-bg--accent-border
blueblue
emeraldemerald
orangeorange
violetviolet
slateslate

Every family carries its own light and dark values, so switching the theme re-resolves it on its own — the switcher in the left column shows this in both themes. In the application the family is picked in the account menu and remembered by the account, not by the browser. Inside a shop, that shop's own colour takes precedence.

Neutral, accent and state colours

The values in the column are read at runtime from the palette currently in effect — switching the theme on the left rewrites them. A screen therefore always reaches for the token name, never the value.

Neutral tokens
TokenValueWhat for
--bgThe page surface.
--surfaceCards, tables.
--surface-2Headers, hover.
--surface-3Tracks, fills.
--borderThe default line.
--border-strongInputs, active.
--inkText, primary button.
--ink-2Body text.
--ink-3Secondary.
--ink-4Tertiary, disabled.
Accent tokens
TokenValueWhat for
--accentActions, focus.
--accent-inkHover, links.
--accent-bgSelection, callout.
--accent-borderThe accent line.
State tokens
TokenValueWhat for
--okActive, done.
--ok-bgThe tint underneath.
--warnPending, at the limit.
--warn-bgThe tint underneath.
--dangerError, stop.
--danger-bgThe tint underneath.

Every state also has a tint variant. Without it a badge with a state tint cannot be built: the saturated token is the text in it, and the surface underneath has to be a colour of its own, not a weakened version of the first.

  • The neutral scale carries most of the surface — accent and state are guests in it.
  • Two accents are never mixed in one view.
  • State colours are reserved for the state of the data, never for decoration.
  • Colour never carries information on its own — always alongside text or a shape.

Type scale

The scale has eight steps, each with a name and a fixed value — a size is never picked by eye. The sample on the left is set in exactly the classes the row names.

The sans face carries speech, mono carries facts: numbers, codes, dimensions and identifiers. Tabular figures keep digit above digit, so amounts in a column can be compared by eye.

Type scale
SampleStepSize / weightClasses
Manufacturing partnersPage title40 / 600text-h1 text-ink
Pricing formulasSection heading26 / 600text-h2 text-ink
Machine parametersSubheading18 / 600text-h3 text-ink
A setting that propagates into every quote.Lede17text-lede text-ink-2
The ordinary text in panels and field labels.Body text14,5text-body text-ink-2
Secondary information, the hint under an input.Small text13text-small text-ink-2
Section · uppercaseEyebrow11 / 500text-eyebrow uppercase text-ink-3
128 640 CZK · S235JR · 3.0 mm · 1 380 pcsNumbermonofont-mono tabular-nums text-body text-ink

Space, radii, layers

Spacing runs in four-pixel steps. No smaller step exists — two adjacent values you cannot tell apart by eye are not two values. The square below is exactly the size its label names.

s-1 · 4px
s-2 · 8px
s-3 · 12px
s-4 · 16px
s-5 · 24px
s-6 · 32px
s-7 · 48px

Radius grows with the element: small badges take the smallest, cards and frames the largest. The full circle is reserved for avatars and dots.

rounded-sm · r-xs · 4px
rounded · r-sm · 6px
rounded-md · r-md · 10px
rounded-lg · r-lg · 14px
rounded-full · 999px

A shadow says how high above the page an element sits. Three steps are enough: each has its floor and is not used outside it.

--shadow-sm

Cards on the page and their hover.

--shadow-md

Dropdown menus and the modal.

--shadow-lg

The side panel and toasts.

Layers sit at fixed levels so overlays do not outbid each other case by case. The gap between content blocks is 24 px.

Layers
LayerLevel
Content0
Sticky toolbar30
Header40
Side panel80
Modal90
Toast100

Motion

Motion has one duration and one curve across the system. A dialog, a drawer, a toast and a menu therefore open at the same speed — and when that speed should change, it changes in one place.

  • --dur — 0.22 s. Long enough to show where a panel came from; short enough not to be waited on.
  • --ease — a curve that leaves quickly and lands softly. Linear motion reads as mechanical.
  • An overlay enters; it does not animate away. Closing should be immediate, because the user already knows what they wanted.
  • Under the system's “reduce motion” setting the movement is dropped, not the panel. Dropping the panel would take the content away rather than calm it down.