diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
index 0dd0ed0d..3dae9ab7 100644
--- a/.storybook/preview.tsx
+++ b/.storybook/preview.tsx
@@ -75,6 +75,7 @@ const preview: Preview = {
"Helpers",
"Theme",
"Theme/Logos",
+ "Accessibility",
"MUI",
"Components",
],
diff --git a/src/storybook/accessibility/00-overview.mdx b/src/storybook/accessibility/00-overview.mdx
new file mode 100644
index 00000000..69d5251e
--- /dev/null
+++ b/src/storybook/accessibility/00-overview.mdx
@@ -0,0 +1,175 @@
+import { Meta } from "@storybook/blocks";
+
+
+
+
+
+# Accessibility
+
+Accessibility (a11y) in the Diamond Design System is a baseline for quality,
+clarity, and usability in complex scientific tools, not a checklist or a
+separate mode.
+
+Our goal is to make interfaces that are understandable, predictable, and
+usable across a wide range of abilities, environments, and levels of fatigue.
+
+## Standards and approach
+
+We follow WCAG 2.2 as the baseline for accessibility compliance.
+
+We also use APCA (Advanced Perceptual Contrast Algorithm) to design for
+perceived readability. Unlike WCAG contrast ratios, APCA accounts for font
+size, weight, and light/dark conditions.
+
+WCAG defines minimum thresholds. APCA is used to ensure interfaces remain
+readable, comfortable, and usable in real-world conditions.
+
+This reflects the direction of emerging standards such as WCAG 3.
+
+## Core principles
+
+
+ -
+ Clarity over cleverness: interfaces should explain
+ themselves.
+
+ -
+ Predictable behaviour: similar things behave in similar
+ ways.
+
+ -
+ Multiple ways to perceive information: never rely on one
+ signal alone.
+
+ -
+ Low cognitive effort by default: minimise mental overhead.
+
+
+
+## ✅ Do
+
+### Interactive elements
+
+
+ - Ensure every interactive control has an accessible name.
+ -
+ Provide this via a visible label,
aria-label, or{" "}
+ aria-labelledby.
+
+ - Make keyboard focus clearly visible at all times.
+ -
+ Use a consistent focus indicator (outline) rather than transient effects
+ such as ripples.
+
+ -
+ Ensure disabled states are clearly distinguishable from enabled and default.
+
+
+
+### Keyboard navigation
+
+
+ -
+ All interactive elements must be reachable and usable using a keyboard
+ alone.
+
+ - Follow a logical tab order that matches the visual and reading order.
+ -
+ Do not trap focus. Users must be able to move in and out of components using
+ standard keyboard interactions.
+
+ -
+ Ensure focus is always visible and moves predictably between elements.
+
+ -
+ Support standard keyboard interactions (e.g. Enter or Space to activate
+ controls).
+
+
+
+For composite components (e.g. menus, dialogs, tables), manage focus
+intentionally:
+
+
+ - Move focus into the component when it opens.
+ - Keep focus within the component while it is active.
+ - Return focus to the triggering element when it closes.
+
+
+### Icons and icon-only actions
+
+
+ -
+ Icon-only controls must include an accessible name that describes the action
+ (e.g. “Delete sample”), using
aria-label or{" "}
+ aria-labelledby.
+
+ -
+ Tooltips support discoverability, but do not replace accessible names.
+
+ -
+ Decorative icons should be hidden from assistive technologies using{" "}
+
aria-hidden="true".
+
+ - Do not rely on an icon alone to communicate critical meaning.
+ -
+ If an icon represents a toggle or state, expose the state using appropriate
+ ARIA attributes (e.g.
aria-pressed).
+
+
+
+For interactive icons, ensure both an accessible name and a visible affordance
+such as a tooltip or label.
+
+In MUI, use
aria-label on
IconButton. Tooltips (e.g.
+
+
<Tooltip />) should be used in addition to, not instead of,
+accessible labelling.
+
+### Forms and inputs
+
+
+ - Always associate inputs with labels (even if visually hidden).
+ -
+ Do not show validation errors while a user is actively typing. Validate on
+ blur or submission.
+
+ - Make error messages clear, specific, and actionable.
+ - Associate errors programmatically with the relevant field.
+
+
+### Content and layout
+
+
+ - Do not rely on colour alone to convey meaning.
+ - Do not rely on icons alone to convey critical meaning.
+ - Use a logical, predictable reading order.
+
+
+## ❌ Don’t
+
+
+ - Don’t use placeholder text as a replacement for labels.
+ - Don’t hide important information in faint or decorative text.
+ - Don’t introduce unexpected interaction patterns.
+ - Don’t create dense, unbroken blocks of content.
+
+
+## Storybook guidance
+
+
+ -
+ Simple component stories may be visually minimal, but should still expose an
+ accessible name, or be documented as intentionally incomplete.
+
+
+
+## Quick sense check
+
+
+ - Can this be used with a keyboard only?
+ - Is its purpose clear without colour or icons?
+ - Would it still make sense when someone is tired or distracted?
+
+
+
diff --git a/src/storybook/accessibility/01-colour-contrast.mdx b/src/storybook/accessibility/01-colour-contrast.mdx
new file mode 100644
index 00000000..617086b5
--- /dev/null
+++ b/src/storybook/accessibility/01-colour-contrast.mdx
@@ -0,0 +1,782 @@
+import { Meta } from "@storybook/blocks";
+
+
+
+
+
+
+
+# Colour contrast and vision
+
+Colour contrast directly affects readability, speed, and error rate. In dense,
+data-heavy scientific interfaces, poor contrast increases cognitive load and
+slows decision-making. Colour vision deficiency adds a second, related
+failure mode: a colour choice can be readable and still fail if the hues
+involved aren't reliably distinguishable in the first place.
+
+We prioritise perceptual contrast using APCA when defining colour choices,
+while maintaining WCAG 2.2 as the compliance baseline. We also check those
+same colour choices under colour vision deficiency simulation, since a
+pairing can clear both APCA and WCAG 2.2 and still rely on a hue distinction
+some users can't actually perceive.
+
+## Why contrast needs a modern approach
+
+Traditional WCAG 2.x contrast ratios are useful, but they are based on
+luminance ratios rather than perceived readability. In practice, some
+combinations can technically pass while still feel strained or unstable in
+real UI.
+
+This becomes more visible across different font sizes, weights, and light or
+dark environments.
+
+This leads to common issues:
+
+
+ - Combinations that pass but still feel hard to read.
+ - Overly strong contrast that causes glare or eye strain in dark mode.
+ -
+ Poor readability with saturated colours such as success, warning, and
+ danger.
+
+
+
+APCA helps address these limitations by modelling perceived readability rather
+than relying only on raw luminance difference.
+
+## APCA contrast (primary)
+
+APCA reflects how contrast is actually experienced by users more closely than
+older ratio-based methods.
+
+
+ - Accounts for font size, weight, and polarity.
+ - Handles light-on-dark and dark-on-light differently.
+ - Produces more reliable results for real UI text.
+ - Helps reduce strain in long-running workflows.
+
+
+We use APCA to tune token values, component defaults, and interaction states.
+
+## WCAG 2.2 contrast (baseline)
+
+WCAG 2.2 remains the current compliance baseline for text contrast.
+
+
+ - Defines minimum acceptable contrast thresholds.
+ - Used as a strict floor we do not go below.
+ - Required for accessibility reviews and audits.
+
+
+WCAG 2.2 is necessary, but on its own it is not enough to judge readability
+quality.
+
+## How we use them together
+
+Contrast decisions follow a clear order:
+
+
+ -
+ 1. Design using APCA for perceptual readability.
+
+ -
+ 2. Validate against WCAG 2.2 for compliance.
+
+ -
+ 3. Adjust only if required, without degrading usability.
+
+
+
+This helps keep interfaces both compliant and genuinely usable.
+
+## Colour-specific considerations
+
+Some hues behave less predictably for perceived contrast, even when WCAG 2.x
+ratios look acceptable.
+
+In DiamondDS this matters most for status colours: `--ds-success`,
+`--ds-warning`, and `--ds-danger`.
+
+A common issue in real interfaces is that black text on a saturated colour may
+look mathematically strong, but visually feel unstable, vibrating, or tiring,
+especially for smaller or denser text.
+
+APCA is better at exposing these perception problems.
+
+
+ -
+ Success: can feel muddy or uneven with dark text,
+ especially in small labels.
+
+ -
+ Warning: often looks shallower than expected, reducing
+ clarity on both light and dark surfaces.
+
+ -
+ Danger: more prone to vibration and reduced legibility,
+ particularly in error messaging.
+
+
+
+When using these colours:
+
+
+ - Use APCA to judge readability, not just WCAG 2.2 ratios.
+ - Test across sizes, weights, and both themes.
+ - Always pair colour with text, icons, or labels.
+
+
+## Colour blindness
+
+Colour vision deficiency (CVD) is not one condition:
+
+
+ -
+ Protanopia / protanomaly: reduced or absent red-cone
+ sensitivity.
+
+ -
+ Deuteranopia / deuteranomaly: reduced or absent
+ green-cone sensitivity. The most common form, affecting roughly 1 in 12
+ men and 1 in 200 women.
+
+ -
+ Tritanopia / tritanomaly: reduced or absent blue-cone
+ sensitivity. Rare.
+
+ -
+ Achromatopsia: little or no colour perception at all.
+ Very rare.
+
+
+
+Together, the red-green deficiencies (protan and deutan) are by far the most
+common, which matters directly here: `--ds-success`, `--ds-warning`, and
+`--ds-danger` sit in exactly the green, amber, and red range those
+deficiencies compress together.
+
+### Checked, not assumed
+
+WCAG 2.2's success criterion 1.4.1 (Use of Colour) already requires that
+colour is never the only way information is conveyed. Confirming that means
+actually checking what these tokens look like under a colour vision
+deficiency, not assuming different hues are automatically distinguishable.
+Running DiamondDS's status colours through a standard CVD simulation
+(Machado, Oliveira and Fernandes, 2009) shows a real gap, not a hypothetical
+one:
+
+
+
+
+ Light: under CVD simulation
+ {[
+ [
+ "Main",
+ "text",
+ [
+ ["As designed", "#137329", "#a95703", "#ae1e13"],
+ ["Simulated: protanopia", "#756821", "#706100", "#4e450f"],
+ ["Simulated: deuteranopia", "#6a602f", "#837401", "#716406"],
+ ],
+ ],
+ [
+ "Solid",
+ "chip",
+ [
+ ["As designed", "#1b8834", "#e97b12", "#d63c41"],
+ ["Simulated: protanopia", "#8a7b2b", "#9c8900", "#686040"],
+ ["Simulated: deuteranopia", "#7e733b", "#b6a20f", "#8f813c"],
+ ],
+ ],
+ [
+ "Container",
+ "chip",
+ [
+ ["As designed", "#d4f3df", "#fef0df", "#fde7e5"],
+ ["Simulated: protanopia", "#f3eede", "#f5f0de", "#ebe9e5"],
+ ["Simulated: deuteranopia", "#edeae0", "#f9f3df", "#f0ede5"],
+ ],
+ ],
+ ].map(([roleName, variant, rows]) => (
+
+
+ {roleName}
+
+ {rows.map(([label, success, warning, danger]) => (
+
+
{label}
+ {variant === "text" ? (
+
+ Success
+ Warning
+ Danger
+
+ ) : (
+
+
+ Success
+
+
+ Warning
+
+
+ Danger
+
+
+ )}
+
+ ))}
+
+ ))}
+
+
+ Dark: under CVD simulation
+ {[
+ [
+ "Main",
+ "text",
+ [
+ ["As designed", "#6fd88a", "#ffb067", "#ff9088"],
+ ["Simulated: protanopia", "#d9c985", "#c9b660", "#a9a187"],
+ ["Simulated: deuteranopia", "#cabf8f", "#dbc868", "#c4b886"],
+ ],
+ ],
+ [
+ "Solid",
+ "chip",
+ [
+ ["As designed", "#23913c", "#f07a13", "#d63c41"],
+ ["Simulated: protanopia", "#938434", "#9d8a00", "#686040"],
+ ["Simulated: deuteranopia", "#867b43", "#b9a50e", "#8f813c"],
+ ],
+ ],
+ [
+ "Container",
+ "chip",
+ [
+ ["As designed", "#10341a", "#382006", "#3a1613"],
+ ["Simulated: protanopia", "#342f18", "#282204", "#1f1c13"],
+ ["Simulated: deuteranopia", "#302c1c", "#2d2806", "#282412"],
+ ],
+ ],
+ ].map(([roleName, variant, rows]) => (
+
+
+ {roleName}
+
+ {rows.map(([label, success, warning, danger]) => (
+
+
{label}
+ {variant === "text" ? (
+
+ Success
+ Warning
+ Danger
+
+ ) : (
+
+
+ Success
+
+
+ Warning
+
+
+ Danger
+
+
+ )}
+
+ ))}
+
+ ))}
+
+
+
+
What the simulation shows
+
+ -
+ Under protanopia, main-role success and warning both land on a
+ similar dark olive: about 34 points apart in simulated colour,
+ closer than most people would reliably tell apart at a glance.
+
+ -
+ Under deuteranopia, the solid role gets even closer: success and
+ danger sit only about 22 points apart, both a similar muddy
+ olive-brown.
+
+ -
+ Container is the worst case. It's already the palest role, so CVD
+ simulation collapses all three towards the same washed-out beige:
+ as close as 3-15 points apart depending on the pair and the
+ deficiency. An outlined button or alert using container colour
+ alone is close to unreadable as a status signal under CVD.
+
+ -
+ Dark mode isn't a safer version of this. Main-role success and
+ warning already have almost the same luminance to begin with
+ (0.543 vs 0.533), so lightness, usually the fallback that survives
+ CVD, doesn't help separate them there either. Solid role is worse
+ in dark mode than light: under deuteranopia, success and danger
+ land only about 13 points apart, tighter than any pairing in light
+ mode.
+
+
+
+
+
+
+### What this means in practice
+
+
+ -
+ Never rely on hue alone between status colours, even where they look
+ obviously distinct to typical vision. Pair colour with an icon, label, or
+ position, the same rule this doc already gives for colour generally.
+
+ -
+ Icons should differ in shape, not just colour. A filled circle versus a
+ filled triangle survives CVD; a green circle versus a red circle does
+ not.
+
+ -
+ If a design puts success, warning, and danger states next to each other
+ (a status legend, a results table), check it against a CVD simulator, not
+ just by eye.
+
+ -
+ Where lightness is being relied on as a fallback, confirm it actually
+ differs enough to matter. Sitting close in lightness, as{" "}
+
--ds-success and --ds-warning currently do in
+ dark mode, removes that fallback along with the hue.
+
+
+
+This is a current gap in the token values, not something already handled,
+worth raising with whoever owns the palette rather than assumed solved.
+
+### Why APCA, not WCAG ratio alone
+
+The clearest case of this in DiamondDS is the Warning button. Judged purely by
+WCAG 2.2's contrast ratio, black text scores _higher_ on the warning surface
+than white text does: it's the pairing the ratio math would point you
+towards. In practice it's the one that vibrates and strains against the
+saturated orange. APCA's polarity-aware model agrees with what the eye
+actually sees, which is why the token ships white text instead:
+
+
+
+
+ Light: Warning button
+
+
+ --ds-warning-solid: #e97b12
+
+
+
+
+ WCAG 2.2 would favour this: 5.9:1, clears AA
+
+
+ Beamline temperature near limit
+
+
APCA Lc ≈ 48, reads as strained
+
+
+
+ What we ship: 2.9:1, fails AA on the ratio alone
+
+
+ Beamline temperature near limit
+
+
APCA Lc ≈ 60, reads as legible
+
+
+
+
+
+ Dark: Warning button
+
+
+ --ds-warning-solid: #f07a13
+
+
+
+
+ WCAG 2.2 would favour this: 6.1:1, clears AA
+
+
+ Beamline temperature near limit
+
+
APCA Lc ≈ 49, reads as strained
+
+
+
+ What we ship: 2.8:1, fails AA on the ratio alone
+
+
+ Beamline temperature near limit
+
+
APCA Lc ≈ 59, reads as legible
+
+
+
+
+
+
+
How to read this
+
+ -
+ WCAG 2.2's ratio is polarity-blind: it rates black-on-orange higher
+ than white-on-orange here, even though white is the better choice.
+
+ -
+ APCA accounts for polarity and light/dark differently, and lines up
+ with what actually reads well.
+
+ -
+ This is why we design with APCA first, then check WCAG 2.2 as the
+ compliance floor, not the other way round.
+
+
+
+
+
+
+### An open trade-off: obvious, readable, compliant
+
+Choosing a status colour means balancing three things that don't always pull
+the same direction:
+
+
+ -
+ Obvious: the colour still reads as its meaning. A danger
+ red has to look like danger, not a pale accent.
+
+ -
+ Readable: the text is actually comfortable to read, which
+ is what APCA is measuring.
+
+ -
+ Compliant: it clears the WCAG 2.2 floor.
+
+
+
+Pushing hard on readability and compliance can quietly erode "obvious": the
+more you lighten a saturated colour to raise its contrast, the closer it gets
+to just being pale, and at some point it stops reading as that colour at all.
+This isn't hypothetical: it's an open question in DiamondDS today, not a
+solved one:
+
+
+
+
+ Light: Danger text on surface
+
+
+ --ds-danger: #ae1e13
+
+
+
+
+ Shipped today: 7.0:1, clears WCAG
+
+
Connection to detector lost: retry required
+
+ APCA Lc ≈ 83, still just under where APCA would like
+ body-sized text
+
+
+
+
+ Pushed further for compliance: 9.9:1
+
+
Connection to detector lost: retry required
+
+ APCA Lc ≈ 91, and #8a0000 still reads plainly as
+ danger red: a deep brick red, not a different colour.
+ Darkening barely costs "obvious" anything here.
+
+
+
+
+
+
+ Dark: Danger text on surface
+
+
+ --ds-danger: #ff9088
+
+
+
+
+ Shipped today: 8.1:1, comfortably clears WCAG
+
+
Connection to detector lost: retry required
+
+ APCA Lc ≈ 58, below where APCA would like body-sized text, but
+ still unmistakably read as danger red
+
+
+
+
+ Pushed further for compliance: 14.5:1
+
+
Connection to detector lost: retry required
+
+ APCA Lc ≈ 92, but #ffe2e0 is only a few RGB points
+ off white (255, 226, 224). Say it plainly: this no longer
+ reads as red at all, let alone danger. Obvious has been
+ traded away to get there.
+
+
+
+
+
+
+
+
Where this stands
+
+ - WCAG alone would call both of today's colours done. Neither fully is: APCA still flags them for regular-sized text.
+ -
+ The trade-off isn't symmetric. In light mode, closing the gap means
+ darkening towards a deeper red, which barely touches "obvious." In
+ dark mode, closing the same gap means lightening towards white,
+ which erases it.
+
+ -
+ We're weighing a smaller, more careful adjustment, most likely in
+ dark mode where the gap actually costs something, against
+ documenting this as a known limitation for now. Either way, this is
+ a live example of the balance, not a finished answer.
+
+
+
+
+
+
+## Practical guidance
+
+
+ -
+ Body text: optimise for perceptual readability first, then
+ confirm WCAG 2.2 compliance.
+
+ -
+ UI chrome: maintain clear separation and predictable
+ hierarchy through surface and border roles.
+
+ -
+ Subtle text: only use for non-essential information.
+
+ -
+ Disabled states: must remain distinguishable without
+ becoming unreadable.
+
+
+
+## Common pitfalls
+
+
+ - Relying on WCAG ratios alone to judge readability.
+ -
+ Reducing contrast for visual subtlety where meaning is still required.
+
+ - Using saturated colours without perceptual validation.
+ - Ignoring polarity differences between light and dark mode.
+
+
+## When WCAG and APCA disagree
+
+
+ - If WCAG 2.2 fails, the colour must change.
+ -
+ If WCAG 2.2 passes but APCA still indicates poor readability, improve the
+ colour choice rather than treating compliance as enough.
+
+ -
+ In critical workflows, readability and accuracy take precedence over visual
+ subtlety.
+
+
+
+## Future: WCAG 3 and APCA
+
+WCAG 3 is still evolving, but perceptual contrast models such as APCA are
+influencing the direction of accessibility guidance.
+
+Our approach reflects that direction while staying grounded in current
+compliance requirements:
+
+
+ - Use perceptual contrast thinking to design and tune colour choices.
+ - Validate text contrast against WCAG 2.2 today.
+ -
+ Reduce future rework by avoiding colour decisions that are only
+ mathematically compliant.
+
+
+
+Learn more:
+
+
+
+
diff --git a/src/storybook/accessibility/02-cognitive-a11y.mdx b/src/storybook/accessibility/02-cognitive-a11y.mdx
new file mode 100644
index 00000000..60bbc7fc
--- /dev/null
+++ b/src/storybook/accessibility/02-cognitive-a11y.mdx
@@ -0,0 +1,119 @@
+import { Meta } from "@storybook/blocks";
+
+
+
+
+
+# Cognitive accessibility and usability
+
+Accessibility is not only about vision, hearing, or motor input. People also
+differ in how they process information, maintain focus, recover from errors,
+and work under pressure or fatigue.
+
+In scientific environments, these differences matter. Users may work for long
+periods, switch between multiple tools and data sources, or operate systems
+during live experiments where mistakes can be costly.
+
+This page focuses on cognitive accessibility and practical usability within
+complex scientific software.
+
+## Designing for cognitive accessibility
+
+Good accessibility and usability often come from the same decisions:
+interfaces that are clear, predictable, consistent, and forgiving.
+
+The goal is not to simplify scientific work itself, but to reduce unnecessary
+cognitive load created by the interface.
+
+## Design objectives
+
+### Help users understand what things are
+
+
+ - Use familiar patterns, terminology, and behaviours.
+ - Avoid inventing new interaction models without strong justification.
+ - Make purpose and state visible at a glance.
+ - Ensure actions and outcomes feel predictable.
+
+
+### Reduce memory burden
+
+
+ - Do not rely on users remembering hidden rules or previous states.
+ - Keep important information visible where possible.
+ - Use clear labels, grouping, and hierarchy.
+ - Support recognition over recall.
+
+
+### Help users maintain focus
+
+
+ - Avoid unnecessary distractions or competing emphasis.
+ - Use layout and spacing to separate concerns clearly.
+ - Keep navigation and interaction patterns consistent.
+ - Help users re-orient when context is lost.
+
+
+### Help users avoid and recover from errors
+
+
+ - Prevent errors where possible rather than reacting to them later.
+ - Make system status and consequences visible before actions occur.
+ - Provide clear, actionable error messages.
+ - Make recovery paths obvious and forgiving.
+
+
+### Design for long-running workflows
+
+
+ - Assume users may be tired, interrupted, or multitasking.
+ - Reduce ambiguity in high-pressure or operational situations.
+ - Keep interfaces calm, stable, and predictable.
+ - Design interactions that still make sense at the end of a long day.
+
+
+## Applying this in Storybook
+
+When reviewing components and patterns, ask:
+
+
+ - Is the interface understandable without prior knowledge?
+ - Does it rely on memory or hidden behaviour?
+ - Is important state clearly visible?
+ - Is error recovery understandable and forgiving?
+ - Would this remain clear during a long experiment session?
+
+
+## Further reading
+
+
+
+