Aros HIG/Vol. I/FoundationsFoundations
Volume I

Foundations

The tokens, measurements, and laws from which every component and pattern is derived. Nothing in later volumes may contradict this volume. If a problem isn't answered here, resolve it in the spirit of the principles, document it, and propose it for the next revision — never improvise silently.

1.0 · Principles

Principles

Four laws. Every rule in this book serves one of them. When the book is silent, decide in their favour.

P1 — Precise

Nothing approximate.

Engineered geometry, tokenised values, exact alignment. If a measurement isn't on the scale, it's wrong. Precision earns trust before a word is read.

P2 — Resilient

Calm under load.

Feel like something that stays up when things go down. Solid surfaces, steady rhythm, no visual panic — even at P1 severity.

P3 — Transparent

State, shown plainly.

Legibility over decoration. Surface truth — green when healthy, red when not — never obscured by ornament or ambiguity.

P4 — Alive

Always watching.

The pulse is the soul. Motion and signal show the estate is observed in real time. Used with restraint, it makes the product feel awake.

1.0 · Principles

Rule grammar

Rules are graded. Keywords are absolute, read as in RFC 2119.

MUSTMandatory. No conforming interface omits or contradicts it.
NEVERProhibited. Disallowed under any circumstance.
SHOULDStrong default. Deviate only with a documented reason.
MAYOptional. A legitimate choice either way.

Token names (--p500, --s4) are normative. Reference tokens, never raw values.

1.1 · Foundations

Color

Obsidian dark, one signal green. Green is the pulse — used sparingly so it always carries meaning. Click any swatch to copy.

1.1.1 Core ramps

Obsidian — surfaces

Pulse — the accent

Neutrals — text & light mode

1.1.2 Elevation by tint

Dark UIs express depth with surface tint and a hairline border, not heavy shadow. Each step up the surface ramp is one level of elevation.

obs-950 · base
obs-900 · card
obs-850 · raised
obs-800 · popover
SHOULDPair every raised surface with a 1px --hair border. Tint alone reads flat on low-contrast displays.

1.1.3 Semantic & data

TokenHexMeaningUse
--p500#22C55ESuccess / healthy / liveOperational state, primary action, the pulse
--info#38BDF8InformationalNeutral notices, links, in-progress
--warn#F59E0BCaution / degradedDegraded nodes, soft warnings
--danger#F43F5EError / offline / destructiveFailures, destructive actions
--violet#8B5CF6Data series 4Charts only — never UI chrome

Data-viz series order: --p500, --info, --warn, --violet, then tints. Status colours keep their meaning in charts — green is always "good."

1.1.4 Contrast

PairingRatioVerdict
Snow on Obsidian-950≈ 16:1AAA · body
Mist on Obsidian-950≈ 9:1AAA · secondary
Slate on Obsidian-950≈ 4.8:1AA · labels only
Pulse-500 on Obsidian-950≈ 6.6:1AA · large / graphical
NEVERConvey state by colour alone, or set small body text in Pulse-500 on obsidian. Pair every status colour with a glyph, label, or shape.
1.2 · Foundations

Typography

Three families, three jobs, no overlap.

AROS
Archivo Expanded · Display

Wordmark & ≥24px headings only

Estate
IBM Plex Sans · Text

All readable copy & UI

192.168.1.251
IBM Plex Mono · Data

Data, code, labels, metadata

NEVERSet body or UI text in Archivo Expanded, or use it below 24px. It is a display face — illegible and off-brand small.

1.2.1 Type scale

TokenFamilySize / lineWeight · trackingUse
display-lDisplay48 / 52800 · +0.01emPage hero
display-mDisplay36 / 40700 · +0.02emSection hero
h1Sans30 / 36700Page title
h2Sans24 / 30600Subsection
h3Sans20 / 28600Block heading
body-lSans18 / 28400Lead paragraph
bodySans16 / 26400Default text
body-sSans14 / 22400Secondary
captionSans13 / 18400Captions, help
labelMono11 / 16500 · +0.16em · UPPEREyebrows, tags
codeMono13 / 20400Code, data values

