Baseline — AI Instructions
The Aleris brand is documented in two layers. Foundation defines identity and reasoning: colour, typography, voice, imagery, and the two reasoning tools (constant/contextual, emotional modes). Baseline is the implementation layer: the token architecture, component rules, and pattern library that apply Foundation across digital products. Read Foundation first; read Baseline for how to execute it.
When Foundation and Baseline conflict, Foundation takes precedence.
Before writing or modifying any UI code in an Aleris product, use only tokens from aleris-tokens.css. When uncertain about a decision, flag it as an open question in the code rather than guessing:
/* OPEN: [description of the decision needed] */
Token system
All values come from tokens/aleris-tokens.css — a three-layer architecture:
- Primitives — raw values (colors, spacing, type sizes). Platform-independent.
- Semantic — primitives mapped to usage (text colors, surface colors, states). Reference these in product code.
- Component — semantic tokens composed into component-level clusters (button, input, card, table, tab-nav).
Machine-readable token data with usage and constraint fields is in tokens/baseline-tokens.json. Consult it for lookup — the CSS remains the source of truth.
Never use raw values. No hex colors, no pixel values for spacing, no raw Tailwind color classes. Everything goes through tokens.
The one documented exception: a page rendered before the token stylesheet can load. A server-rendered pre-auth surface (login, an error page, a maintenance page) is often served before the built, hashed-filename stylesheet is reachable — it sits behind the gate it is rendering, so it cannot @import or link aleris-tokens.css and has to inline its colours. Added 2026-08-12, after a real build's first version of exactly this page used two values that aren't Aleris colours at all (#d9663d, #e6e1da) because there was nothing here to check against. The four values a pre-auth page needs, cited from canonical rather than invented for this case: page background --surface-page (sand-100, #f2ece4), text --text-primary (petrol-500, #004851), primary button --color-orange-600 (#d14811), border --border-default (gray-100, #d7d2cb). Inlining these four is the exception; every other surface still goes through the token file. Pin the values with a test that extracts every hex a pre-auth page uses and asserts each one is one of these four — a build cannot see this rule fail otherwise.
Serving this file. The comments in aleris-tokens.css are its documentation and they are not optional — every @usage and @constraint annotation is a rule, and the supersede notes are why a value is what it is. They are also not for browsers. Strip comments from the stylesheet at build time, keep them in the source a developer opens, and leave one pointer comment in the emitted file saying where the reasoning went. Stripping is not minifying: remove the comments and the blank runs they leave behind, and nothing else — whitespace crunching, shorthand rewriting and selector merging each change what the browser computes if they are wrong, and the weight here is almost entirely in the prose.
Two reasons, and the second is the one that bites. Weight: the file is 50,487 bytes, roughly 34,000 of them comment. Gzipped it is 15.9 KB with the prose and 3.3 KB without, so about four fifths of the compressed download is English sentences — prose has little redundancy to squeeze while a token file is almost nothing but redundancy. On a page that inlines this file that is the largest single saving available, and one consumer measured 50.0 KB of comment in 82.4 KB of inlined stylesheet, on a patient-facing surface, on every load. Build safety: a comment body can contain a sequence that closes it early. Browsers recover silently and strict minifiers do not — this has already broken one consumer's production build, in dev-invisible fashion, and the fix at the time was to reword the comment. A build that strips comments before the minifier sees them is not exposed to it at all.
patientguide/frame/lib/css.js is a working implementation, including the guard that refuses to emit a stylesheet when an unterminated comment opener survives the strip — that failure mode silently swallows every declaration up to the next closer, which is a page with rules missing and no error anywhere.
Hard rules
They apply to every surface, every product.
- Page background: sand, not white. Communicative =
--surface-page(sand-100, #f2ece4). Instrumental =--surface-page-instrumental(sand-50, #faf8f6). Never white. - Cards and surfaces: white, not sand.
--surface-cardis white. Sand on cards inverts the hierarchy. - One primary CTA per screen. Interactive orange (
--color-orange-600, via--button-primary-bg) marks the primary action on a screen. Do not place two orange buttons in the same view. Note the split as of 2026-07-29:--brand-accent(orange-500) is the brand orange for accent, decoration and print, and no longer carries the primary button – white text on it fails AA. - Status colors for state only. Error red, warning amber, confirm green, goal colors — never decorative.
- Confirm green is an indicator, never a button.
--color-confirm-500(#4f866e) marks completion — status dots, badges, chips. It is not an interactive fill: white on it is 4.23:1, below the floor at rest, before any interaction. The confirm button variant was retired 2026-07-31 rather than recoloured; a completion action takes the petrol button form plus a required check glyph, so "I'm done" is carried by the glyph and the verb. Keep it distinct from--color-goal-achieved(#2e8540), which indicates "target met" on dashboards. This is the rule of record for confirm; other documents reference it rather than restating it. - No all caps in content. Sentence case everywhere. The only exception is abbreviations (AB, MRI) — see
foundation/typography.md. - Only animate transform and opacity. No layout-triggering animations. Respect
prefers-reduced-motion: reduce— it disables everything. - No animation in email. All Aleris email layouts are static.
- 14px is the floor.
--font-size-xs(14px) is the smallest text in the system. Nothing goes below it. - No font-weight 400. Museo Sans has no 400 weight. Using it causes browser synthesis. Use
--font-weight-regular(500) or--font-weight-bold(700).
Surface temperature
Baseline applies F6 (foundation/constant-contextual.md) to surfaces through two modes: communicative and instrumental. Mode is determined by the situation, never the user's role — a patient managing their treatment plan in MyAleris is in instrumental mode; a staff member reading an internal newsletter is in communicative mode.
Communicative — Aleris tells, guides, explains, welcomes. Patient-facing content, marketing, service introductions. onboarding Removed 2026-09-05, card 122. Onboarding names when a flow happens, not what the person is doing in it, so it carries no mode of its own — and it was on this list while aleris-design-governance.md § 3 put treatment-plan work in instrumental, which left a treatment onboarding filed under both. Read the situation: a welcome sequence that introduces a service is communicative; setting up a treatment plan is instrumental from its first screen. The same holds for any word that names a stage rather than a situation — activation, renewal, offboarding.
- Page background:
--surface-page(sand-100) - Cards mandatory for content structure
- Generous spacing (
--spacing-lgto--spacing-3xl) - Full type scale, typography has room to breathe
Content spans 6–8 of 12 grid columnsSuperseded 2026-09-05, card 120: one reading column at every width,--grid-column-communicative— 640px up to a 768 window, growing a quarter of every further pixel to 768px from 1280 up. Decided by looking at three candidates rendered side by side (baseline/conformance/layout/index.html). The column holds 88 characters of 18px body at 768 and 105 at 1280, past the 45–75 guideline; that was seen and chosen, and the token says so. "6–8 columns" was never a measure proxy — 600–800px is 82–109 characters.- Max-width:
--grid-max-width-communicative(1200px)
Instrumental — The user works, navigates, configures, monitors. Tools, admin, dashboards, documentation, booking flows (decided 2026-06-12 — a booking flow is instrumental throughout).
- Page background:
--surface-page-instrumental(sand-50) - Cards optional — content can live directly on the surface
- Tighter spacing.
compressed type rangeSuperseded 2026-09-05, card 122: surface temperature does not change type size. Type size is the reader's to set and the browser already gives them that control — every size in the scale is a rem value, so a reader who raises their root font size raises the whole page, and the 14px floor is a floor at default settings rather than a cap. Instrumental density comes from layout utilisation and information hierarchy, which is whataleris-design-governance.md§ Scanning vs. attending already says: "not from spacing compression". "Compressed type range" told a builder to shrink type and named no token to do it with, because no mode-scoped type token has ever existed — the five mode-scoped tokens are all grid or background. Asserted intokens.test.ts. - Content can span all 12 columns. Tiles and card grids, decided 2026-09-05, card 120: fluid, no breakpoints —
repeat(auto-fit, minmax(var(--grid-tile-min-instrumental), 1fr)), 14rem tiles, so the column count falls out of the width: one to 390, two at 640, three at 768, four at 1024, five from 1280. Four tiles leave an empty fifth slot from 1280 up; rendered, seen, chosen over the stepped 12→6→1 and 12→1 candidates. Tables scroll inside their own container at every width. - Max-width:
--grid-max-width-instrumental(1440px or fluid)
Mode does not shift between steps within a single flow.
Component shapes
Radius by functional role:
- Cards:
--radius-l(16px) — decided 2026-08-10, board card 45, from computed styles measured live on aleris.se/.no/.dk (every card ships at 16px, not Baseline's former 4px). Derived inward: nested elements take the card's own radius at zero gap, floored at 0. Cards only, for now — panels, modals and tables were never measured live and stay--radius-s. - General containers (panels, modals, tables):
--radius-s(4px) - Interactive elements (buttons, inputs, dropdowns):
--radius-m(8px) - Indicators (badges, tags, avatars):
--radius-full(100px) - No full-pill buttons exist in Aleris interfaces.
- Flush top-of-card media (a hero image with zero clearance from the card's top edge): carries no radius of its own. The card clips its contents to its own rounded shape (
--card-media-overflow: hidden), which renders the image's top corners matching the card and its bottom edge square, for free — nothing to keep in sync, and the inversion the 4px card tier used to produce against an 8px image (see the corner-radius reasoning below) cannot recur. Scoped to cards that actually contain flush media, not every card, so a plain card stays free to let content overhang its edge without a second decision. Does not apply to an inset image with clearance on all sides, which keeps--image-radius-default(8px) unchanged. --radius-lwas retired 2026-08-07 at its old value (12px, never assigned to a component) and reinstated 2026-08-10 at a new one for cards. The radius set is0 / l / m / s / full.
The corner-radius reasoning, board cards 44/45. Baseline assigned radius by role — container, interactive, indicator — which is easy to teach but ignores the geometric convention that nested rounded rectangles must be concentric: an outer radius has to be at least its inner radius plus the gap between them, or the two curves aren't parallel and the corner reads as an error. At Baseline's 24px card padding, nothing sits close enough to a card's edge for this to show, which is why a 4px card holding an 8px-radius image went unnoticed for months. It stopped being invisible the moment an image sits flush against the card. Rather than resolve that one pair in isolation, the question was reframed as one problem — what should the default corner state be — and answered from what production had already settled empirically rather than from a rule invented for the occasion. A four-model comparison (baseline/conformance/radius/index.html, unpublished) made the candidates visible side by side before the decision, per the same design-by-looking approach as baseline/buttons/index.html.
Typography
See foundation/typography.md (F2) for the typography system and principles. Baseline implementation:
- Reference typography tokens from
aleris-tokens.css(--type-body-*,--type-lead-*,--type-h1-*, etc.) rather than specifying pixel sizes. - Font weights available:
--font-weight-regular(500) and--font-weight-bold(700). Do not use font-weight 400 — Museo Sans has no 400 weight and browser synthesis distorts the letterforms. - The licensed Museo Sans has no tabular figures, at either weight. Setting
font-variant-numeric: tabular-numsagainst it changes nothing and says so nowhere — measured in a browser against Arial as a control, digit advance widths are identical with and without the property, and the ten digits spread 8.72px at weight 500 and 7.50px at 700 where Arial spreads 0. At a 16px value size that puts 8.2px between "111,1" and "000,0". Right-alignment is what aligns a numeric column; the property is a silent no-op. (Measured bysundviktlakemedel, 2026-08-25. Whether a cut carryingtnumexists under the licence is unknown and worth asking separately.) - The licensed Museo Sans has no arrow glyphs, and no check mark. U+2192 →, U+2190 ←, U+2264 ≤, U+2265 ≥ and U+2713 ✓ are absent from both licensed weights, so any of them in running text falls back to another face silently — a different stroke weight and baseline beside the words it sits in. Present and safe: en and em dash, bullet, ×, …, °. Use an icon from the allowlist for an arrow or a check, never the character. (Measured 2026-09-05 by reading the character maps of
MuseoSans_500-webfont.woff2and_700: 229 and 228 mapped codepoints. First noticed bypatientguide, 2026-08-13.) --type-lead-*is used once per section, after the heading.
Spacing
Modular scale, 1.5 ratio, 4px grid. Use tokens — never fabricate values.
| Token | Value | Typical use |
|---|---|---|
--spacing-3xs |
4px | Minimum gap, label-to-field |
--spacing-2xs |
8px | Tight inline gaps |
--spacing-xs |
12px | Related elements, input padding-y |
--spacing-sm |
16px | Component padding |
--spacing-md |
24px | Section spacing, card padding |
--spacing-lg |
36px | Between components |
--spacing-xl |
48px | Between sections |
--spacing-2xl |
72px | Major section breaks |
--spacing-3xl |
96px | Page-level (communicative only) |
Buttons
Six variants, each with a job:
- Primary (orange): "Do this" — main action, booking, submission
- Secondary (petrol): "Go here" — navigation, exploration
- Outline: Less prominent alternative
- Ghost: Tertiary, minimal visual weight
Confirm (green): "I'm done" — completion, sign-off. Only for: Klarmarkera, Godkänn, Signera, Markera som klar. Not for generic "OK" in dialogs.- Small: Compact variant for tight spaces
Superseded 2026-07-31. The confirm button variant listed above was retired rather than recoloured —
--color-confirm-500fails AA as an interactive fill (white on it is 4.23:1). Confirm green is now an indicator only (status dots, badges, chips); a completion action takes the petrol button form plus a required check glyph. Hard rule 5 is the rule of record for confirm — this entry restated it out of date; don't restate it again elsewhere.
All buttons use --radius-m (8px). No full-pill buttons.
Contrast is the constraint. No interaction state may take a component's text below the AA floor against its own fill.
Darkening is the convention for interaction states. If a component already sits at the palette's highest contrast, darkening will lower contrast. That is permitted so long as it stays above the floor.
Superseded 2026-07-28. This replaces "Hover lightens, never darkens" (Anchor, decided 2026-06-12), which read: "Every hover state moves one step lighter — a choice lights up rather than dims. Primary hovers to orange-400, secondary to petrol-300, outline/ghost to petrol-100, confirm to its lighter step. Do not introduce darker hover values." The old rule named a direction and left the constraint implicit, which is how a lighter hover could silently break AA — the primary button hovered to orange-400 and the secondary still hovers to petrol-300 at 2.56:1. The replacement separates the two: the floor is the rule, the direction is the convention. The primary now darkens to orange-700.
Primary on a petrol surface inverts. orange-600 is specified for light surfaces and must never be placed on petrol. On a petrol ground the primary action becomes white fill with petrol-500 text (10.27:1) – --button-primary-inverse-*.
States, decided 2026-08-04/05 (board cards 16 and 17).
- Hover is a ring, not a fill. One petrol ring specified for six variants on two surfaces produced two invisible focus rings – petrol-500 on a petrol-500 fill (secondary) and petrol-500 on the petrol-500 page (primary-inverse), both 1.0:1. Rather than add another fill step to fix hover and a second mechanism to fix focus, the two merged: hover draws the outer ring only, focus draws both. No
--button-*-hover-bgtoken exists any more, and none should be added – a hover fill that changes colour is what the "hover lightens/darkens" rule used to constrain, and the constraint no longer applies because there is no fill to constrain. - Focus is a dual ring: 2px white inner, 2px petrol-500 outer, both always drawn. Whichever ground a button sits on, one ring contrasts – the inner against the button's own fill, the outer against the page.
primary-inverseswaps the two, because it sits on petrol rather than sand:--button-primary-inverse-focus-ring(outer position) is white,--button-primary-inverse-focus-ring-inner(inner position) is petrol. - Active (press) is per-variant, not a shared tint.
--state-active(sand-500) was retired rather than repointed – it was never a button fill, and reads 1.93:1 under white. Primary and primary-inverse reuse what used to be their hover fill (orange-700, petrol-100); secondary and confirm take a new step, petrol-700 (13.88:1); outline and ghost take petrol-100. A supplementary, unasserted second channel –--state-press-shade, a neutral inset, plus a 1px translate dropped underprefers-reduced-motion– is deliberately not petrol-tinted, for the same reason a single focus ring failed: a petrol inset on a petrol fill is invisible. - Buttons do not disable. A disabled button dissolves into the page (gray-100 on sand-100 is 1.28:1) and offers no explanation for why it is unavailable. Patient-facing: prefer explain-on-click – clicking reveals the prerequisite rather than the control simply not responding. Instrumental: a transparent, gray-500-edged treatment is acceptable where the workflow context is self-evident to the user.
--state-disabled-*remains for inputs, which have their own disabled semantics – see § Forms. - Buttons must survive text-zoom without causing horizontal scroll. Added 2026-08-12, from a real conformance failure: a normal-length label at 200% text size on a 320px viewport measured wider than its container and pushed the page into horizontal scroll — an EN 301 549 11.7 failure, not a cosmetic one, since 11.7 requires layout to follow the platform's text-size setting.
max-width: 100%andwhite-space: normal(label wraps to a second line rather than the button overflowing) are required on the button primitive, not optional per-instance styling. The same failure recurs at the row level: a flex row of buttons or other controls (a role switch, a toolbar) needsflex-wrapfor the identical reason — a non-wrapping row overflowed a 375px viewport before the fix, independently of any single button's own width. No dedicated layout section exists yet for this to live in more centrally; flagged here so both halves of the same defect are documented together rather than only the button half.
See baseline/buttons/index.html for every variant against every state, measured live from these tokens, and tokens/tokens.test.ts for the fitness check. One documented failure remains: ghost's press fill (petrol-100, reused from outline) has no border to carry its boundary, at 1.13:1 against sand-100 – tracked as KNOWN_BOUNDARY_FAILURES['ghost/active']. Ghost has no instances in app/ or components/; fixing it means giving ghost a border, which is a design call about what distinguishes it from outline, not made here.
Forms
- Labels above fields.
- Mark optional fields "(valfritt)", not required fields.
- Error text: "what happened + what to do" below the field, replacing helper text.
aria-invalid="true"+aria-describedbyfor error linking.- Focus:
focus-visiblewith petrol ring, 2px offset. Neverfocus. - Disabled: use sparingly. Patient-facing: prefer explain-on-click. Instrumental: acceptable when workflow context is self-evident.
- Read-only: looks like content, not a greyed-out input.
- Error text sits on a white card or an instrumental ground, never directly on the communicative ground.
--input-error-color(error-500) measures 5.03:1 on white (clears), 4.74:1 on sand-50 (clears) and 4.28:1 on sand-100 (fails).--input-error-sizeis--font-size-xsat regular weight, so the failing case is the ordinary one — a field error at the smallest size in the system. A form on a communicative page goes in a card, which is already the rule there (§ Surface temperature: "Cards mandatory for content structure"). Decided 2026-09-04, board card 118, from three alternatives: darkening error-500 was rejected becausefoundation/colour.mdcites#C14444by hex in its colour-vision reasoning and both published ΔE figures would need recomputing; a separate darker error-text step was rejected as a primitive bought to solve a case no product has. Surveyed before deciding rather than after: of the four consumers, onlysundviktlakemedelrenders error text, its whole app is<Page mode="instrumental">, and the rendered ratio measured 4.74:1 — passing. Enforced bytokens.test.ts§ "error text clears AA on every ground this rule permits", which reads the permitted grounds out of this bullet rather than holding its own list.
Status messages
Icon plus label, on error and on success both. A status message carries its meaning in an icon and in words, never in the fill or text colour alone – red and green are the pair that collapses under red-green colour vision deficiency, which is roughly 8% of men. Success already required a checkmark in the goal-status rules; error now carries the same requirement, so the two are distinguishable with colour removed.
This is the domain implementation of the constitutional rule that meaning is never carried by colour alone. The rule itself lives once, at the constitutional layer – this section says what it means for a status message, it does not restate the rule.
Tables
Two types: read tables (display data) and work tables (interactive).
- Three density levels: compact (36px), default (48px), comfortable (64px)
- Note to builders (reframed 2026-08-12, was stated as a requirement): user-selectable density that persists as a preference is the expectation for instrumental work tables, not a hard requirement every table must ship on day one. Build toward it; a first cut that ships with only the default density is a known gap, not a violation.
- Headers quieter than data (smaller, sentence case)
- Identifier in column one, always
- Numbers right-aligned, text left-aligned — right-alignment is what actually aligns a numeric column here, for the reason under Typography above
- Actions near the identifier, not at the far right
Motion
Four durations, two curves.
| Token | Value | Use |
|---|---|---|
--duration-instant |
100ms | Focus rings, checkbox toggles |
--duration-fast |
200ms | Buttons, hover, tooltips |
--duration-moderate |
350ms | Modals, accordions, sidebars |
--duration-slow |
500ms | Page transitions (sparingly) |
--ease-out: elements arriving--ease-in-out: elements moving- Never use
ease-inalone — slow start reads as unresponsive.
Loading: skeleton shimmer, not spinners. < 2s: shimmer only. > 2s: shimmer + progress. > 10s: navigate away + notify.
Anti-patterns (healthcare-specific)
If you experience a conflict between design requirements and anti-patterns, please note it and leave a comment.
- Consent asymmetry — consent and decline must be visually equal. Same size, same prominence, same steps.
- Cost burial — surface pricing before any data entry or emotional investment.
- Urgency fabrication — no countdown timers or scarcity messaging unless clinically real and verifiable.
- Obstacle withdrawal — anything booked online can be cancelled online with equal ease.
- Informational hiding — risks and qualifying information inline at point of decision. Never progressively disclosed.
- Data maximalism — collect only what the current service requires. Optional = labeled "(valfritt)".
- Default escalation — no pre-selection on choices with financial, clinical, or privacy consequences.
- Emotional exploitation — no shame, guilt, or fear to drive action. Motivate through clarity.
- Exit penalty — no degraded experience for choosing a less profitable path.
- Notification coercion — notifications for clinical relevance only. Marketing is separate with distinct opt-in.
Smell test: Is it easier to accept than to decline? Does the flow hide information that would change the decision? Does it require something not necessary for care?
Accessibility
- WCAG 2.1 AA minimum
- 14px font floor (enforced by token scale)
- Meaning is never carried by colour alone – the rule is constitutional, see
constitutional/accessibility-is-foundational.md. In this system it means pairing colour with icon, shape, or text, and it means error and success must be distinguishable from each other with colour removed (see Status messages above) - 44px minimum touch/click target (
--button-min-height-touch,--button-padding-y-touch) on patient-facing and touch contexts. Relaxed 2026-08-12 for dense instrumental surfaces on desktop pointer input: 24×24 CSS px is the floor there (WCAG 2.1 AA 2.5.8 Target Size Minimum), not 44×44 (AAA 2.5.5 Target Size Enhanced, which 44px implements) — token added the same day,--button-min-height-pointer. A dense work table or admin toolbar built for mouse/trackpad use may use the smaller target; anything a patient touches, or anything that could be used on a touchscreen, keeps 44px. focus-visiblefor keyboard navigation, neverfocus. Amended 2026-08-05, card 17 – this used to read "with petrol ring" as one rule for every control, which cannot hold: a single ring colour collides with something on six button variants across two surfaces (petrol-500 on a petrol-500 fill is 1.0:1). Inputs keep a single petrol ring, 2px offset – see § Forms. Buttons use a dual ring, inner and outer, so one half always contrasts regardless of ground – see § Buttonsprefers-reduced-motion: reducedisables all animationaria-invalid+aria-describedbyfor form errors
(Corrected 2026-09-11, cutover step 5. This table made five claims about app/ — the Next application — which was deleted that day. Each was a measurement against a codebase that no longer exists, so the pointers now name what is actually there: the site's own CSS under site/src, or this repo generally. The verdicts are unchanged; only what they were measured against is restated. Claude-drafted: a coverage table is utility text, not voice-bearing prose.)
Test coverage, card 18, 2026-08-05. Card 18's own done-when asked that each claim above have either a test or a recorded reason it cannot have one. None had a test before this card.
| Claim | Coverage |
|---|---|
| WCAG 2.1 AA minimum | Not independently testable as one check – it's the umbrella the other six implement. Covered in aggregate by tokens.test.ts and baseline/buttons/index.html + baseline/conformance/index.html. |
| 14px font floor | Corrected 2026-08-12 — the "failing" verdict below was stale. tokens.test.ts "the token scale itself now clears the floor at the real root font-size" passes: --font-size-xs is 0.875rem, which is 14.0px at the browser's actual 16px root — nothing overrides root font-size in the site's own CSS, so the scale's own floor holds. (An earlier version of this row assumed an 18px root the scale's own comment implied but nothing in the app ever set; that assumption, not the token, was the bug.) Separately, the Qlik icon picker's stylesheet still has 23 literal sub-14px declarations — unrelated to the token scale, not fixed here. That file left this repo on 2026-09-10 for code.aleris.ai/aleris/ikon, and nothing checks the floor there: the contributed scan that travelled with it reads colours only. Board card 153. See baseline/conformance/index.html § The 14px floor. |
| Meaning never carried by colour alone | Not testable as a token ratio – it's a claim about whether a rendered component pairs colour with an icon, shape or text. No status-message component exists in this repo yet to check it against; tracked as a requirement for whoever builds the first one. |
| 44px minimum touch target | Partially tested; rule itself relaxed 2026-08-12. tokens.test.ts "the touch-target token matches the rule it exists to enforce" asserts --button-min-height-touch is 44px, still correct for the patient-facing/touch case. --button-min-height-pointer (24px, added 2026-08-12) is tested the same way — "the pointer-target token matches the AA floor the rule relaxed to". Neither test can check any rendered button actually uses its token — no component reads either one yet, same shape as the colour-alone gap below. |
focus-visible ring, dual on buttons / single on inputs |
Tested. Buttons: tokens.test.ts "the focus ring is perceivable on both its grounds" (card 19). Inputs: tokens.test.ts "form input tokens are perceivable against their surfaces" (card 18) – the ring clears 3:1 on both the field and the page. |
prefers-reduced-motion: reduce disables all animation |
Not testable from tokens – there is no @media (prefers-reduced-motion: reduce) rule anywhere in the site's own CSS, confirmed by search, because there is no animation implementation to disable yet. A token-level check would assert the absence of a rule that has no positive counterpart either; recorded as a gap, not asserted as a false pass. |
aria-invalid + aria-describedby for form errors |
Not testable from tokens – no form component in this repo uses either attribute yet, confirmed by search. --input-error-* tokens exist and are tested for contrast (see Forms above); the ARIA wiring is a component-code claim with nothing built to check it against. |
Three of seven have a real test. Two are structural claims about components that don't exist yet, correctly left unasserted rather than faked. Two – the 14px floor and, indirectly, the touch target – are tested and found wanting.
File reference
Foundation (read first)
| File | Purpose |
|---|---|
foundation/index.md |
Brand in Brief — entry point to all Foundation pages |
foundation/colour.md |
F1 Colour |
foundation/typography.md |
F2 Typography |
foundation/voice.md |
F4 Voice — "den nära experten" |
foundation/constant-contextual.md |
F6 reasoning tool |
foundation/emotional-modes.md |
F7 reasoning tool |
foundation/imagery.md |
F10 Imagery |
Baseline (implementation)
| File | Purpose |
|---|---|
data-products/tokens/aleris-tokens.css |
Source of truth — all token values. Moved from baseline/tokens/ 2026-08-10, Phase B step 3 (card 48) |
data-products/tokens/baseline-tokens.json |
Generated — token lookup with usage/constraint. Same move |
data-products/tokens/aleris-tailwind.css |
Optional Tailwind v4 theme bridge — bg-aleris-petrol-500, p-aleris-md, and so on, each compiling straight to a token. Generated from the token file, holds no value of its own, adds a namespace rather than replacing Tailwind's. New 2026-08-28, card 97 |
schemas/design-token.md |
The token record's shape, the layer architecture, framework/Figma integration. Not yet in the agent-baseline package — open question, see _packages/README.md |
principles/design-tokens.md |
Why each token value is what it is. Corpus-only — reasoning, not a build constraint |
governance/aleris-anti-patterns.md |
10 healthcare-specific behavioural guardrails |
governance/aleris-design-governance.md |
Design decisions with certainty levels |
governance/aleris-privacy-jtbd-analysis.md |
Privacy as interaction design |
reference/aleris-progressive-enhancement.md |
Foundational design principle |
reference/aleris-grids-tables-dataviz.md |
Grid, table, and dataviz specs |
reference/aleris-baseline-animation.md |
Motion system (implements F6/F7) |
reference/aleris-baseline-images.md |
Image formats, aspect ratios (implements F10) |
voice/ |
Digital voice patterns, behaviour notes (implements F4) |
| Icon path data | 3,772 canonical FA Pro Regular SVGs are already extracted and reachable — no FA kit token required. Fetch a glyph at https://brand.dev.aleris.ai/icon-picker/svgs/regular/<name>.svg, with the name index at public/icon-picker/metadata/icons.json. Only re-extraction on an FA upgrade needs the kit. Lives at public/icon-picker/svgs/regular/ in the Brand OS repo, regenerable via scripts/build-icon-metadata.py. Which names may be used is a separate question — see data-products/iconography/allowlist.json and schemas/icon-allowlist-entry.md |
logo/ |
The logo files, the four ratified constants (clear space, primary variant, minimum height, prohibitions) and the sender rule. Read logo/README.md before placing the logo anywhere. New in agent-baseline v0.7 |
reference/aleris-design-tokens.md, the human-readable token reference this table used to list here, split into the two schemas//principles/ rows above on 2026-08-10 (card 48) — the value-restatement half was dropped entirely, not carried anywhere, per constitutional/tokens-are-canonical.md's rule against restating a token's value.
Baseline — last updated 2026-08-28. Maintained by Torfinn Almers, Head of Design, Aleris Group. Change history: workspace/status/changelog.md.