diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
index 7b5be244..06b272ff 100644
--- a/.storybook/preview.tsx
+++ b/.storybook/preview.tsx
@@ -69,6 +69,11 @@ const preview: Preview = {
"Installation",
"Practical Guidance",
"Working with Components",
+ "Foundations",
+ "Foundations/Theme Colours",
+ "Foundations/Colour",
+ "Foundations/Typography",
+ "Foundations/Icons",
"Helpers",
"Theme",
"Theme/Logos",
diff --git a/.storybook/storybook.css b/.storybook/storybook.css
index 36695d50..3c2f3c54 100644
--- a/.storybook/storybook.css
+++ b/.storybook/storybook.css
@@ -27,7 +27,7 @@
--sb-ds-success: #24a148;
--sb-ds-warning: #f1c21b;
--sb-ds-danger: #da1e28;
- --sb-ds-info: #3d1380;
+ --sb-ds-info: #355ec9;
--sb-ds-brand: #202945;
}
@@ -40,8 +40,10 @@ body .sbdocs:not(.MuiTypography-root) {
/* Base font */
.sbdocs:not(.MuiTypography-root),
.sbdocs p:not(.MuiTypography-root),
-.sbdocs li:not(.MuiTypography-root) {
- font-family: var(--sb-ds-font-body);
+.sbdocs li:not(.MuiTypography-root),
+.sbdocs :where(div:not(.sb-anchor, .sb-unstyled, .sb-unstyled div)),
+.sbdocs :where(span:not(.sb-anchor, .sb-unstyled, .sb-unstyled span)) {
+ font-family: var(--sb-ds-font-body) !important;
}
/* Headings use Outfit or Inter */
@@ -66,8 +68,10 @@ code:not(.MuiTypography-root),
.sbdocs pre:not(.MuiTypography-root),
.sbdocs kbd:not(.MuiTypography-root),
.sbdocs samp:not(.MuiTypography-root),
-.token:not(.MuiTypography-root) {
- font-family: var(--sb-ds-font-mono);
+.token:not(.MuiTypography-root),
+pre .language-text:not(.MuiTypography-root),
+pre .language-tsx:not(.MuiTypography-root) {
+ font-family: var(--sb-ds-font-mono) !important;
}
/* DS DOCS */
@@ -213,7 +217,7 @@ code:not(.MuiTypography-root),
}
/* Note */
-.ds-docs .ds-note {
+.ds-note {
border: 1px solid var(--sb-ds-border-subtle);
background: var(--sb-ds-surface-container-high);
border-radius: 12px;
@@ -294,3 +298,676 @@ code:not(.MuiTypography-root),
.ds-swatch-brand {
background: var(--sb-ds-brand);
}
+
+/* -------------------------------------------------------------------------- */
+/* Mode comparison */
+/* -------------------------------------------------------------------------- */
+
+.ds-docs .ds-mode-compare {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 16px;
+ margin: 24px 0 32px;
+}
+
+.ds-mode-panel {
+ padding: 16px;
+ border: 1px solid var(--ds-border-subtle);
+ border-radius: 16px;
+ background: var(--ds-background);
+ color: var(--ds-on-surface);
+}
+
+.ds-mode-panel h3 {
+ margin-top: 10px;
+ color: var(--ds-on-surface);
+}
+
+.ds-mode-panel p {
+ color: var(--ds-on-surface-variant);
+}
+
+.ds-token-grid {
+ display: grid;
+ gap: 12px;
+}
+
+.ds-token-card {
+ display: grid;
+ grid-template-columns: 44px 1fr;
+ column-gap: 12px;
+ row-gap: 2px;
+ align-items: center;
+ padding: 12px;
+ border: 1px solid var(--ds-border-subtle);
+ border-radius: 12px;
+ background: var(--ds-surface);
+ color: var(--ds-on-surface);
+}
+
+.ds-docs .ds-token-card code {
+ grid-column: 2;
+ width: fit-content;
+ background: var(--ds-surface-container) !important;
+ color: var(--ds-on-surface-variant) !important;
+ border-color: var(--ds-border-subtle) !important;
+}
+
+.ds-docs .ds-token-swatch {
+ grid-row: span 2;
+ width: 44px;
+ height: 44px;
+ border-radius: 10px;
+ border: 1px solid var(--ds-border-subtle);
+}
+
+.ds-docs .ds-bg-primary {
+ background: var(--ds-primary);
+}
+
+.ds-docs .ds-bg-primary-container {
+ background: var(--ds-primary-container);
+}
+
+.ds-docs .ds-bg-surface {
+ background: var(--ds-surface);
+}
+
+.ds-docs .ds-bg-surface-container {
+ background: var(--ds-surface-container);
+}
+
+.ds-docs .ds-bg-success {
+ background: var(--ds-success);
+}
+
+.ds-docs .ds-bg-warning {
+ background: var(--ds-warning);
+}
+
+.ds-docs .ds-bg-danger {
+ background: var(--ds-danger);
+}
+
+.ds-docs .ds-bg-info {
+ background: var(--ds-info);
+}
+
+@media (max-width: 900px) {
+ .ds-docs .ds-mode-compare {
+ grid-template-columns: 1fr;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+/* Theme Colours */
+/* -------------------------------------------------------------------------- */
+
+.ds-colour-page {
+ display: grid;
+ gap: 32px;
+}
+
+.ds-intent-grid {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 16px;
+}
+
+.ds-colour-family {
+ display: grid;
+ align-content: start;
+ gap: 10px;
+}
+
+.ds-colour-stack {
+ display: grid;
+ gap: 1px;
+ overflow: hidden;
+ border-radius: 12px;
+ border: 1px solid var(--ds-border-subtle);
+}
+
+.ds-colour-row {
+ min-height: 42px;
+ padding: 8px 10px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+}
+.ds-colour-row span {
+ line-height: 1.3;
+ font-size: 14px;
+}
+.ds-colour-row code,
+.ds-border-card code {
+ font-family: var(--ds-font-family-mono, monospace);
+ font-size: 0.75rem;
+ opacity: 0.8;
+}
+
+.ds-border-card {
+ min-height: 72px;
+ padding: 16px;
+ display: grid;
+ gap: 8px;
+ border-radius: 12px;
+ background: var(--ds-surface);
+ color: var(--ds-on-surface);
+}
+
+@media (max-width: 1100px) {
+ .ds-intent-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .ds-border-grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+@media (max-width: 700px) {
+ .ds-intent-grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+.ds-neutral-grid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 16px;
+}
+
+section.ds-mode-panel section {
+ margin-bottom: 16px;
+}
+
+/* Neutral foregrounds */
+
+.ds-fg-primary {
+ color: var(--ds-on-surface);
+}
+
+.ds-fg-surface {
+ color: var(--ds-surface);
+}
+
+.ds-fg-on-surface-disabled {
+ color: var(--ds-on-surface-disabled);
+}
+
+@media (max-width: 700px) {
+ .ds-neutral-grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+/* Colour Tokens */
+/* -------------------------------------------------------------------------- */
+
+/* Intent backgrounds */
+
+.ds-bg-primary-main {
+ background: var(--ds-primary);
+}
+.ds-bg-primary-dark {
+ background: var(--ds-primary-emphasis);
+}
+.ds-bg-primary-light {
+ background: var(--ds-primary-accent);
+}
+.ds-bg-primary-container {
+ background: var(--ds-primary-container);
+}
+.ds-bg-primary-on-container {
+ background: var(--ds-on-primary-container);
+}
+.ds-bg-primary-solid {
+ background: var(--ds-primary-solid);
+}
+.ds-bg-primary-on-solid {
+ background: var(--ds-on-primary-solid);
+}
+
+.ds-bg-secondary-main {
+ background: var(--ds-secondary);
+}
+.ds-bg-secondary-dark {
+ background: var(--ds-secondary-emphasis);
+}
+.ds-bg-secondary-light {
+ background: var(--ds-secondary-accent);
+}
+.ds-bg-secondary-container {
+ background: var(--ds-secondary-container);
+}
+.ds-bg-secondary-on-container {
+ background: var(--ds-on-secondary-container);
+}
+.ds-bg-secondary-solid {
+ background: var(--ds-secondary-solid);
+}
+.ds-bg-secondary-on-solid {
+ background: var(--ds-on-secondary-solid);
+}
+
+.ds-bg-tertiary-main {
+ background: var(--ds-tertiary);
+}
+.ds-bg-tertiary-dark {
+ background: var(--ds-tertiary-emphasis);
+}
+.ds-bg-tertiary-light {
+ background: var(--ds-tertiary-accent);
+}
+.ds-bg-tertiary-container {
+ background: var(--ds-tertiary-container);
+}
+.ds-bg-tertiary-on-container {
+ background: var(--ds-on-tertiary-container);
+}
+.ds-bg-tertiary-solid {
+ background: var(--ds-tertiary-solid);
+}
+.ds-bg-tertiary-on-solid {
+ background: var(--ds-on-tertiary-solid);
+}
+
+.ds-bg-brand-main {
+ background: var(--ds-brand);
+}
+.ds-bg-brand-dark {
+ background: var(--ds-brand-emphasis);
+}
+.ds-bg-brand-light {
+ background: var(--ds-brand-accent);
+}
+.ds-bg-brand-container {
+ background: var(--ds-brand-container);
+}
+.ds-bg-brand-on-container {
+ background: var(--ds-on-brand-container);
+}
+.ds-bg-brand-solid {
+ background: var(--ds-brand-solid);
+}
+.ds-bg-brand-on-solid {
+ background: var(--ds-on-brand-solid);
+}
+.ds-bg-brand-fixed {
+ background: var(--ds-brand-fixed);
+}
+.ds-bg-brand-fixed-dim {
+ background: var(--ds-brand-fixed-dim);
+}
+.ds-bg-brand-on-fixed {
+ background: var(--ds-on-brand-fixed);
+}
+
+.ds-bg-danger-main {
+ background: var(--ds-danger);
+}
+.ds-bg-danger-dark {
+ background: var(--ds-danger-emphasis);
+}
+.ds-bg-danger-light {
+ background: var(--ds-danger-accent);
+}
+.ds-bg-danger-container {
+ background: var(--ds-danger-container);
+}
+.ds-bg-danger-on-container {
+ background: var(--ds-on-danger-container);
+}
+.ds-bg-danger-solid {
+ background: var(--ds-danger-solid);
+}
+.ds-bg-danger-on-solid {
+ background: var(--ds-on-danger-solid);
+}
+
+.ds-bg-warning-main {
+ background: var(--ds-warning);
+}
+.ds-bg-warning-dark {
+ background: var(--ds-warning-emphasis);
+}
+.ds-bg-warning-light {
+ background: var(--ds-warning-accent);
+}
+.ds-bg-warning-container {
+ background: var(--ds-warning-container);
+}
+.ds-bg-warning-on-container {
+ background: var(--ds-on-warning-container);
+}
+.ds-bg-warning-solid {
+ background: var(--ds-warning-solid);
+}
+.ds-bg-warning-on-solid {
+ background: var(--ds-on-warning-solid);
+}
+
+.ds-bg-success-main {
+ background: var(--ds-success);
+}
+.ds-bg-success-dark {
+ background: var(--ds-success-emphasis);
+}
+.ds-bg-success-light {
+ background: var(--ds-success-accent);
+}
+.ds-bg-success-container {
+ background: var(--ds-success-container);
+}
+.ds-bg-success-on-container {
+ background: var(--ds-on-success-container);
+}
+.ds-bg-success-solid {
+ background: var(--ds-success-solid);
+}
+.ds-bg-success-on-solid {
+ background: var(--ds-on-success-solid);
+}
+
+.ds-bg-info-main {
+ background: var(--ds-info);
+}
+.ds-bg-info-dark {
+ background: var(--ds-info-emphasis);
+}
+.ds-bg-info-light {
+ background: var(--ds-info-accent);
+}
+.ds-bg-info-container {
+ background: var(--ds-info-container);
+}
+.ds-bg-info-on-container {
+ background: var(--ds-on-info-container);
+}
+.ds-bg-info-solid {
+ background: var(--ds-info-solid);
+}
+.ds-bg-info-on-solid {
+ background: var(--ds-on-info-solid);
+}
+
+/* Foregrounds */
+
+.ds-fg-primary-contrast,
+.ds-fg-secondary-contrast,
+.ds-fg-tertiary-contrast,
+.ds-fg-brand-contrast,
+.ds-fg-danger-contrast,
+.ds-fg-warning-contrast,
+.ds-fg-success-contrast,
+.ds-fg-info-contrast {
+ color: var(--ds-on-solid);
+}
+
+.ds-fg-primary-contrast {
+ color: var(--ds-on-primary);
+}
+
+.ds-fg-secondary-contrast {
+ color: var(--ds-on-secondary);
+}
+
+.ds-fg-tertiary-contrast {
+ color: var(--ds-on-tertiary);
+}
+
+.ds-fg-brand-contrast {
+ color: var(--ds-on-brand);
+}
+
+.ds-fg-danger-contrast {
+ color: var(--ds-on-danger);
+}
+
+.ds-fg-warning-contrast {
+ color: var(--ds-on-warning);
+}
+
+.ds-fg-success-contrast {
+ color: var(--ds-on-success);
+}
+
+.ds-fg-info-contrast {
+ color: var(--ds-on-info);
+}
+
+.ds-fg-primary-container {
+ color: var(--ds-primary-container);
+}
+.ds-fg-primary-on-container {
+ color: var(--ds-on-primary-container);
+}
+.ds-fg-primary-solid {
+ color: var(--ds-primary-solid);
+}
+.ds-fg-primary-on-solid {
+ color: var(--ds-on-primary-solid);
+}
+.ds-fg-primary-fixed {
+ color: var(--ds-primary-fixed);
+}
+.ds-fg-primary-on-fixed {
+ color: var(--ds-on-primary-fixed);
+}
+
+.ds-fg-secondary-container {
+ color: var(--ds-secondary-container);
+}
+.ds-fg-secondary-on-container {
+ color: var(--ds-on-secondary-container);
+}
+.ds-fg-secondary-solid {
+ color: var(--ds-secondary-solid);
+}
+.ds-fg-secondary-on-solid {
+ color: var(--ds-on-secondary-solid);
+}
+.ds-fg-secondary-fixed {
+ color: var(--ds-secondary-fixed);
+}
+.ds-fg-secondary-on-fixed {
+ color: var(--ds-on-secondary-fixed);
+}
+
+.ds-fg-tertiary-container {
+ color: var(--ds-tertiary-container);
+}
+.ds-fg-tertiary-on-container {
+ color: var(--ds-on-tertiary-container);
+}
+.ds-fg-tertiary-solid {
+ color: var(--ds-tertiary-solid);
+}
+.ds-fg-tertiary-on-solid {
+ color: var(--ds-on-tertiary-solid);
+}
+.ds-fg-tertiary-fixed {
+ color: var(--ds-tertiary-fixed);
+}
+.ds-fg-tertiary-on-fixed {
+ color: var(--ds-on-tertiary-fixed);
+}
+
+.ds-fg-brand-container {
+ color: var(--ds-brand-container);
+}
+.ds-fg-brand-on-container {
+ color: var(--ds-on-brand-container);
+}
+.ds-fg-brand-solid {
+ color: var(--ds-brand-solid);
+}
+.ds-fg-brand-on-solid {
+ color: var(--ds-on-brand-solid);
+}
+.ds-fg-brand-fixed {
+ color: var(--ds-brand-fixed);
+}
+.ds-fg-brand-on-fixed {
+ color: var(--ds-on-brand-fixed);
+}
+
+.ds-fg-danger-container {
+ color: var(--ds-danger-container);
+}
+.ds-fg-danger-on-container {
+ color: var(--ds-on-danger-container);
+}
+.ds-fg-danger-solid {
+ color: var(--ds-danger-solid);
+}
+.ds-fg-danger-on-solid {
+ color: var(--ds-on-danger-solid);
+}
+.ds-fg-danger-fixed {
+ color: var(--ds-danger-fixed);
+}
+.ds-fg-danger-on-fixed {
+ color: var(--ds-on-danger-fixed);
+}
+
+.ds-fg-warning-container {
+ color: var(--ds-warning-container);
+}
+.ds-fg-warning-on-container {
+ color: var(--ds-on-warning-container);
+}
+.ds-fg-warning-solid {
+ color: var(--ds-warning-solid);
+}
+.ds-fg-warning-on-solid {
+ color: var(--ds-on-warning-solid);
+}
+.ds-fg-warning-fixed {
+ color: var(--ds-warning-fixed);
+}
+.ds-fg-warning-on-fixed {
+ color: var(--ds-on-warning-fixed);
+}
+
+.ds-fg-success-container {
+ color: var(--ds-success-container);
+}
+.ds-fg-success-on-container {
+ color: var(--ds-on-success-container);
+}
+.ds-fg-success-solid {
+ color: var(--ds-success-solid);
+}
+.ds-fg-success-on-solid {
+ color: var(--ds-on-success-solid);
+}
+.ds-fg-success-fixed {
+ color: var(--ds-success-fixed);
+}
+.ds-fg-success-on-fixed {
+ color: var(--ds-on-success-fixed);
+}
+
+.ds-fg-info-container {
+ color: var(--ds-info-container);
+}
+.ds-fg-info-on-container {
+ color: var(--ds-on-info-container);
+}
+.ds-fg-info-solid {
+ color: var(--ds-info-solid);
+}
+.ds-fg-info-on-solid {
+ color: var(--ds-on-info-solid);
+}
+.ds-fg-info-fixed {
+ color: var(--ds-info-fixed);
+}
+.ds-fg-info-on-fixed {
+ color: var(--ds-on-info-fixed);
+}
+
+/* Neutrals */
+
+.ds-bg-background {
+ background: var(--ds-background);
+}
+.ds-bg-surface {
+ background: var(--ds-surface);
+}
+.ds-bg-surface-subtle {
+ background: var(--ds-surface-subtle);
+}
+.ds-bg-surface-strong {
+ background: var(--ds-surface-strong);
+}
+.ds-bg-surface-container {
+ background: var(--ds-surface-container);
+}
+.ds-bg-surface-container-high {
+ background: var(--ds-surface-container-high);
+}
+.ds-bg-surface-disabled {
+ background: var(--ds-surface-disabled);
+}
+.ds-bg-on-surface {
+ background: var(--ds-on-surface);
+}
+
+.ds-bg-on-surface-variant {
+ background: var(--ds-on-surface-variant);
+}
+
+.ds-bg-on-surface-subtle {
+ background: var(--ds-on-surface-subtle);
+}
+
+.ds-bg-on-surface-muted {
+ background: var(--ds-on-surface-muted);
+}
+
+.ds-bg-action-disabled {
+ background: var(--ds-action-disabled);
+}
+
+.ds-bg-placeholder {
+ background: var(--ds-placeholder);
+}
+
+.ds-bg-placeholder-focus {
+ background: var(--ds-placeholder-focus);
+}
+
+.ds-bg-on-solid {
+ background: var(--ds-on-solid);
+}
+
+.ds-bg-border-subtle {
+ background: var(--ds-border-subtle);
+}
+
+.ds-bg-border-emphasis {
+ background: var(--ds-border-emphasis);
+}
+
+.ds-bg-border-strong {
+ background: var(--ds-border-strong);
+}
+
+.ds-fg-primary {
+ color: var(--ds-on-surface);
+}
+
+.ds-border-subtle {
+ border: 1px solid var(--ds-border-subtle);
+}
+.ds-border-emphasis {
+ border: 1px solid var(--ds-border-emphasis);
+}
+.ds-border-strong {
+ border: 1px solid var(--ds-border-strong);
+}
diff --git a/src/storybook/foundation/1. colour.mdx b/src/storybook/foundation/1. colour.mdx
new file mode 100644
index 00000000..f2644e68
--- /dev/null
+++ b/src/storybook/foundation/1. colour.mdx
@@ -0,0 +1,1009 @@
+import { Meta } from "@storybook/blocks";
+
+
+
+
+
+# Colour
+
+
+ Colour helps users understand structure, meaning, and system state across
+ Diamond applications. In scientific software, colour must support complex
+ workflows, dense information displays, and operational decision-making without
+ becoming distracting or overwhelming.
+
+
+DiamondDS uses colour semantically. Colours are chosen based on purpose rather than appearance. Neutral colours provide structure and hierarchy, intent colours communicate actions and status, and brand colours express Diamond identity.
+
+Most interfaces should be built primarily from neutral colours, with semantic colours used deliberately to draw attention to actions, changes in state, warnings, errors, or other important information. This helps maintain clarity, reduces visual noise, and ensures meaningful information stands out when it matters.
+
+---
+
+
+ Colour should support understanding, not carry meaning on its own. Important
+ information should also be communicated through text, icons, labels, layout,
+ or interaction patterns.
+
+
+## Contents
+
+
+
+ - Colour principles
+ - Colour model
+ - Colour decision tree
+ - Surface model
+ - Colour anatomy
+ - Interaction states
+ - Scientific workflow guidance
+ - Data visualisation guidance
+ - Accessibility
+ - Token reference
+
+
+
+## 1. Colour principles
+
+
+### Colour supports scientific work
+
+Colour should help users understand information, state, and action without becoming visual noise. Scientific applications often display large amounts of information at the same time, so colour must be deliberate, predictable, and accessible.
+
+### Structure before meaning
+
+Use neutral colours to build hierarchy, grouping, and layout.
+
+Apply semantic colours only when meaning needs to be communicated.
+
+### Meaning before brand
+
+Action and status colours communicate behaviour and system state.
+
+Brand colours communicate Diamond identity.
+
+Brand colour should rarely be responsible for functional meaning.
+
+### Consistency over decoration
+
+The same colour role should always communicate the same thing throughout the system.
+
+Avoid using colour simply to make an interface feel more decorative.
+
+### Accessible by default
+
+Colour must never be the sole method of communication.
+
+Use labels, icons, typography, and spatial cues alongside colour.
+
+
+
+## 2. Colour model
+
+DiamondDS separates colour into three categories: **neutral**, **intent**, and **brand**.
+
+This separation helps ensure that visual structure, operational meaning, and organisational identity remain distinct.
+
+
+
+
+ | Category |
+ Purpose |
+ Typical usage |
+
+
+
+
+ |
+
+ Neutral
+ |
+ Structure and hierarchy |
+ Backgrounds, surfaces, borders, text, tables, layout |
+
+
+ |
+
+ Intent
+ |
+ Actions, status, and system meaning |
+ Buttons, alerts, validation, feedback, selected states |
+
+
+ |
+
+ Brand
+ |
+ Diamond identity |
+ Branding moments, facility identity, splash screens |
+
+
+
+
+### Neutral
+
+Neutral colours define the structure of the interface.
+
+Use neutral colours for:
+
+- Page backgrounds
+- Surfaces
+- Containers
+- Dividers
+- Tables
+- Text
+- Data-heavy interfaces
+
+Neutral should account for the majority of visible colour in most applications.
+
+### Intent
+
+Intent colours communicate behaviour, status, and meaning.
+
+Intent colours answer:
What does this mean?
+
+
+
+
+ | Intent |
+ Meaning |
+ Typical usage |
+
+
+
+
+ |
+
+ Primary
+ |
+ Main action |
+ Primary buttons, selected states, primary emphasis |
+
+
+ |
+
+ Secondary
+ |
+ Alternative or supporting action |
+ Secondary buttons, filters, supporting controls |
+
+
+ |
+
+ success
+ |
+ Valid, complete, or operational |
+ Confirmation, completion, available states |
+
+
+ |
+
+ Warning
+ |
+ Caution or attention required |
+ Risk states, thresholds, degraded conditions |
+
+
+ |
+
+ Error/Danger
+ |
+ Blocking, failed, hazardous, or destructive |
+ Errors, failed actions, destructive actions |
+
+
+ |
+
+ Info
+ |
+ Informational, contextual, or in progress |
+ Guidance, progress, system messages |
+
+
+
+
+### Brand
+
+Brand colours communicate Diamond identity.
+
+Brand colours answer:
Who are we?
+
+
+
+
✅ Use brand colour for:
+
+- Logos
+- Branded pages
+- Onboarding experiences
+- Splash screens
+- Facility identity
+
+
+
+
+
❌ Avoid using brand colour for:
+
+- Status
+- Errors
+- Warnings
+- Destructive actions
+- Operational state
+
+
+
+
+## 3. Colour decision tree
+
+When choosing a colour role, start with purpose rather than appearance.
+
+```text
+Do I need colour?
+│
+├─ No
+│ └─ Neutral
+│
+└─ Yes
+ │
+ ├─ Communicating action?
+ │ ├─ Primary
+ │ └─ Secondary
+ │
+ ├─ Communicating status?
+ │ ├─ Success
+ │ ├─ Warning
+ │ ├─ Error
+ │ └─ Info
+ │
+ └─ Communicating identity?
+ └─ Brand
+```
+
+## 4. Surface model
+
+Neutral colours establish hierarchy and depth throughout the interface.
+
+Surface roles define the relationship between areas of content, while elevation provides additional visual prominence where needed.
+
+In most Diamond applications, hierarchy should be communicated through surface roles, spacing, borders, and layout before relying on elevation.
+
+
+
+
+ | Surface level |
+ Purpose |
+ Typical usage |
+
+
+
+
+ | Background |
+ Application canvas |
+ App shell, page background, full-screen layouts |
+
+
+ | Surface |
+ Default content surface |
+ Cards, dialogs, menus, content panels |
+
+
+ | Surface container |
+ Quiet grouped surface |
+ Secondary panels, grouped controls, low-emphasis regions |
+
+
+ | Surface container high |
+ Stronger grouped surface |
+ Nested containers, selected regions, raised sections |
+
+
+ | Overlay |
+ Temporary elevated layer |
+ Menus, popovers, drawers |
+
+
+ | Modal |
+ Highest-emphasis layer |
+ Dialogs and critical workflows |
+
+
+
+
+### Surface hierarchy
+
+```text
+Background
+ └─ Surface
+ └─ Surface container
+ └─ Surface container high
+ └─ Overlay
+ └─ Modal
+```
+
+### Surface hierarchy and elevation
+
+Surface roles and elevation work together but serve different purposes.
+
+
+
+
+ | Concept | Purpose | Examples |
+
+
+
+
+ | Surface hierarchy |
+ Defines content relationships and grouping |
+ Background, Surface, Container, Overlay |
+
+
+ | Elevation | Defines visual prominence and separation |
+ Cards, menus, dialogs, temporary layers |
+
+
+
+
+A surface may use elevation, but elevation alone should not be used to communicate hierarchy.
+
+
+
+ Prefer surface hierarchy, spacing, and borders before increasing elevation.
+ Elevation should be used primarily for floating, temporary, or
+ high-attention content such as menus, popovers, and dialogs.
+
+
+
+## 5. Colour anatomy
+
+Each semantic colour role contains related tokens that support different levels of emphasis and interaction.
+
+
+
+
+ | Part |
+ Purpose |
+ Typical usage |
+
+
+
+
+ | Default/Main |
+ Core semantic colour |
+ Actions, status indicators, emphasis |
+
+
+ | Accent |
+ Supporting highlight |
+ Focus rings, highlights, supporting accents |
+
+
+ | Emphasis |
+ Stronger emphasis |
+ Hover, active, or stronger emphasis states |
+
+
+ | Container |
+ Low-emphasis semantic surface |
+ Chips, alerts, selected regions, grouped states |
+
+
+ | On Container |
+ Foreground for container |
+ Text and icons inside semantic containers |
+
+
+ | Solid |
+ High-emphasis interactive surface |
+ Contained buttons and strong interactive controls |
+
+
+ | On Solid |
+ Foreground for solid |
+ Text and icons inside solid controls |
+
+
+ | Contrast Text |
+ Foreground for the main colour |
+ Text and icons placed directly on the main colour |
+
+
+
+
+### Light and dark comparison
+
+
+
+
+
+
+
+ Primary
+ --ds-primary
+
+
+
+ Primary container
+ --ds-primary-container
+
+
+
+ Surface
+ --ds-surface
+
+
+
+
+
+
+
+
+
+ Primary
+ --ds-primary
+
+
+
+ Primary container
+ --ds-primary-container
+
+
+
+ Surface
+ --ds-surface
+
+
+
+
+
+### Container and solid patterns
+
+DiamondDS uses two primary semantic presentation patterns: **container** and **solid**.
+
+
+
+
+ | Pattern |
+ Emphasis |
+ Purpose |
+ Typical usage |
+
+
+
+
+ | Container |
+ Low |
+ Provides a semantic surface without dominating the interface |
+ Alerts, chips, selected regions, informational panels |
+
+
+ | Solid |
+ High |
+ Creates a strong interactive or semantic surface |
+ Contained buttons, primary actions, high-priority controls |
+
+
+
+
+Use **container** when meaning should be visible but quiet.
+
+Use **solid** when an action or state needs stronger emphasis.
+
+
+
+**Looking for the implementation reference?**
+
+This page explains the principles behind colour in DiamondDS. For a complete reference of every semantic theme token in light and dark mode, see **[Theme Colours](/docs/foundations-theme-colours--docs)**.
+
+
+
+## 6. Interaction states
+
+Colour changes should support interaction without becoming the only indication of state.
+
+
+
+
+ | State |
+ Purpose |
+ Guidance |
+
+
+
+
+ | Rest |
+ Default appearance |
+ Use the base semantic role for the component or surface. |
+
+
+ | Hover |
+ Pointer interaction |
+ Use a subtle change in surface, border, or emphasis. |
+
+
+ | Focus |
+ Keyboard focus |
+ Always use the focus ring. Do not rely only on colour changes. |
+
+
+ | Active |
+ Pressed state |
+ Use a stronger interaction treatment than hover. |
+
+
+ | Selected |
+ Persistent selection |
+
+ Use a clear selected treatment that remains visible after interaction.
+ |
+
+
+ | Read-only |
+ Viewable but not editable |
+
+ Content remains selectable and readable. Users can focus, copy, and
+ inspect values, but cannot modify them.
+ |
+
+
+ | Disabled |
+ Unavailable interaction |
+
+ Disabled styles always override hover, focus, active, and selected
+ states.
+ |
+
+
+
+
+### Read-only
+
+Read-only content is available for inspection but cannot be edited.
+
+Use read-only when users need access to information while preventing modification. This is common in scientific and operational workflows where values may be locked, system-generated, or controlled by permissions, but still need to be reviewed, verified, compared, copied, or referenced.
+
+
+
+ Prefer read-only over disabled whenever
+ users still need access to the underlying information. Disabled states
+ should primarily be used for unavailable actions and controls rather than
+ viewable data.
+
+
+
+Disabled content may be omitted from form submissions, skipped during keyboard navigation, unavailable to some automation and testing tools, or inaccessible to integrations and data extraction workflows. Read-only content remains part of the interface and remains available for inspection, copying, automation, and accessibility tooling.
+
+Use read-only when users need to:
+
+- Review values before making decisions.
+- Compare settings or configuration.
+- Copy text or data.
+- Reference system-generated information.
+- Access information that is currently locked for editing.
+
+Read-only content should remain:
+
+- Readable.
+- Clearly identifiable as non-editable.
+- Focusable where appropriate.
+- Selectable and copyable where appropriate.
+- Visually distinct from editable controls.
+
+Read-only content should not appear disabled.
+
+Disabled content communicates that a control is unavailable. Read-only content communicates that a value is available but cannot be changed.
+
+### Read-only vs disabled
+
+
+
+
+ | Capability |
+ Read-only |
+ Disabled |
+
+
+
+
+ | Visible |
+ ✓ |
+ ✓ |
+
+
+ | Readable |
+ ✓ |
+ ✓ |
+
+
+ | Focusable |
+ Usually |
+ ✕ |
+
+
+ | Selectable |
+ ✓ |
+ Usually not |
+
+
+ | Copyable |
+ ✓ |
+ Usually not |
+
+
+ | Submitted with forms |
+ Usually |
+ Usually not |
+
+
+ | Available to automation and integrations |
+ Usually |
+ Not always |
+
+
+ | Editable |
+ ✕ |
+ ✕ |
+
+
+
+
+### State priority
+
+When multiple states apply, use this priority order.
+
+```text
+Disabled
+ ↓
+Error
+ ↓
+Selected
+ ↓
+Active
+ ↓
+Hover
+ ↓
+Rest
+```
+
+Disabled and error states always win over other visual states.
+
+## 7. Scientific workflow guidance
+
+Scientific interfaces often contain:
+
+- Large tables
+- Live data
+- Monitoring views
+- Control panels
+- Acquisition screens
+- Alerts and operational feedback
+
+In these environments, colour must maintain a strong signal-to-noise ratio.
+
+### Do
+
+
+
+
✅ Do
+
+ - Use neutral colours for most layout and structure.
+ - Reserve semantic colours for meaningful changes in state.
+ - Use warning and error colours only when attention or action is needed.
+ - Ensure critical alerts remain visually distinct.
+ - Allow data visualisation colours to remain distinct from UI colours.
+
+
+
+
+
❌ Don’t
+
+ - Don’t use large blocks of semantic colour as decoration.
+ - Don’t colour every data point, metric, or row.
+ - Don’t use status colours for general layout structure.
+ - Don’t create multiple competing status colours in the same view.
+ - Don’t make visualisation colours compete with interface colours.
+
+
+
+
+## 8. Data visualisation guidance
+
+UI colours and visualisation colours serve different purposes.
+
+
+
+
+ | Colour system |
+ Purpose |
+ Examples |
+
+
+
+
+ | UI colours |
+ Communicate structure, actions, and status |
+ Buttons, alerts, text, borders, surfaces |
+
+
+ | Visualisation colours |
+ Communicate data categories, measurements, and trends |
+ Charts, plots, heatmaps, scientific visualisations |
+
+
+
+
+Do not reuse UI intent colours as a general chart palette.
+
+Use visualisation colours for data and UI colours for interface meaning.
+
+## 9. Accessibility
+
+Colour plays an important role in accessibility but should not be relied upon as the sole means of communication.
+
+Important information should be communicated through a combination of colour, text, icons, labels, layout, and interaction patterns.
+
+### Colour accessibility principles
+
+- Do not communicate meaning through colour alone.
+- Ensure important states remain distinguishable in both light and dark modes.
+- Pair status colours with labels, icons, or supporting text.
+- Use semantic colour tokens rather than hardcoded values.
+- Test colour usage in realistic workflows and data-dense interfaces.
+
+
+ For contrast requirements, focus indicators, and broader accessibility
+ standards, refer to the Accessibility section.
+
+
+## 10. Token reference
+
+The token reference connects DiamondDS semantic colour roles to CSS variables and MUI palette roles.
+
+Use semantic tokens and MUI palette roles in components. Avoid hardcoded hex values.
+
+### Semantic intent and brand roles
+
+Intent and brand colours follow a shared semantic structure.
+
+
+
+
+ | Token pattern |
+ MUI role |
+ Purpose |
+ Typical use |
+
+
+
+
+
+ --ds-[token]
+ |
+
+ palette.[role].main
+ |
+ Main semantic colour |
+ Actions, status communication, emphasis, identity |
+
+
+
+ --ds-on-[token]
+ |
+
+ palette.[role].contrastText
+ |
+ Foreground colour paired with the role |
+ Text and icons shown on the role colour |
+
+
+
+ --ds-[token]-emphasis
+ |
+
+ palette.[role].dark
+ |
+ Stronger variation of the role |
+ Hover, active, or stronger emphasis states |
+
+
+
+ --ds-[token]-accent
+ |
+
+ palette.[role].light
+ |
+ Lighter accent variation |
+ Focus rings, highlights, supporting accents |
+
+
+
+ --ds-[token]-container
+ |
+
+ palette.[role].container
+ |
+ Lower-emphasis role surface |
+ Chips, alerts, selected regions, grouped states |
+
+
+
+ --ds-on-[token]-container
+ |
+
+ palette.[role].onContainer
+ |
+ Foreground colour paired with role containers |
+ Text and icons inside semantic containers |
+
+
+
+ --ds-[token]-solid
+ |
+
+ palette.[role].solid
+ |
+ High-emphasis interactive surface |
+ Contained buttons and strong interactive controls |
+
+
+
+ --ds-on-[token]-solid
+ |
+
+ palette.[role].onSolid
+ |
+ Foreground colour paired with solid surfaces |
+ Text and icons inside solid controls |
+
+
+
+
+
+
Token names and MUI role names are usually aligned.
+
+ DiamondDS uses danger tokens internally, which map to the MUI
+ error palette role.
+
+
+
+### Neutral roles
+
+Neutral tokens create the structure of the interface. They should be the default choice for layout, surfaces, borders, text, and dense scientific workflows.
+
+
+
+
+ | Token |
+ MUI role |
+ Purpose |
+ Typical use |
+
+
+
+
+
+ --ds-background
+ |
+
+ background.default
+ |
+ Root application background |
+ App shell, page canvas, full-screen layouts |
+
+
+
+ --ds-surface
+ |
+
+ background.paper
+ |
+ Base content surface |
+ Cards, dialogs, menus, content panels |
+
+
+
+ --ds-surface-container
+ |
+
+ surface.subtle
+ |
+ Quiet grouped surface |
+ Secondary panels, grouped controls, low-emphasis regions |
+
+
+
+ --ds-surface-container-high
+ |
+
+ surface.strong
+ |
+ Stronger grouped surface |
+ Nested containers, selected regions, raised sections |
+
+
+
+ --ds-surface-disabled
+ |
+
+ surface.disabled
+ |
+ Disabled surface treatment |
+ Disabled filled controls and inactive regions |
+
+
+
+ --ds-on-surface
+ |
+
+ text.primary
+ |
+ Main foreground colour |
+ Primary text and icons |
+
+
+
+ --ds-on-surface-variant
+ |
+
+ text.secondary
+ |
+ Lower-emphasis foreground colour |
+ Secondary text, metadata, helper text |
+
+
+
+ --ds-on-surface-disabled
+ |
+
+ text.disabled
+ |
+ Disabled foreground colour |
+ Disabled text and icons |
+
+
+
+ --ds-action-disabled
+ |
+
+ action.disabled
+ |
+ Disabled interactive colour |
+ Disabled buttons, controls, and actions |
+
+
+
+ --ds-border-subtle
+ |
+
+ border.subtle
+ |
+ Quiet structural boundary |
+ Dividers, table lines, subtle outlines |
+
+
+
+ --ds-border-emphasis
+ |
+
+ border.emphasis
+ |
+ Stronger boundary |
+ Interactive boundaries and active regions |
+
+
+
+ --ds-border-strong
+ |
+
+ border.strong
+ |
+ Highest-emphasis neutral boundary |
+ Hover states and high-attention boundaries |
+
+
+
+
+
diff --git a/src/storybook/foundation/1.1. theme-colours.mdx b/src/storybook/foundation/1.1. theme-colours.mdx
new file mode 100644
index 00000000..ee482831
--- /dev/null
+++ b/src/storybook/foundation/1.1. theme-colours.mdx
@@ -0,0 +1,321 @@
+import { Meta } from "@storybook/addon-docs/blocks";
+
+