Andromeda Pro · Foundation

The primitives

Every Andromeda Pro component is built from the values on this page, read through three layers of tokens. This page is the what. The Brain teaches when and how to use each value.

Three layers

  1. 100
    200
    300
    400
    500

    Layer 1

    Primitives

    The neutral ladder and four hue families. A theme retunes these; a component never reads them.

  2. status.info.textbrand 500

    Layer 2

    Semantic

    Named roles such as status.danger.text. Every component reads this layer and only this one.

  3. Live

    Layer 3

    Component wires

    A --component-role variable in the one file that owns it, pointing at exactly one role. The wiring never leaves that file.

The neutral ladder

Thirteen grays, numbered by depth: 100 is the page ground, 1300 the strongest ink. Surfaces, borders and text are all roles pointing into this one ladder.

light

100
200
300
400
500
600
700
800
900
1000
1100
1200
1300

dark

100
200
300
400
500
600
700
800
900
1000
1100
1200
1300

Four hue families

Five stops each, 100 through 500, plus two alphas and a guaranteed-contrast on ink. The ramp itself is the same in both themes; what flips is which stop a role points at, shown further down. Color is never the only channel: a tone always rides with a glyph, a position or a label.

Brand

the live series, the primary action

light

dark

Success

this moved the good way

light

dark

Warning

caution, degraded, restricted

light

dark

Danger

loss, fault, threshold breach

light

dark

Semantic roles

Components never read a primitive. They say what they mean, in eight role groups:

textthe four inks: primary, secondary, muted, faint
surfacethe grounds and the interaction steps a fill climbs
borderthe hairline ladder, subtle to strong, plus the floating frame
statusfour tones × six roles: surface, border, text, on, onMuted, fill
actionwhat a control does: primary, secondary, danger, and their states
focusthe ring, the glow, and their invalid forms
selectionthe mark, the track, the selected edge
chartbaseline, live, context, threshold, grid, and the stacked ramp

How a family crosses the themes

When the theme flips, a role’s stop mirrors around the middle of its family: 100 and 500 swap, 200 and 400 swap, and 300 is the pivot. Fills stop at 200 rather than 100, because 100 barely stands off the light page. The one thing that overrules the mirror is WCAG. Where the mirrored value misses its contrast minimum on the light page ground it steps toward the deep end until it clears. That is the whole reason the text row below reads 300 → 500 rather than 300 → 400: on the light ground the 400 stop measures 3.97 for brand, 4.21 for success and 3.12 for warning, all under the 4.5 that normal text requires, so they step again. Danger reaches 4.86 at 400 and stops there. The row under it lands on 400 everywhere because a mark is a non-text object and needs 3.0, not 4.5. Both columns are resolved from the same functions the site paints with, so they cannot drift from what you see.

RoleBrandSuccessWarningDanger

Text

a status word, a value, a chart label

300500
300500
300500
300400

Secondary text

the quieter second line beside it

200400
200400
200400
200300

Foreground and borders

icons, dots, chart lines, frames

300400
300400
300400
300400

Background fill

a rail, a filled chip, a track

500200
500200
500200
500200

Every color, both themes

The whole set, dark on the left of each pair and light on the right. Enumerated from the live token set rather than listed by hand, so a color added to the system shows up here on its own. A pair marked same is deliberately theme invariant: a scrim darkens what is behind it whatever the theme, and a solid fill that carries pale text has to stay deep in both.

Neutrals

numbered by depth in the stack, not by lightness, so 100 is the page ground in both themes and the ladder never folds

neutral-100
neutral-200
neutral-300
neutral-400
neutral-500
neutral-600
neutral-700
neutral-800
neutral-900
neutral-1000
neutral-1100
neutral-1200
neutral-1300
neutral-scrimsame

Text

the four neutral inks

text-primary
text-secondary
text-muted
text-faint

Surfaces

grounds and the steps a fill climbs under the pointer

surface-floating
surface-scrimsame
surface-base
surface-raised
surface-overlay
surface-hover
surface-active
surface-alpha

Borders

the hairline ladder

border-floating
border-subtle
border-base
border-bright
border-strong

Brand ramp

the primitive stops every brand role points at

brand-100same
brand-200same
brand-300same
brand-400same
brand-500same
brand-alphasame
brand-alpha-strongsame
brand-onsame
brand-on-brightsame