1.2.2 Numerics & truncation

MUSTUse tabular figures for any column of numbers, metrics, timestamps, or live values so digits don't jitter. Plex Mono is tabular by default.
SHOULDTruncate overflowing identifiers with a trailing ellipsis + tooltip carrying the full value. Never wrap a hostname mid-string.
1.3 · Foundations

Spacing & layout

Everything is a multiple of 4px. One base unit is what makes unrelated screens feel like one product.

1.3.1 The scale

--s14pxHairline gaps, icon-to-text nudge
--s28pxTight inset, chip padding
--s312pxCompact gaps, control padding
--s416pxDefault gap between elements
--s624pxCard inset, related groups
--s832pxSection sub-blocks
--s1248pxMajor block separation
--s1664pxSection padding (vertical)
MUSTEvery margin, padding, and gap is a value from this scale. 13px, 15px, 30px do not exist.

1.3.2 Inset · stack · inline

Inset

Padding inside a container. Cards --s6. Compact controls --s3×--s4.

Stack

Vertical gap. Default --s4; related --s2; unrelated blocks --s8+.

Inline

Horizontal gap. Icon-label --s2; button group --s3; toolbar sections --s6.

1.3.3 Density

Comfortable is default. Compact (tables, inventory, dashboards) steps each inset/stack token down one.

SHOULDPick one density per surface and hold it. NEVER mix densities within a single view.
1.4 · Foundations

Grid & breakpoints

A 12-column fluid grid inside a fixed content well, with a persistent navigation rail.

Columns12Subdivide 2 / 3 / 4 / 6
Gutter--s4 → --s6Compact → comfortable
Content max1080pxReading & app well
Page margin--s6 → --s11Scales with viewport
Nav rail288px fixedPersistent ≥ lg; off-canvas below

1.4.1 Breakpoints

TokenMinBehaviour
sm480pxSingle column, stacked controls
md768pxTwo-column grids permitted
lg1024pxNav rail persistent; full grid
xl1280pxComfortable gutters & margins
xxl1536pxWell centred, margins grow
MUSTBelow lg, the nav rail collapses to an off-canvas drawer. The content well never sits under a fixed rail it can't clear.
1.5 · Foundations

Elevation & shape

Depth is layered and ordered; corners follow one radius scale.

1.5.1 Z-layers

z-base0Page content
z-raised10Cards, hovered rows
z-sticky30Sticky headers, toolbars
z-rail40Navigation rail / drawer
z-modal50Dialogs & scrim
z-toast90Toasts, transient alerts

1.5.2 Shadow tokens

none
shadow-sm
shadow-md
shadow-lg
shadow-sm0 1px 2px rgba(0,0,0,.4)Hover lift
shadow-md0 6px 16px rgba(0,0,0,.45)Popovers, menus
shadow-lg0 18px 40px rgba(0,0,0,.5)Modals only
SHOULDPrefer tint + border for elevation; reserve shadows for genuinely floating layers. Heavy shadows on flat cards read cheap.

1.5.3 Corner radius

xs · 4
sm · 6
md · 9
lg · 14
xl · 20
pill
--r-xs (4)Inputs in cards, chips, code blocks
--r-md (9)Buttons, inputs — default
--r-lg (14)Cards, panels, modals
--r-xl (20)Hero surfaces, app-icon tiles
pill / fullStatus pills, avatars, the live dot
NEVERMix radii on one element, or nest a larger radius inside a smaller one. Nested radii step down (9px control in a 14px card).
1.6 · Foundations

Iconography

Icons are a system, not a pile of drawings. They share one grid, one stroke, and a strict convention for when green appears — so the set reads as a single hand and every glyph is distinguishable from its neighbours.

1.6.1 The convention

