Deployment
Branding without breaking the disclosure model
A museum, a university or a ministry running the Digital Passport will want it to look like theirs. Every visual decision on this site — colour, type scale, corner radius, content width, wordmark — is a token in @dpa/theme, so that is a configuration change rather than a fork. Use the switcher in the navigation to rebrand the page you are reading.
Why some tokens are validated and others are not
Not every colour on the page is decoration. Background, surfaces, rules, body text and the accent are chrome: change them freely, because nothing about the meaning of a passport depends on whether the page is near-black or paper-white.
The five role colours and the three coverage colours are not chrome. They tell a reader which disclosure tier they are looking at and whether a score can be trusted at all. A rebrand that quietly collapses enforcement and public into two similar blues has not restyled the site — it has introduced a disclosure bug wearing a stylesheet, and it will look completely fine to whoever shipped it.
So those eight tokens are themeable but checked. Distinctness is measured in CIELAB rather than by comparing hex values, because hex distance is a poor proxy for whether two colours look different to a person. Every theme in the repository is validated by a test, so a brand that hurts legibility fails CI instead of shipping.
| Rule | Threshold | Why |
|---|---|---|
| Body text on background | 4.5:1 | WCAG 2.2 AA for normal-size text. |
| Faint text on background | 3:1 | Labels and captions are still meant to be read. |
| Semantic colour on background | 3:1 | WCAG 1.4.11 — these are used as non-text indicators. |
| Separation between any two role colours | ΔE 22 | A just-noticeable difference is around ΔE 2.3. This is set far higher because role colours are read at small size, in a table, possibly projected, by someone who is not deliberately comparing them. |
| Separation between coverage colours | ΔE 18 | Confusing well-covered with structurally-uncovered inverts the meaning of the score printed next to it. |
The brands in this repository
Slate
The project default. Dark, low-chroma, built for long reading and for screenshots that sit inside academic documents.
- id
- slate
- scheme
- dark
- wordmark
- DPA.
- base type
- 15–16.5px
- text contrast
- 16.0:1 · faint 3.6:1
- closest roles
- public / owner — ΔE 29.6
- validator
- passes
Atrium
A light, high-legibility theme for gallery kiosks and printed handouts, where the surrounding room is bright and the screen cannot be.
- id
- atrium
- scheme
- light
- wordmark
- Atrium Collection
- base type
- 15.5–17.5px
- text contrast
- 16.4:1 · faint 4.2:1
- closest roles
- source-community / enforcement — ΔE 27.1
- validator
- passes
Campus
High-contrast and larger type, for lecture projection and for teaching the coverage argument to a room.
- id
- campus
- scheme
- dark
- wordmark
- DPA Teaching
- base type
- 16–18.5px
- text contrast
- 18.6:1 · faint 5.9:1
- closest roles
- source-community / enforcement — ΔE 44.7
- validator
- passes
Live preview
This panel carries its own data-theme, so you can hold a candidate brand next to the one the rest of the page is using instead of flipping back and forth.
Deployed by a partner institution — example branding only. — preview
Atrium Collection Bura askos, terracotta
Confidence
58/100
Register coverage
structurally-uncovered
0 of 9 registers could identify this object. The score is not about the object; it is about the paperwork around it.
Disclosure tiers
legal.holderIdentity withheld at this tierEvery colour, radius and type size in this panel came from atrium. No component was modified to produce it.
Adding your own
// packages/theme/src/themes/pinacoteca.ts
import { defineTheme } from "../define.js";
export const pinacoteca = defineTheme({
id: "pinacoteca",
label: "Pinacoteca",
description: "House brand for a civic picture gallery.",
colorScheme: "light",
identity: {
wordmark: "Brera",
wordmarkAccent: "·",
organisation: "Pinacoteca di Brera",
},
brand: { bg: "#fbfaf7", text: "#1b1a17", accent: "#8c2f39" },
});Register it in THEMES, run pnpm --filter @dpa/theme test, then deploy with NEXT_PUBLIC_THEME=pinacoteca pnpm build:web. Anything not overridden falls back to the default, so a brand is usually three or four colours rather than a stylesheet.
The validator runs over every registered theme in the test suite. Had the palette above pushed two roles together, this page would say so and CI would be red.