Status

four tones, six roles each

status-success-surfacesame
status-success-border
status-success-on
status-success-on-muted
status-success-text
status-success-fill
status-success-mark
status-success-areasame
status-warning-surfacesame
status-warning-border
status-warning-on
status-warning-on-muted
status-warning-text
status-warning-fill
status-warning-mark
status-warning-areasame
status-danger-surfacesame
status-danger-border
status-danger-on
status-danger-on-muted
status-danger-text
status-danger-fill
status-danger-mark
status-danger-areasame
status-info-surfacesame
status-info-border
status-info-on
status-info-on-muted
status-info-text
status-info-fill
status-info-mark
status-info-areasame

Actions

what a control does

action-primarysame
action-primary-hoversame
action-primary-pressedsame
action-primary-bordersame
action-primary-border-hoversame
action-on-primarysame
action-secondary
action-secondary-hover
action-secondary-pressed
action-secondary-border
action-secondary-border-hover
action-on-secondary
action-ghost-hover
action-ghost-pressed
action-on-ghost
action-on-ghost-hover
action-dangersame
action-danger-hoversame
action-danger-bordersame
action-danger-border-hoversame
action-on-dangersame
action-danger-text-hover
action-active-text
action-active-glow

Focus

the ring and its glow

focus-ring
focus-ring-invalidsame

Selection

checked, selected, current

selection-border
selection-border-hover
selection-surfacesame
selection-mark
selection-tracksame

Chart ink

roles, not series numbers

chart-baseline
chart-live
chart-context
chart-thresholdsame
chart-compare
chart-grid
chart-cursor
chart-axis
chart-stack1
chart-stack2same
chart-stack3
chart-stack4

Gradients

composed values, swapped stop by stop

gradient-brand-fade
gradient-brand-sweep
gradient-surface-soft

Accessibility

Every color pair in this system meets WCAG 2.2 level AA, in both themes. The ratios are measured by a contrast script, not judged by eye, and contrast is the one thing here that overrules a design decision, including the family pivot above.

4.5 : 1

Normal text

Anything under 24px, or under 18.66px bold. Almost all of our text. WCAG 1.4.3.

3.0 : 1

Large text and non-text

Display sizes, and every icon, border, chart line, dot and focus ring. WCAG 1.4.3 and 1.4.11.

7.0 : 1

AAA, where it lands

Not a target for the whole system, but the primary, secondary and muted text inks clear it in both themes.

The type ramp

A step names three values, not one: a size, its leading, and its tracking. Taking a step means taking all three. Tracking is a function of size here, open at the small end where letterforms crowd and pulled in at the display end where large type sets loose. Weight is the second axis and stays a component’s choice.

StepSpecimenSizeLine heightTracking
textXsAa10px / 0.625rem14px / 0.875rem0.14em / 14%
textSmAa12px / 0.75rem18px / 1.125rem0.08em / 8%
textMdAa14px / 0.875rem20px / 1.25rem0.02em / 2%
textLgAa16px / 1rem24px / 1.5rem0.02em / 2%
textXlAa18px / 1.125rem28px / 1.75rem0
text2xlAa20px / 1.25rem30px / 1.875rem0
displayXsAa24px / 1.5rem32px / 2rem-0.02em / -2%
displaySmAa30px / 1.875rem38px / 2.375rem-0.02em / -2%
displayMdAa36px / 2.25rem44px / 2.75rem-0.02em / -2%
displayLgAa48px / 3rem60px / 3.75rem-0.02em / -2%
displayXlAa60px / 3.75rem72px / 4.5rem-0.02em / -2%
display2xlAa72px / 4.5rem90px / 5.625rem-0.02em / -2%

The one named style

Everything in the system is a step plus a weight. There is exactly one exception, because it carries something the ramp deliberately does not: case. Uppercase is a decision a component makes, not a property of a size, so it lives here and nowhere else. It carries no color either, so ink stays a separate decision.

typography.role.label10 / 14 · medium · wider · uppercase

Bearing

column heads, axis and legend labels, kickers, stat captions

Spacing

A 4px grid with one half-step. Control heights ride their own three-rung ladder (28 / 32 / 40) so fields, buttons and toggles in a row always agree.

1
4px
1.5
6px
2
8px
3
12px
4
16px
5
20px
6
24px
8
32px
10
40px
12
48px