Design system

Diagnostik styleguide

The token contract, component kit and accessibility rules behind both portals. Everything here is shipped code — the contrast table below measures the live theme.

Color

Colour is expressed as intent, never as a raw value. Every token is a CSS custom property with a light and dark definition, so a theme flip needs no component changes.

background
card
muted
accent
primary
brand
sidebar
sidebar-primary
status-green
status-yellow
status-red
destructive
Contrast audit

Every pairing the product actually ships, measured in the browser against WCAG 2.x. This runs on the live theme — change a token and the verdict changes with it.

measuring…Measured live in this theme. Flip the theme above and the numbers re-run.
Contrast ratios for shipped token pairings
PairingSampleRatioNeedsResult
AA thresholds · 4.5:1 normal text · 3:1 large text and non-text UI (WCAG 1.4.3 / 1.4.11)
Typography

Geist for interface, Geist Mono for micro-labels and figures, Instrument Serif for editorial moments in the report.

The quick brown fox — Grinea · Impuls · CHF 1,240text-2xl / boldPage titles
The quick brown fox — Grinea · Impuls · CHF 1,240text-lg / boldSection titles
The quick brown fox — Grinea · Impuls · CHF 1,240text-smBody — the default
The quick brown fox — Grinea · Impuls · CHF 1,240text-xs / semiboldLabels, dense UI
The quick brown fox — Grinea · Impuls · CHF 1,240text-[11px]Hints, help text
The quick brown fox — Grinea · Impuls · CHF 1,240mono 10pxMicro-labels · brand signature

Instrument Serif — used sparingly, for report pull-quotes.

Spacing & shape

A 4px base grid, one radius token, and a single elevation step. Restraint here is what keeps two portals feeling like one product.

Spacing · 4px base
1 · 4px
2 · 8px
3 · 12px
4 · 16px
6 · 24px
8 · 32px
Radius & elevation
md
lg
xl
full
shadow-sm

Cards use rounded-xl + shadow-sm; controls use rounded-lg. Deeper shadows are not part of the system.

Motion

Motion signals that the system is thinking — never decoration. Every animation is disabled under prefers-reduced-motion, which matters because Iris breathes and blinks.

Entrance · fiq-rise
Content rises in
Pulse · live signal
Something is happening
Skeleton · loading
Buttons

Two variants only. Primary carries the single most important action on a screen; ghost carries everything else.

Primary · default / hover / disabled
Ghost · default / disabled

Both carry a focus-visible ring and a 44px minimum target on touch devices. Tab into this card to see the ring.

Form controls

Label, hint, and state are part of the primitive — not something each screen re-implements.

Status & chips

One traffic-light scale across both portals. Status colour never appears ad-hoc — always through these tokens, which is why they all clear AA.

Status pills
approvedpendingreturned
Chips
DefaultBrandMuted
Surfaces

Cards on background, and the permanently-dark navy stage used for the sidebar and the interview room. Dark surfaces re-point the focus ring at the lime accent so it stays visible.

Card

The default container.

Muted

Secondary grouping.

Navy stage

Sidebar & interview room.

Tables

Review queues, coverage and roadmap views all use this shape: scoped headers, hover rows, and status carried by pills rather than row colour.

Example review queue
ItemModuleStatus
Entity merge — “Impuls” / “IMPULS ERP”AS-IS Mappending
Maturity claim — Data foundations L2Maturityapproved
Map correction — “Requisition intake”AS-IS Mapreturned
Data visuals

Numbers carry the argument in this product, so they get their own primitives.

Sessions
18
Findings
142
Coverage
76%
Gap bars · evidence vs self-report
Data foundationsL2.1 · self-report L3.8
Process clarityL3.4 · self-report L3.1
Automation readinessL1.6 · self-report L3.5
Iris — living portrait

Iris is the product's face. Her four states are the only animation users read as meaning, so they are part of the design system rather than a component detail.

Iris
Speaking
Iris
size=lg
IrisIrissm · face chip
State matrix

What every interactive component must handle. If a screen shows only the default state, it is not finished.

StateSignalWhere it must exist
DefaultToken colours, no emphasisEverything
HoverOpacity or accent backgroundButtons, rows, nav, chips
FocusRing from --ring, 2px offsetEvery interactive element
Disabledopacity-50/60 + not-allowed cursorButtons, inputs, gated actions
Invaliddestructive border + messageForm controls
LoadingSkeleton or pending labelAny async view or mutation
EmptyOne sentence explaining what will appearLists, tables, queues, maps
ErrorAmber panel + a way to continueAnything that can fail — e.g. voice mode
Empty

Nothing in the queue — findings appear here as Iris records them.

Loading
Error

Voice unavailable — you can keep typing instead.

Accessibility

Target: WCAG 2.2 AA / EN 301 549, because EU enterprise procurement tests for it under the Accessibility Act.

In place
  • · Focus ring on every interactive element, ≥3:1 against its surface, via one base rule
  • · All shipped token pairings clear AA — verified live in the table above
  • · 44×44 minimum targets on touch devices
  • · prefers-reduced-motion honoured, including Iris
  • · Semantic tables with scoped headers and captions
  • · Real dark theme, not an inverted filter
Deliberately deferred
  • · CJK / Thai font coverage — gated on an actual APAC tenant
  • · Per-tenant white-label theming — gated on a deal that needs it
  • · Dialog, toast and tooltip primitives — added when a flow first needs one
  • · Published EN 301 549 conformance statement — after a full audit pass
  • · 10px micro-labels kept by choice: they clear AA at 4.9:1 and never carry meaning alone