Search

Search components, tokens, patterns, architecture

Foundations

Colors

The warm Peri palette is canonical: creams, beiges, warm browns, muted oranges, soft golds and earthy neutrals — with green reserved exclusively for data. Click any swatch to copy its hex.

Palette law

Purple, lavender, violet and magenta belong to Tuluna, the legacy product identity. They are excluded from every token, component and example in this system. Purple artifacts found in Figma are documented only in the divergence register — never as valid tokens.

Surfaces

The canvas-to-card ladder. Cards are pure white on a cool-tinted canvas; the warm surface (#F7F4F2) marks interactive insets.

Text — warm brown ramp

The strongest brand signal in the system: deep warm brown instead of grey-black. Grey text is off-system.

Primary — orange

Orange means interaction and identity, exclusively. It is never used as a data color.

Semantic

Three feedback hues, used sparingly so they keep their meaning.

Chart — green family

Green is reserved for data and positivity so orange keeps exclusive meaning as interaction. The two never compete on one element.

Cycle-phase pastels (retained)

Inherited from the earlier product generation; survive only in calendar/phase marking. Flagged for a future warm-harmonisation pass — the luteal pink is the furthest from the warm palette without being purple.

Gradients — the only four

Gradients are sanctioned in exactly four places. New gradients are off-system; the portal itself uses none beyond these.

gradient.button

Primary CTA, selected chips, selected scale cells

gradient.fab

Floating + button, active day card

gradient.header

App top bar (Figma intent), demo banner

gradient.splash

Splash screen only — warm blush, one-off

Accessibility checker

Live WCAG contrast ratios for the system's real text/surface pairs. Muted text intentionally trades contrast for hierarchy and is restricted to non-essential captions.

SamplePairRatioWCAG
AaPrimary text on card#673228 on #FFFFFF · body10.18AAA
AaSecondary text on card#7A5D53 on #FFFFFF · body5.97AA
AaMuted text on card#B59386 on #FFFFFF · caption2.81Fails
AaPrimary text on warm surface#673228 on #F7F4F2 · body9.29AAA
AaWhite on gradient end#FFFFFF on #C94800 · 15px/6004.76AA
AaWhite on accent (gradient top)#FFFFFF on #F39021 · 15px/6002.38Fails
AaActive tab on pill#C2581D on #F7F4F2 · 11px/6004.07AA Large
AaAccent-dark on tint#C94800 on #F1E3D6 · body3.79Large only
AaAlert on card#D1495B on #FFFFFF · body4.36Large only
AaChart green on card#0E9455 on #FFFFFF · body3.90Large only

Known tradeoffs

  • text.muted (#B59386) fails AA on white — by design it is limited to captions, placeholders and timestamps that are never the only carrier of information.
  • White on #F39021 passes only at large/bold sizes — which is why CTA labels are 15px/600 and the gradient darkens toward #C94800.
  • The 11px active-tab label uses #C2581D (not #F39021) precisely to hold contrast at small sizes — this is the documented reason two “primary dark” tokens exist.

Token structure

Shipped code uses flat CSS custom properties. For scaling, tokens map into three tiers without renaming the shipped vars:

TierExampleNotes
1 · Primitiveperi.palette.orange.500 = #F39021Raw values; never referenced by components directly
2 · Semanticperi.color.action.primary → orange.500Meaning, not appearance; what this portal documents
3 · Componentperi.button.primary.bg → color.action.primaryPer-component overrides only where needed