MUSTChrome icons (search, settings, close, chevrons — generic UI) are monochrome in --ink. Domain icons (node, deploy, audit — things with meaning) carry exactly one green --accent element, placed on the part that is the live / active / verified thing.
NEVERPut two green elements in one icon, colour a chrome icon green, or mix filled and outline icons on the same surface.

1.6.2 Construction grid & keylines

Every icon is drawn on a 24px grid with 1px padding (drawable area 22px). Forms snap to the keyline shapes so square, round and tall icons feel optically equal in weight.

Square 20×20 — blocky forms (host, container).

Circle 22Ø — round forms run slightly larger to match weight (node, observe).

Rectangle wide forms (terminal, database).

1.6.3 Stroke spec

Stroke weight2px @ 24px (scales proportionally)
Caps & joinsRound
Interior corners2px radius
Structure / signal--ink · one --p500 element
FillNone — outline (default variant)
MUSTKeep stroke weight optically constant across the set. Never hand-thin a single icon to fit.

1.6.4 Chrome set · monochrome

1.6.5 Domain set · two-tone

1.6.6 Deliberate metaphors

Where there is a convention, we use it. Where the obvious glyph would collide with a neighbour or mislead, we modify it or design a new one. The reasoning is part of the system.

1.6.7 Variants

Each glyph ships as outline (default) and, where it appears in navigation, solid (filled silhouette) for the active/selected state. The green signal element is retained in both.

outline
solid / active
outline
solid
outline
solid
outline
solid

Optical sizing

16 · inline / table
20 · buttons / UI
24 · toolbars
32 · empty states

1.6.8 Rules

✓ Do
Constant weight, one green signal, geometric.
✗ Don't
No shadow, off-palette colour, or rotation.
SHOULDChoose the most literal metaphor available. An icon's job is recognition, not cleverness — but never reuse one neighbour's silhouette for a different concept.
1.7 · Foundations

Motion

Motion is purposeful, quick, and eased — it communicates state and causality, never decoration. The heartbeat is the one signature animation and the only thing permitted to loop indefinitely.

1.7.1 Principles

Purposeful

Every animation answers "what changed and why." If it explains nothing, remove it.

Quick

UI transitions land in 120–240ms. Slow motion feels broken, not premium.

Eased

Decelerate into rest. Linear is reserved for the continuous pulse loop only.

Restrained

One focal motion per view. Many small animations compete and cheapen.

1.7.2 Duration tokens

TokenValueUse
d-instant0msDirect manipulation (drag)
d-fast120msTaps, toggles, hover colour
d-quick180msButtons, small reveals
d-base240msPanels, cards, menus
d-slow360msModals, page transitions
d-pulse2800ms loopLive indicators & the mark

1.7.3 Easing tokens

1.7.4 Per-component motion

ElementTriggerPropertyDuration · easing
ButtonHover / pressbg, transform 1pxfast · standard
Card / rowHoverborder, translateY 2pxquick · standard
Menu / popoverOpenopacity + 4px risebase · decelerate
ModalOpenopacity + scale .98→1slow · emphasized
ToastEnter / exitopacity + 20px slidebase · standard
PageRoute changeopacity + 14px rise (stagger)base · decelerate

1.7.5 Choreography

When several elements enter together, stagger them 40–60ms in reading order. One orchestrated entrance beats scattered independent animations.

1.7.6 The signature pulse

The heartbeat traces the pulse path over 2800ms on a continuous loop with --e-standard. It is visual proof that the estate is being watched.

MUSTReserve the looping pulse for liveness: the live dot, the active logo, real-time indicators.
NEVERLoop the pulse (or any animation) on a static or decorative element. Indefinite motion that means nothing is noise.

1.7.7 Accessibility

MUSTHonour prefers-reduced-motion. When set, disable loops and large transforms; keep opacity only. The pulse becomes a static green dot — state stays legible without motion.
End of Volume I

Next: Components

Foundations are locked. Volume II — Components → builds every element on these tokens and laws.

Copied