@medquantis/design-system 0.0.0-bootstrap.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +44 -0
  2. package/README.md +145 -2
  3. package/brand/LICENSE +8 -0
  4. package/brand/favicon/apple-touch-icon.png +0 -0
  5. package/brand/favicon/favicon.ico +0 -0
  6. package/brand/favicon/favicon.svg +1 -0
  7. package/brand/favicon/icon-192.png +0 -0
  8. package/brand/favicon/icon-512.png +0 -0
  9. package/brand/monogram-small.svg +1 -0
  10. package/brand/monogram-square.svg +1 -0
  11. package/brand/monogram.svg +1 -0
  12. package/brand/wordmark-on-light-print.svg +1 -0
  13. package/brand/wordmark-on-light.svg +1 -0
  14. package/brand/wordmark-on-navy-print.svg +1 -0
  15. package/brand/wordmark-on-navy.svg +1 -0
  16. package/css/app.css +57 -0
  17. package/css/base.css +124 -0
  18. package/css/components.css +469 -0
  19. package/css/print.css +59 -0
  20. package/css/slide.css +110 -0
  21. package/dist/kit-contract.css +73 -0
  22. package/dist/llms-full.txt +942 -0
  23. package/dist/llms.txt +39 -0
  24. package/dist/tailwind.css +116 -0
  25. package/dist/tokens.css +179 -0
  26. package/dist/tokens.json +1802 -0
  27. package/fonts/fonts.css +76 -0
  28. package/fonts/geist-mono/OFL.txt +93 -0
  29. package/fonts/geist-mono/geist-mono-latin-ext-wght-normal.woff2 +0 -0
  30. package/fonts/geist-mono/geist-mono-latin-wght-normal.woff2 +0 -0
  31. package/fonts/newsreader/OFL.txt +93 -0
  32. package/fonts/newsreader/newsreader-latin-ext-wght-italic.woff2 +0 -0
  33. package/fonts/newsreader/newsreader-latin-ext-wght-normal.woff2 +0 -0
  34. package/fonts/newsreader/newsreader-latin-wght-italic.woff2 +0 -0
  35. package/fonts/newsreader/newsreader-latin-wght-normal.woff2 +0 -0
  36. package/fonts/outfit/OFL.txt +93 -0
  37. package/fonts/outfit/outfit-latin-ext-wght-normal.woff2 +0 -0
  38. package/fonts/outfit/outfit-latin-wght-normal.woff2 +0 -0
  39. package/guidelines/LICENSE +8 -0
  40. package/guidelines/README.md +310 -0
  41. package/guidelines/accessibility.md +62 -0
  42. package/guidelines/brand.md +75 -0
  43. package/guidelines/charts.md +84 -0
  44. package/guidelines/colour.md +102 -0
  45. package/guidelines/data-patterns.md +60 -0
  46. package/guidelines/layout.md +110 -0
  47. package/guidelines/principles.md +28 -0
  48. package/guidelines/specialising.md +40 -0
  49. package/guidelines/typography.md +76 -0
  50. package/guidelines/voice.md +42 -0
  51. package/guidelines/writing.md +40 -0
  52. package/icons/LICENSE +43 -0
  53. package/icons/lucide.min.js +12 -0
  54. package/icons/manifest.json +7 -0
  55. package/package.json +66 -4
  56. package/stylelint.config.mjs +52 -0
@@ -0,0 +1,942 @@
1
+ # MedQuantis design system
2
+
3
+ > Design tokens, shared CSS, self-hosted fonts, brand files and written guidelines for every MedQuantis medium: slides, A4 reports, papers, the website, newsletters and interactive apps. Navy is the single brand accent; documents never use status colours.
4
+
5
+ Every value is a `--mq-*` CSS custom property in `tokens.css`. Use the semantic names, never the `--mq-core-*` ones, and never write a literal colour, font, radius or spacing value. Status colours (`--mq-success`, `--mq-warning`, `--mq-danger`, `--mq-info`) are for interactive apps only, always with an icon or a word. Corners are 3 px for small items and 6 px for cards; 12 px only for app dialogs, drawers and command palettes. Numbers use the straight apostrophe as thousands separator, a decimal point, a non-breaking space before `%` and after `CHF`. Copy never contains an em dash or an en dash.
6
+
7
+ The links below point at the exact release on the jsDelivr CDN; pin that version, never a range.
8
+
9
+ # Guidelines
10
+
11
+ The MedQuantis brand, writing, colour, type, layout, chart, data and accessibility rules. They apply to every medium: slides, A4 reports, papers, the website, newsletters and interactive apps. These files are © MedQuantis SA, all rights reserved (LICENSE); the tokens and CSS they describe are MIT.
12
+
13
+ | File | Covers |
14
+ | :-- | :-- |
15
+ | principles.md | The principles that decide the cases the other files do not cover |
16
+ | brand.md | Name, tagline, legal line, wordmark, monogram, favicon, icons |
17
+ | voice.md | Tone, words to prefer and avoid, languages, terminology in French, German, Italian and English |
18
+ | writing.md | No em or en dash, titles, sentences and lists, French typography |
19
+ | colour.md | Semantic colour tokens, the medium split, navy panels, states by mark style, status colours in apps |
20
+ | typography.md | Families, weights, roles, sizes and line heights |
21
+ | layout.md | Media, report skeleton, widths and spacing, radius, components, tables, app patterns, print |
22
+ | charts.md | The ordered palette, highlight on grey, sequential and diverging use, marks, legends |
23
+ | data-patterns.md | Numbers, amounts, dates, null versus zero, confidential and illustrative data |
24
+ | accessibility.md | WCAG 2.2 AA, contrast pairs, focus, targets, motion, structure |
25
+ | specialising.md | Framework neutrality, the four rules, the promotion tests, the one-off log |
26
+
27
+ The values themselves live in `tokens/` and reach these pages as `--mq-*` names; when a guideline and a token disagree, the token is right and the guideline is fixed. The generated specimen (`make specimen`) is the visual reference: when a rendering is in doubt, it decides.
28
+
29
+ # Principles
30
+
31
+ These principles decide the cases the other guidelines do not cover. When two rules seem to conflict, the earlier principle wins.
32
+
33
+ 1. **Clinical clarity.** Sober and high-contrast. Nothing is decorative unless it carries meaning: colour communicates a role, a state or an emphasis, never an ornament. Every coloured element must earn its place.
34
+ 2. **One accent.** Navy (`--mq-accent`, `#0a2463`) is the only brand accent, on every surface (ADR-0003). Everything else is a warm neutral or the blue-grey family. Interactive apps add status colours for genuine system status only (ADR-0004).
35
+ 3. **The figure before the adjective.** A claim is backed by a number, and every number can be traced to its source. Figures are the hero of a page: they get the largest type, the accent colour and room around them. Any fictitious figure says so on the page.
36
+ 4. **Calm confidence.** Pale neutral surfaces, generous whitespace, one idea per block and one hero figure per column. When a page is full, cut content before shrinking text.
37
+ 5. **Document-grade.** Every document reads as well printed on A4 or exported to PDF as on a screen. A design that only works on a screen is not finished.
38
+ 6. **Sober motion, never required.** Motion is optional, short and carries meaning (a bar grows, a line draws). Nothing loops, and print always shows the final state.
39
+ 7. **Three families, three roles.** Outfit for headings, labels and app UI; Newsreader for reading text; Geist Mono for codes, table figures and dates (typography).
40
+ 8. **One system, many media.** Slides, A4 reports, papers, the website, newsletters and apps share the same tokens. Media differ in what they may use (documents never carry status colours), never in the values themselves.
41
+
42
+ ## Where the rules live
43
+
44
+ | Topic | File |
45
+ | :-- | :-- |
46
+ | Name, tagline, legal line, logo, monogram, icons | brand.md |
47
+ | Tone, terminology in four languages | voice.md |
48
+ | Punctuation, titles, sentence and list style | writing.md |
49
+ | Colour tokens, the medium split, on-navy values | colour.md |
50
+ | Families, weights, roles and sizes | typography.md |
51
+ | Widths, spacing, radius, page and component patterns | layout.md |
52
+ | Chart palette, marks, axes, labels | charts.md |
53
+ | Numbers, amounts, dates, null versus zero, illustrative data | data-patterns.md |
54
+ | WCAG 2.2 AA, focus, contrast pairs, motion | accessibility.md |
55
+ | Using and extending the system in a consumer | specialising.md |
56
+ | Where each legacy rule went | README.md |
57
+
58
+ # Brand
59
+
60
+ ## Name
61
+
62
+ - **MedQuantis** is the company and the public brand. It is the name on every slide, report, paper, page and email a reader outside the company sees.
63
+ - It is written as one word with a capital M and a capital Q: MedQuantis. Never Medquantis, MEDQUANTIS in running text, or Med Quantis.
64
+ - **Paracel** names the technology (the engine and its data), never the company. Use it only when the sentence is about the technology itself; to a client, the company that speaks is MedQuantis.
65
+
66
+ ## Tagline
67
+
68
+ | Language | Tagline |
69
+ | :-- | :-- |
70
+ | French | L'IA suisse au service des systèmes de santé |
71
+ | German | Schweizer KI für das Gesundheitswesen |
72
+ | English | Swiss AI for healthcare systems |
73
+ | Italian | Not yet defined, owner to provide |
74
+
75
+ The French line is the reference; the German and English lines are its approved translations. Do not write an Italian tagline until the owner provides one.
76
+
77
+ ## Legal line
78
+
79
+ The footer of every document sent outside carries the legal line and the date of the document:
80
+
81
+ `MedQuantis SA · CH-1095 Lutry · medquantis.ch`
82
+
83
+ Set it in Geist Mono at the note size, tertiary text colour (`--mq-tertiary`), with the date at the right end of the same line.
84
+
85
+ On slides the legal line appears on every slide, bottom left, small and in tertiary grey, with the slide number bottom right (owner ruling 11). Use the slide footer row `mq-slide-foot` of `css/slide.css`, never `mq-foot`, which flows from the top of a slide canvas.
86
+
87
+ Material left with a reader (a deck after a meeting, a report sent outside) also carries a confidentiality mention and its date, in the document's language:
88
+
89
+ | Medium | French | German | English | Italian |
90
+ | :-- | :-- | :-- | :-- | :-- |
91
+ | Presentation | Présentation confidentielle | Präsentation vertraulich | Confidential presentation | Not yet defined, owner to provide |
92
+ | Report | Rapport confidentiel | Vertraulicher Bericht (proposed, owner to confirm) | Confidential report (proposed, owner to confirm) | Not yet defined, owner to provide |
93
+
94
+ ## Wordmark
95
+
96
+ The wordmark is the logo; no icon is required next to it. "Med" is set in Outfit 600 and "Quantis" in Outfit 300, in navy (`#0a2463`) on light backgrounds and in white on navy, at every size (owner ruling 6).
97
+
98
+ Each background has two files in `brand/`:
99
+
100
+ | File | Use |
101
+ | :-- | :-- |
102
+ | `wordmark-on-light.svg`, `wordmark-on-navy.svg` | Live text. Inline the SVG in a page that loads `fonts/fonts.css`, so the letters render in Outfit and stay selectable. |
103
+ | `wordmark-on-light-print.svg`, `wordmark-on-navy-print.svg` | Outlined letters. Use for images (`<img>` cannot load web fonts), documents, PDFs, email and anything sent to a printer. |
104
+
105
+ Rules:
106
+
107
+ - Use the on-navy file on navy and the on-light file on light backgrounds. Never recolour, stretch, outline, shadow or rearrange the wordmark.
108
+ - Inline the SVG rather than linking an external image, and remove its `width` and `height` so the page sizes it. On a report header the wordmark sits at about 198 by 44 px on screen and 162 by 36 px in print.
109
+ - A full stop in the on-navy accent (`--mq-on-navy-accent`) after a name is reserved for a one-word name on a navy cover. It is never added to the wordmark.
110
+
111
+ ## Monogram and favicon
112
+
113
+ Where the wordmark does not fit (favicon, app icon, avatar, app tile), use the monogram: a white M and Q on a navy (`#0a2463`) square with rounded corners of 8/64 of its side, M in Outfit 700 and Q in Outfit 400, centred on the cap height (owner ruling 7). The letters are outlined in every file.
114
+
115
+ | File | Use |
116
+ | :-- | :-- |
117
+ | `brand/monogram.svg` | The monogram with its rounded corners |
118
+ | `brand/monogram-square.svg` | For platforms that round icons themselves |
119
+ | `brand/monogram-small.svg` | 16 px and smaller: larger letters, M 800 and Q 600 |
120
+ | `brand/favicon/` | `favicon.svg`, `favicon.ico` (16, 32, 48), `apple-touch-icon.png` (180), `icon-192.png`, `icon-512.png` |
121
+
122
+ ## No combined logo yet
123
+
124
+ There is no lockup of the monogram and the wordmark in v1, and no on-navy variant of the monogram. Do not compose one locally: the combined logo is deferred until a real surface needs it ([issue #2](https://github.com/MedQuantis/design-system/issues/2)). Older lockups with a strapline under the wordmark are retired.
125
+
126
+ ## Icons
127
+
128
+ - Lucide only, from the pinned build in `icons/` (version and hash in `icons/manifest.json`). No second icon library, and never an emoji in place of an icon.
129
+ - Icons are offline: the pinned build or an inline SVG, never a CDN or any remote request.
130
+ - Monochrome, stroke 2, round caps and joins, colour inherited from the text. Navy on a pale navy pill (`--mq-accent-pale`), white on a navy panel inside a translucent pill (`--mq-on-navy-pill`), blue-grey (`--mq-border-strong`) in a card title bar.
131
+ - The icon pill is a small square with the 6 px radius (`--mq-radius-medium`), never a circle or a pill shape.
132
+ - An icon that carries meaning has a text label or an accessible name; a decorative icon is hidden from assistive technology.
133
+
134
+ # Voice
135
+
136
+ ## Tone
137
+
138
+ - **Expert to expert.** Write to a professional who knows the field: confident, never boastful. The work is shown, not promised.
139
+ - **Partnership.** "We" is MedQuantis, "you" is the reader's organisation. Write with the reader, not at them.
140
+ - **Numbers before adjectives.** Replace "fast", "easy" or "significant" with the figure that proves it. A claim of ease or speed without a number is cut.
141
+ - **No hype.** Do not oversell artificial intelligence; describe what the system does and how it can be checked.
142
+ - **No humour.** The material is about health insurance, public money and patients.
143
+ - **No jargon for clients.** No query languages, table names or internal system names in client material.
144
+ - **Respect the client.** In a document written for a client, do not judge the client's past choices and do not estimate their internal costs. The only figures put forward are the ones our work establishes.
145
+
146
+ ## Words
147
+
148
+ Prefer wording a reader can verify: traced to the exact clause, executable, auditable, reproducible.
149
+
150
+ Avoid: AI-powered, revolutionary, seamless, easy, simply, just. In French, also révolutionnaire, simplement, facile, juste; in German, revolutionär, einfach, nahtlos, nur; in Italian, rivoluzionario, semplicemente, facile, solo.
151
+
152
+ ## Languages
153
+
154
+ - English is the source language of shared material; French, German and Italian versions are translations of it and must read as if written in that language.
155
+ - German is formal Swiss Standard German: the reader is addressed as Sie, and the sharp s is always written ss.
156
+ - French follows French typography, including non-breaking spaces before high punctuation (writing).
157
+ - One term per concept across all four languages, taken from the table below. Product names and the names of regulatory lists keep their capitals.
158
+
159
+ ## Terminology
160
+
161
+ | Concept | French | German | Italian | English |
162
+ | :-- | :-- | :-- | :-- | :-- |
163
+ | The list of reimbursed medicines | Liste des spécialités (LS) | Spezialitätenliste (SL) | Elenco delle specialità (ES) | Specialities List (SL) |
164
+ | Federal Office of Public Health, the regulator | Office fédéral de la santé publique (OFSP) | Bundesamt für Gesundheit (BAG) | Ufficio federale della sanità pubblica (UFSP) | Federal Office of Public Health (FOPH) |
165
+ | Mandatory health insurance | assurance obligatoire des soins (AOS) | obligatorische Krankenpflegeversicherung (OKP) | assicurazione obbligatoria delle cure medico-sanitarie (AOMS) | mandatory health insurance |
166
+ | Health insurer | assureur-maladie | Krankenversicherer | assicuratore malattia | health insurer |
167
+ | Price model | modèle de prix | Preismodell | modello di prezzo | price model |
168
+ | Refund owed under a price model | restitution | Rückerstattung | restituzione | refund |
169
+ | Limitation (conditions of reimbursement) | limitation | Limitatio | limitazione | limitation |
170
+ | Prior cost approval | garantie de prise en charge | Kostengutsprache | garanzia di assunzione dei costi | cost approval |
171
+ | Health insurance ordinance, cited by article | art. 71 OAMal | Art. 71 KVV | art. 71 OAMal | Art. 71 KVV |
172
+ | The insurer's executive management | direction | Geschäftsleitung | direzione | executive management |
173
+ | Fictitious figures | chiffres illustratifs | illustrative Zahlen | cifre illustrative | illustrative figures |
174
+
175
+ The regulator is never "the board": the board, or executive management, belongs to the client.
176
+
177
+ # Writing
178
+
179
+ ## No em dash, no en dash
180
+
181
+ Never use the em dash or the en dash, in any language, in any copy: slides, reports, pages, emails, app strings, translations and these guidelines. A guideline test fails on either character in `guidelines/`.
182
+
183
+ Choose the punctuation that matches how the two parts relate:
184
+
185
+ - a second clause with its own subject becomes a new sentence;
186
+ - an aside goes between commas or in parentheses;
187
+ - a definition, an explanation or a list lead-in takes a colon;
188
+ - two balanced independent clauses take a semicolon;
189
+ - a short label pairing (a section number and its name, a scope and its period) takes a middle dot: "04 · Analytics".
190
+
191
+ A spaced hyphen used as an aside is a disguised dash and follows the same rule. Hyphens inside compound words stay ("Swiss-hosted", "nDSG-konform"). The middle dot and the arrow (→) are allowed.
192
+
193
+ When translating, never carry a dash over from the source language: restructure the sentence in the target language.
194
+
195
+ ## Titles
196
+
197
+ - Sentence case: capital on the first word and on proper nouns only.
198
+ - No full stop at the end of a title, even a title of two sentences (drop only the final one).
199
+ - Eyebrows and section labels are typed in normal case; CSS sets them in capitals (typography).
200
+
201
+ ## Sentences and lists
202
+
203
+ - Write full sentences with a subject and a verb. An idea that matters gets two or three sentences, not a bullet.
204
+ - Distrust triads and mechanical bullet lists. A list is for items that are genuinely parallel.
205
+ - Body pages: short sentences, one idea per bullet.
206
+ - Summary and agenda pages: one line per point, readable in three seconds. The detail lives in the body pages.
207
+
208
+ ## French typography
209
+
210
+ - A non-breaking space (U+00A0) before `:`, `;`, `?`, `!` and `%`.
211
+ - French quotation marks with non-breaking spaces inside: « exemple ».
212
+ - Regulatory abbreviations as listed in voice.
213
+
214
+ ## Source files
215
+
216
+ Markdown is written one line per paragraph or list item, never hard-wrapped at a fixed width. Editors wrap the display; the file keeps one logical line per paragraph.
217
+
218
+ # Colour
219
+
220
+ Use semantic tokens only. The `--mq-core-*` names hold raw values and exist so semantic tokens can point at them; a consumer never names them. Every value below is generated in `dist/tokens.css`, and every contrast ratio comes from `tokens/contrast-pairs.json`, checked by the token test and shown in the specimen.
221
+
222
+ ## The medium split
223
+
224
+ | Medium | Colours allowed | How a state is shown |
225
+ | :-- | :-- | :-- |
226
+ | Documents: slides, A4 reports, papers, newsletters, the website | Navy, the neutrals, the blue-grey family, the chart tokens | By mark style: solid, ring, pale, outline, quiet, dashed, struck through |
227
+ | Interactive apps | Everything documents use, plus `--mq-success`, `--mq-warning`, `--mq-danger`, `--mq-info` | Status colour for genuine system status only (errors, validation, alerts, confirmations), always with an icon or a word |
228
+
229
+ Documents never carry green, orange, red, sky blue, pink, purple or turquoise, not even to say good or bad (ADR-0004). They never load `css/app.css`. A callout in a document is always navy; there is no warning-orange or success-green callout.
230
+
231
+ ## Accent
232
+
233
+ | Token | Value | Use |
234
+ | :-- | :-- | :-- |
235
+ | `--mq-accent` | `#0a2463` | The single accent: key figures, links, active states, the key column of a table, top and edge rules, series 1, navy panels |
236
+ | `--mq-accent-hover` | `#061a4d` | Hover and pressed state of a link or an accent control, nothing else |
237
+ | `--mq-accent-pale` | `#eaeef7` | Icon pills and chips, a deviating value, the highlighted table row, the pale state |
238
+ | `--mq-accent-pale-2` | `#f2f4f9` | Progress tracks, the quiet state, callout background |
239
+ | `--mq-on-accent` | `#ffffff` | Text and icons on an accent fill (14.53:1) |
240
+
241
+ Navy carries emphasis on its own. Status colours never replace it for emphasis, in any medium.
242
+
243
+ ## Neutrals
244
+
245
+ The neutrals are warm greys tuned to the warm canvas, never blue-tinted greys.
246
+
247
+ | Token | Value | Use | Contrast |
248
+ | :-- | :-- | :-- | :-- |
249
+ | `--mq-ink` | `#1a1a1a` | Primary text and values | 16.65:1 on canvas |
250
+ | `--mq-muted` | `#555555` | Secondary text, leads, captions | 7.13:1 on canvas |
251
+ | `--mq-tertiary` | `#707070` | Tertiary text: notes, footers, axis labels, placeholders (owner ruling 1) | 4.74:1 on canvas, 4.95:1 on surface |
252
+ | `--mq-decoration` | `#8c8c8c` | Non-text decoration only: axis lines, ticks, an icon beside its label. Never text (owner ruling 1) | 3.22:1 on canvas |
253
+ | `--mq-canvas` | `#fafaf8` | Background of every document page: A4 report, paper, slide (owner ruling 9) | |
254
+ | `--mq-surface` | `#ffffff` | Cards, panels, tables, figures, inputs | |
255
+ | `--mq-surface-alt` | `#f5f4f1` | Recessed areas: table headers, tab bars, grouped areas, hover | |
256
+ | `--mq-desk` | `#e9e8e4` | On screen only, around a page preview; never inside a document, so a printed page is never grey (owner ruling 9) | |
257
+ | `--mq-border` | `#dddbd6` | Borders, dividers, chart baselines | decorative |
258
+ | `--mq-border-light` | `#ebeae6` | Hairlines between rows and columns, card borders | decorative |
259
+ | `--mq-border-strong` | `#5d6f91` | Outline of outlined and dashed state marks | 4.84:1 on canvas, non-text |
260
+
261
+ Why a warm canvas: pure white reads clinical and generic; the warm off-white reads institutional while white cards still stand out on it. Tertiary text sits exactly at 4.50:1 on `--mq-surface-alt`, so put it on canvas or surface, not on the recessed grey.
262
+
263
+ ## Navy panels and gradients
264
+
265
+ Navy panels, the report header and the navy KPI tile use a gradient between `--mq-panel-start` (`#0f2a5e`) and `--mq-panel-end` (`#0a2047`) at 160 degrees. Contrast is always checked against `--mq-panel-start`, the lighter stop and the worst case.
266
+
267
+ Text and marks on navy follow owner ruling 2. There is no sky blue anywhere.
268
+
269
+ | Token | Value | Use | On navy | On panel start | Allowed for |
270
+ | :-- | :-- | :-- | :-- | :-- | :-- |
271
+ | `--mq-on-navy-title` | `#ffffff` | Titles, figures, icons | 14.53:1 | 13.88:1 | Text |
272
+ | `--mq-on-navy-secondary` | white at 68 % | Secondary text, kickers, labels | 7.40:1 | 7.18:1 | Text |
273
+ | `--mq-on-navy-second-level` | `#c3cbdc` | Second-level text, descriptions | 8.92:1 | 8.52:1 | Text |
274
+ | `--mq-on-navy-accent` | `#8795b3` | A one-off accent: one word, one dot | 4.83:1 | 4.61:1 | Text, narrow margin |
275
+ | `--mq-on-navy-discreet` | white at 40 % | Discreet numbers | 3.48:1 | 3.44:1 | Large text or non-text only |
276
+ | `--mq-on-navy-rule`, `--mq-on-navy-rule-strong` | white at 16 and 18 % | Rules and separators | 1.61:1 | 1.62:1 | Decorative only |
277
+ | `--mq-on-navy-pill` | white at 12 % | Icon pill fill; the icon on it stays white (10.31:1) | 1.41:1 | | Decorative only |
278
+
279
+ Use white icons on navy, including Lucide icons (set the SVG stroke). One large navy block per screen or page area (layout).
280
+
281
+ ## States by mark style (documents)
282
+
283
+ | Mark | Look | Meaning |
284
+ | :-- | :-- | :-- |
285
+ | Solid | Navy fill, white text | Acquired, paid, confirmed |
286
+ | Ring | White fill, navy outline and text | Approved, validated, in progress |
287
+ | Pale | Pale navy fill, navy text | Corrected, for information |
288
+ | Outline | White fill, blue-grey outline, ink text | Neutral, pending |
289
+ | Quiet | Quiet pale fill, muted text | Withdrawn, excluded, not applicable |
290
+ | Dashed | Dashed blue-grey outline, muted text | Upcoming, not yet claimed, on the roadmap |
291
+ | Struck through | Text struck through in blue-grey 2 | Excluded from the total |
292
+
293
+ The first six are the `mq-badge` states (`is-solid`, `is-ring`, `is-pale`, `is-outline`, `is-quiet`, `is-dashed`); the struck-through row is a table pattern without a shared class yet (layout). A page that uses them gives their key once (accessibility).
294
+
295
+ ## Status colours (apps only)
296
+
297
+ | Token | Value | Use | Contrast |
298
+ | :-- | :-- | :-- | :-- |
299
+ | `--mq-success` | `#2e7d32` | Confirmation, published, valid | 5.13:1 on surface, 4.91:1 on canvas |
300
+ | `--mq-danger` | `#d8232a` | Errors, destructive actions | 5.01:1 on surface, 4.79:1 on canvas |
301
+ | `--mq-info` | `#1565c0` | Information | 5.75:1 on surface, 5.50:1 on canvas |
302
+ | `--mq-warning` | `#a06400` | Warning text, icons and borders | 4.86:1 on surface, 4.65:1 on canvas |
303
+ | `--mq-warning-fill` | `#d4850a` | Warning badge or highlight fill, always with ink text (5.93:1) | Fill only |
304
+ | `--mq-warning-tint` | `#fbf3e7` | Warning background behind ink text (15.81:1) | Fill only |
305
+
306
+ The warning split (owner ruling 5): the orange `#d4850a` is a fill and never text, an icon or a border (2.81:1 on canvas). Text on it is ink; white on it is forbidden (2.93:1). On the warning tint, the text stays ink and `--mq-warning` is used only for the icon and the border (4.42:1, non-text).
307
+
308
+ Every status colour comes with an icon or a word (WCAG 1.4.1):
309
+
310
+ - a status badge carries its word, an urgent flag adds an icon and a border (`mq-status` in `css/app.css`);
311
+ - a status column shows a small coloured dot followed by the plain word, not a badge;
312
+ - a flag is a coloured word, and only on the rows that need attention, so normal rows stay quiet;
313
+ - light badge backgrounds come from the 50 and 100 steps of the status scales in `dist/tailwind.css`, never a hand-picked tint.
314
+
315
+ The red of the old Paracel theme survives only as `--mq-danger` (ADR-0003). App-specific hues, such as the annotation colours of regulatory text, stay local in the app under its own prefix until a second consumer needs them (specialising).
316
+
317
+ ## Chart colours
318
+
319
+ The chart tokens (`--mq-chart-series-1` to `--mq-chart-series-4`, `--mq-chart-rest`, `--mq-chart-axis`, `--mq-chart-baseline`) and their order are in charts.
320
+
321
+ # Typography
322
+
323
+ ## Three families, three roles
324
+
325
+ | Family | Token | Role |
326
+ | :-- | :-- | :-- |
327
+ | Outfit | `--mq-font-family-heading`, `--mq-font-family-ui` | Headings, column titles, hero figures, labels, table text, takeaways; the whole UI of apps (navigation, buttons, badges, UI body text) |
328
+ | Newsreader | `--mq-font-family-body` | Reading text: body of documents and slides, leads, captions, notes, quoted official text, and regulatory text in apps. The only serif (owner ruling 10) |
329
+ | Geist Mono | `--mq-font-family-mono` | Codes, figures in tables, dates in tables, eyebrows, axis labels, identifiers |
330
+
331
+ Georgia and Times New Roman appear only as fallbacks. The three families are self-hosted (`fonts/fonts.css`, variable woff2 with latin and latin-ext); no page loads a font from a remote service. Newsreader ships its true italic, so leads and notes are never a slanted roman.
332
+
333
+ Outfit was chosen because it reads cleanly from a display title down to an 11 px badge, with a geometric, contemporary character that stays distinct from the generic interface sans-serifs.
334
+
335
+ ## Weights
336
+
337
+ | Weight | Token | Use |
338
+ | :-- | :-- | :-- |
339
+ | Outfit 500 | `--mq-font-weight-heading` | Every heading, column title, hero figure, KPI value, label, button label and badge (owner ruling 4) |
340
+ | Outfit 600 | `--mq-font-weight-emphasis` | Only a short highlighted word inside body text, as the "Med" of the wordmark. Bold inside Newsreader prose switches to Outfit 600 at about 0.94 em |
341
+ | Outfit 400 | `--mq-font-weight-body` | App UI body text |
342
+ | Outfit 300 | `--mq-font-weight-light` | Only the "Quantis" half of the wordmark |
343
+ | Newsreader 400 | `--mq-font-weight-body` | Reading text, with its italic for leads and notes |
344
+ | Geist Mono 400 and 500 | | Table figures and codes 400, eyebrows 500 |
345
+
346
+ Weights 700 and 800 appear only inside the monogram files; no heading, button or table uses them.
347
+
348
+ ## Roles and sizes
349
+
350
+ Every size is a token. The print column gives the A4 scale for reports printed from a browser; it is not yet a token (open point).
351
+
352
+ | Role | Family and style | Screen token | Screen | Print (A4) |
353
+ | :-- | :-- | :-- | :-- | :-- |
354
+ | Hero title (`mq-display`) | Outfit 500, line height 1.04 to 1.08, letter spacing about -0.025 em | `--mq-font-size-hero-min` to `--mq-font-size-hero-max` | 34 to 56 px | 26 pt |
355
+ | Slide title (`mq-slide-title`) | Outfit 500, line height 1.15 | `--mq-font-size-slide-title` | 36 px | |
356
+ | Section title (`mq-title`) | Outfit 500, line height 1.15, about -0.015 em | `--mq-font-size-h2` | 32 px | 17 pt |
357
+ | Subsection, card and column title (`mq-subtitle`, `mq-card-title`) | Outfit 500, about -0.01 em | `--mq-font-size-h3` | 20 px | 12.5 pt |
358
+ | Lead (`mq-lead`) | Newsreader italic, muted, line height 1.5 | `--mq-font-size-lead` | 18 px | 11.5 pt |
359
+ | Body (`mq-doc`, `mq-prose`) | Newsreader 400, line height 1.6 | `--mq-font-size-body` | 16.5 px | 10 pt |
360
+ | Small text, figure caption | Newsreader | `--mq-font-size-small` | 15 px | 9.5 pt |
361
+ | Label (`mq-label`) | Outfit 500, muted | `--mq-font-size-label` | 13 px | 8.5 pt |
362
+ | Eyebrow (`mq-eyebrow`) | Geist Mono 500, capitals, letter spacing 0.16 to 0.18 em, navy | `--mq-font-size-eyebrow` | 11 px | 7.5 pt |
363
+ | Hero figure (`mq-figure`) | Outfit 500, tabular figures, navy | `--mq-font-size-figure` | 50 px | 28 pt |
364
+ | KPI value (`mq-kpi-value`) | Outfit 500, tabular figures | `--mq-font-size-kpi` | 30 px | 17 pt |
365
+ | Counter value | Outfit 500, tabular figures, navy | `--mq-font-size-stat` | 24 px | 14 pt |
366
+ | Table header | Geist Mono, capitals, small letter spacing | `--mq-font-size-table-header` | 11 px | 7 pt |
367
+ | Table figure (`mq-num`) | Geist Mono 400, tabular figures, right-aligned | `--mq-font-size-table-cell` | 13 px | 8.5 pt |
368
+ | Table text | Outfit 500 (first column) or Newsreader | `--mq-font-size-table-text` | 14 px | 8.5 pt |
369
+ | Takeaway (`mq-takeaway`) | Outfit 500 | `--mq-font-size-takeaway` | 16 px | 10.5 pt |
370
+ | Note, source, illustrative mention (`mq-note`, `mq-foot`) | Newsreader italic, tertiary | `--mq-font-size-note` | 12.5 px | 8 pt |
371
+ | Chart axis label | Geist Mono, tertiary | `--mq-font-size-axis` | 11 px | about 8 pt on paper |
372
+
373
+ Rules:
374
+
375
+ - **Floor:** no text below 11 px on screen, in any medium, including table headers and badges.
376
+ - **Letter spacing** is negative on titles and tightens as the size grows: about -0.01 em near 20 px, -0.015 em near 32 to 38 px, -0.025 em at 56 px and above. Body text keeps the font's own spacing.
377
+ - **Figures** always use tabular figures (`font-variant-numeric: tabular-nums`, or `mq-mono`), so columns of numbers align.
378
+ - **Eyebrows and section labels** are typed in normal case and set in capitals by CSS; a middle dot separates their parts: "02 · Amounts by year".
379
+
380
+ ## Line height
381
+
382
+ | Context | Line height |
383
+ | :-- | :-- |
384
+ | Hero titles | 1.04 to 1.08 |
385
+ | Headings, counters, stat figures | 1.15 to 1.3 |
386
+ | Leads | 1.5 |
387
+ | App UI text, labels, descriptions | 1.55 |
388
+ | Reading text in documents | 1.6 |
389
+ | Help text and longer descriptions in apps | 1.75 |
390
+ | Regulatory text in apps (dense legal prose read under time pressure) | 2.2, and 2.0 on phones |
391
+
392
+ Long regulatory text is set in Newsreader at about 15 px with that generous line height, so long German compounds stay separable line by line. Codes inside it are set in Geist Mono at 12 px on the recessed surface with the small radius. Dense tables keep tight padding; the breathing room goes to the text people read word by word.
393
+
394
+ ## App type scale
395
+
396
+ Apps use the same families and weights at UI sizes: UI body Outfit 400 at 14 px, help text 13 to 14 px at line height 1.75, labels and navigation Outfit 500 at 13 px, badges Outfit 500 at 11 px, data values Geist Mono at 12 to 13 px, page title Outfit 500. Heavier weights (600 to 800) and sizes below 11 px from older app designs are retired.
397
+
398
+ # Layout
399
+
400
+ ## Media
401
+
402
+ | Medium | Canvas | Layout |
403
+ | :-- | :-- | :-- |
404
+ | Slide | 1280 by 720 px (`--mq-slide-width`, `--mq-slide-height`, `css/slide.css`) | Fixed canvas, 72 px side margins (`--mq-space-8`), section label top left, title under it, and a footer row (`mq-slide-foot`) with the legal line bottom left and the slide number bottom right, both in tertiary mono (owner ruling 11) |
405
+ | Screen report or paper | A page that scrolls, centred, `--mq-page-width` (1040 px) wide | Flow layout: no absolute positions, no fixed heights. It is not a deck: no slide canvas inside a report |
406
+ | A4 print | 210 by 297 mm (`--mq-a4-width`, `--mq-a4-height`, `css/print.css`) | One `mq-page` per sheet on the canvas colour; on screen the pages sit on the desk |
407
+
408
+ ## Report skeleton
409
+
410
+ 1. A navy header: navy gradient, the on-navy wordmark, a mono kicker preceded by a short rule, the title in white Outfit 500, one sentence that carries the message (its first clause in white, the rest in on-navy secondary), and a row of metadata (author, scope, date) separated by on-navy rules. The header is a pattern, not yet a shared component.
411
+ 2. "In brief": three or four self-contained sentences with the figure that matters, under a 2 px navy rule.
412
+ 3. Sections. Each opens with a head (numbered eyebrow such as "02 · Amounts by year", title, one-sentence lead), then its blocks, then, when useful, one takeaway line (`mq-takeaway`).
413
+ 4. The footer (`mq-foot`): a rule, the numbered sources, then the legal line and the date (brand).
414
+
415
+ A source is cited in the text with a small superscript number in Geist Mono, navy, pointing to the numbered source list.
416
+
417
+ ## Widths and spacing
418
+
419
+ All spacing comes from the 4 and 8 px scale (`--mq-space-1` to `--mq-space-8`: 4, 8, 12, 16, 24, 32, 48, 72 px). No other spacing value.
420
+
421
+ | Measure | Token | Value |
422
+ | :-- | :-- | :-- |
423
+ | Page width | `--mq-page-width` | 1040 px |
424
+ | Reading measure: prose, leads, in-brief, callouts stop here | `--mq-page-measure` | 760 px |
425
+ | Side gutter | `--mq-space-6` | 32 px, 16 px (`--mq-space-4`) on phones |
426
+ | Between cards | `--mq-space-5` | 24 px |
427
+ | Between calm columns | `--mq-space-7` | 48 px |
428
+ | From a section head to its content | `--mq-space-6` | 32 px |
429
+ | Between sections | `--mq-space-8` | 72 px, 48 px on phones |
430
+
431
+ Figures, tables and grids take the full page width; running text never does.
432
+
433
+ Grids: calm columns (three columns separated by thin rules, no boxes, one hero figure each), two-column and three-column grids of cards or figures. On phones every grid becomes one column, and a band of four tiles becomes two by two.
434
+
435
+ ## Radius
436
+
437
+ Owner ruling 3, as amended on 2026-10-10:
438
+
439
+ | Token | Value | For |
440
+ | :-- | :-- | :-- |
441
+ | `--mq-radius-small` | 3 px | Small items: tags, chips, badges, inputs, buttons, progress tracks, bar ends, tooltips |
442
+ | `--mq-radius-medium` | 6 px | Cards, panels, KPI tiles, figures, icon pills, slide frames. The maximum anywhere else |
443
+ | `--mq-radius-overlay` | 12 px | Apps only: dialogs and modals, side drawers and command palettes. Never in documents, slides, cards or website media |
444
+
445
+ - No pill shapes, ever: no fully rounded buttons, tags, chips or tabs.
446
+ - A circle is allowed only for something that is genuinely round: a status dot, a numbered marker, an avatar. In Tailwind that is `rounded-full`, and only there.
447
+ - In `dist/tailwind.css` the steps `rounded`, `rounded-xs` and `rounded-sm` resolve to 3 px, `rounded-md` to `rounded-4xl` to 6 px, and `rounded-overlay` to 12 px, so no utility class can exceed the ruling. The shared stylelint config rejects any other radius.
448
+
449
+ Squared-off corners read professional and institutional; pills read consumer.
450
+
451
+ ## Elevation and navy blocks
452
+
453
+ - Cards, figures and tables: `--mq-shadow-small`. Raised panels, menus and a page or slide previewed on the desk: `--mq-shadow-medium`. Navy panels: `--mq-shadow-panel`. No shadow in print and none on chart marks.
454
+ - One large navy block per screen, slide or page area. In a report, keep the header, a navy KPI band and a navy panel apart with light content.
455
+
456
+ ## Document components
457
+
458
+ | Pattern | Shared class | Rules |
459
+ | :-- | :-- | :-- |
460
+ | Card | `mq-card` | White, light border, small shadow, 6 px radius. An optional title bar (blue-grey icon, navy title, mono note on the right on the canvas colour) is a pattern, not yet a class |
461
+ | Navy panel | `mq-panel` | Navy gradient, white title, on-navy secondary and second-level text, white icons in translucent pills |
462
+ | KPI tiles | `mq-kpis`, `mq-kpi` | Three forms: calm columns with one hero figure each; ruled counters (a navy left rule, value, muted label) in rows of three or four; a navy band (`is-navy`) or pale tiles (`is-pale`). Value above its caption, never side by side |
463
+ | Callout | `mq-callout` | A reservation or a point of attention: navy left tab, quiet pale fill, mono navy title. Always navy |
464
+ | Takeaway | `mq-takeaway` | The one sentence to remember, under a navy tab, Outfit 500 |
465
+ | Numbered rows | (pattern) | A navy circle with the number, a heading column, a body column: one line per point |
466
+ | Footer | `mq-foot` | Sources and legal line in tertiary italic, in reports and papers; never inside a slide |
467
+ | Slide footer | `mq-slide-foot` | On every slide (owner ruling 11): the legal line bottom left, the slide number bottom right, small, tertiary, Geist Mono: `<footer class="mq-slide-foot"><p>MedQuantis SA · CH-1095 Lutry · medquantis.ch</p><p class="mq-slide-number">03</p></footer>` |
468
+
469
+ ## Tables
470
+
471
+ Document tables (`mq-table`):
472
+
473
+ - Horizontal hairlines only, never vertical rules and never zebra stripes.
474
+ - Headers in Geist Mono capitals on the recessed surface; the unit goes on a second header line ("Gap" then "CHF"), never repeated in every cell.
475
+ - Figures in Geist Mono, right-aligned (`mq-num`); the first column in Outfit 500 or Newsreader.
476
+ - The key column in navy (`is-key`).
477
+ - A deviating value may sit in a pale navy pill with the small radius.
478
+ - At most one highlighted row (`tr.is-highlight`): a pale navy fill. The source pattern adds a 3 px navy edge on its first cell; the shared class does not draw it yet.
479
+ - An excluded row is struck through in blue-grey 2 and left out of the total (pattern, not yet a class).
480
+ - The total row (`tr.is-total`) sits under a 2 px navy rule; its key amount is navy.
481
+
482
+ App tables (sober tables):
483
+
484
+ - A white wrapper with a light border, the small shadow and the 6 px radius; recessed header row; row hover on the recessed surface.
485
+ - Below a minimum width (about 640 px) the table scrolls horizontally inside its wrapper, never the page.
486
+ - Do not put a badge in every column. Use three levels of visual weight so the eye rests on normal rows: small classification marks explained by a legend row under the table, a status dot followed by its word, and flags as coloured words only on the rows that need attention (colour).
487
+
488
+ ## App patterns
489
+
490
+ - **Navigation:** links in muted Outfit 500; hover in ink on the recessed surface; the active link in navy on pale navy. On tablets the navigation collapses into a menu.
491
+ - **Tabs:** underline tabs, not segmented pills. The active tab is navy with a 2 px navy underline (`--mq-stroke-strong`); hover in ink on the recessed surface. Underline tabs stay light in dense tools.
492
+ - **Breadcrumb:** inside a light bordered card; links muted, navy on hover; the separator is a single right angle quote in tertiary; the current page in ink.
493
+ - **Buttons:** primary (navy fill, white text, darker navy on hover), secondary (white, border, recessed on hover), danger outline (danger border and text, with an icon or a destructive verb), ghost (no border, muted text). One size, Outfit 500, the small radius. On phones a button row stretches to full width.
494
+ - **Empty state:** centred, a dimmed icon, an Outfit 500 title, one muted sentence, and a hint in Geist Mono tertiary.
495
+ - **Stat cards:** stable. No hover lift, no animation: reference data must not move under the pointer.
496
+ - **Breakpoints:** documents switch to one column below 720 px. Apps use 768 px (tablet: navigation menu, narrower gutters) and 480 px (phone: full-width buttons, two stat cards per row, keys of key-value rows above their values).
497
+
498
+ ## Print and PDF
499
+
500
+ - `css/print.css` prints colours exactly (`print-color-adjust: exact`), so navy headers and panels do not print white, and stops all animation.
501
+ - Every document page uses the canvas colour (owner ruling 9); the desk never reaches paper.
502
+ - Figures, cards, panels, KPI bands, callouts, takeaways, table rows and source items never split across pages, and a heading is never left alone at the foot of a page.
503
+ - Before sending a PDF, check it page by page.
504
+
505
+ ## Phones
506
+
507
+ One column, a 16 px gutter, and no horizontal scrolling of the page. Only tables and wide charts scroll, inside their own frame.
508
+
509
+ # Charts
510
+
511
+ Charts use the navy and blue-grey family only, in every medium. Status colours never colour a chart series, not even in an app; a chart that shows system status labels it in words.
512
+
513
+ ## The ordered palette
514
+
515
+ Four categorical series plus a remainder fill (owner, 2026-10-10), always used in this order, darkest first:
516
+
517
+ | Order | Token | Value | Contrast on canvas | Typical role |
518
+ | :-- | :-- | :-- | :-- | :-- |
519
+ | 1 | `--mq-chart-series-1` | `#0a2463` | 13.90:1 | The main series, the current period, the value the text discusses |
520
+ | 2 | `--mq-chart-series-2` | `#5d6f91` | 4.84:1 | The second share of a whole |
521
+ | 3 | `--mq-chart-series-3` | `#8795b3` | 2.88:1 | Other values, projections, "upcoming" dashed marks, struck values |
522
+ | 4 | `--mq-chart-series-4` | `#c3cbdc` | 1.56:1 | Previous period, reference, neutral outline |
523
+ | Remainder | `--mq-chart-rest` | `#dde3ee` | | What is left, empty or not yet: never a categorical series |
524
+
525
+ The pairs between the four series stay at least CIEDE2000 10 apart under normal vision and under protan, deutan, tritan and achromatic simulation; the remainder fill is too close to series 4, so it is drawn with a series 4 outline.
526
+
527
+ **Series 3 and 4 are below 3:1 against the page** (WCAG 1.4.11). A chart that uses them must not rely on their colour alone: label those marks directly, give them a separating outline or stroke, or add a pattern. Series 1 and 2 meet 3:1 on their own.
528
+
529
+ Rules:
530
+
531
+ - Never more than four series at once. Group the rest as "Other" in the remainder fill.
532
+ - Fix colours per series when the order means something (reference before current); never let a charting library rotate through its palette.
533
+ - Only one element is navy when the others are there for comparison.
534
+
535
+ ## Common cases
536
+
537
+ | Case | Colours |
538
+ | :-- | :-- |
539
+ | One series | Series 1 |
540
+ | Two series: reference or previous period, then current | Series 4, then series 1 |
541
+ | Parts of a whole | Series 1, series 2, remainder fill; in the legend the remainder swatch is outlined |
542
+ | States of an amount (paid, approved, claimed, not yet claimed) | Series 1, series 3, series 4 with its outline, and the upcoming part dashed in series 3; or the document mark styles of colour |
543
+ | Ranking with more than four items | Highlight on grey, below |
544
+ | Workflow stages in an app | Series 1 to 4 with the stage name as a label or legend, never status hues, never white text on series 3 or 4 |
545
+
546
+ ## Highlight on grey
547
+
548
+ To point at one item among many (a ranking, one insurer among peers), draw the item the text discusses in series 1 and every other item in series 3. When the context should recede further, such as a reference period behind the current one, use series 4. Label the highlighted item directly; the others need a label or an outline because series 3 and 4 are below 3:1.
549
+
550
+ ## Sequential and diverging use
551
+
552
+ There are no sequential or diverging ramp tokens yet.
553
+
554
+ - **Sequential:** for an ordered quantity (low to high), use the existing tokens as a light-to-dark ramp of up to five steps: `--mq-chart-rest`, `--mq-chart-series-4`, `--mq-chart-series-3`, `--mq-chart-series-2`, `--mq-chart-series-1`. Their lightness falls monotonically. Do not interpolate new values by hand; if a chart needs more steps, bin the data into five classes or ask for a ramp token.
555
+ - **Diverging:** documents have a single hue, so there is no second hue for the opposite side, and status colours are not allowed in charts. Until a diverging ramp is ruled, show the magnitude with the sequential ramp and the direction with the sign of the value and a mark style (filled for above the reference, outlined or dashed for below), with the reference line drawn as the baseline. This is an open point for the owner.
556
+
557
+ ## Marks
558
+
559
+ - **Grid and axes:** no background grid. One baseline in `--mq-chart-baseline`, 1 px. No drawn vertical axis: at most three value labels on the left, without lines. Axis lines and ticks, where drawn, use `--mq-chart-axis` (non-text).
560
+ - **Axis labels:** Geist Mono at `--mq-font-size-axis`, in tertiary text (`--mq-tertiary`), three to five ticks. Dates as `2024` or `10.2026` (data patterns).
561
+ - **Value labels:** write only the value the text discusses (the peak, the latest value), in navy; leave about 18 % headroom above the tallest mark for it.
562
+ - **Vertical bars:** rounded at the top with the small radius (3 px), square at the base, with a narrow gap between bars of a monthly series.
563
+ - **Horizontal bars:** about 8 px thick, the far end rounded with the small radius, the value in Geist Mono at the end of the bar.
564
+ - **Ring:** for parts of a whole, a thick stroke starting at the top, small gaps between arcs, no text in the centre, the legend beside it. Never a pie of more than four parts.
565
+ - **Lines:** the main series in series 1 at 2 px with round caps; a reference in series 4 at 1.5 px; a projection in series 3 at 1.5 px dashed; an end dot in navy with its value above it. No area fill under a line and no smoothing.
566
+ - **Annotations:** a dotted vertical marker in series 3 with a short sentence in Newsreader italic, muted; or a numeric note under the chart (the number in navy, then a sentence).
567
+ - **Progress bar** (`mq-progress`): a quiet pale track (`--mq-accent-pale-2`), a navy fill, the value in Geist Mono beside it; a secondary value in series 3.
568
+ - **Distribution bar** (`mq-distribution`, `mq-segment`): segments in palette order, the remainder dashed or in the remainder fill.
569
+ - **Tooltips**, where a library draws them: navy background, white text, title in Outfit, values in Geist Mono, the small radius.
570
+
571
+ Never: background grids, zebra bands, 3D, shadows on marks, area fills under lines, pies of more than four parts.
572
+
573
+ ## Ring construction
574
+
575
+ Build a ring in SVG from one circle per part, so the arcs need no path arithmetic:
576
+
577
+ 1. Every circle has the same centre and radius, `fill="none"`, `pathLength="100"` (so lengths are percentages) and a thick stroke; wrap them in a group with `transform="rotate(-90 cx cy)"` so the first arc starts at the top.
578
+ 2. Check that the values sum to 100 before drawing.
579
+ 3. Each arc is drawn with `stroke-dasharray="L G"`, where the arc length L is its value minus the gap (1 unit) and G is 100 minus L. The arc is therefore one unit shorter than its value on purpose: that unit is the gap between arcs.
580
+ 4. Each arc starts where the previous ones end: `stroke-dashoffset` is minus the running total of the previous values (0, then minus the first value, and so on).
581
+ 5. The parts take series 1, 2, 3 in order. The remainder is two circles with the same dash: a `--mq-chart-series-4` arc 2 px wider, then a `--mq-chart-rest` arc over it, so the series 4 edge shows as its outline.
582
+ 6. Set the stroke colour with `style="stroke: var(--mq-chart-series-1)"`, never a literal value. No text in the centre; the legend sits beside the ring (`mq-legend is-column`).
583
+
584
+ ## Legends
585
+
586
+ The legend is HTML (`mq-legend`, `mq-legend-item`, `mq-swatch`) placed above or beside the plot, never inside it. Beside a ring, use `mq-legend is-column`: the items in a column, each value in `mq-legend-value` at the right edge in Geist Mono, and the remainder item (`is-rest`) separated by a rule. Above a bar or line chart, use the plain `mq-legend`, one inline row. Swatches: `is-1` to `is-4`, `is-rest`, `is-outline` and `is-dashed`.
587
+
588
+ ## Size and motion
589
+
590
+ - An SVG chart takes the full width of its figure, and its text sizes are in viewBox units. Because the SVG shrinks with its figure in print, size the labels for the printed width: they should read about 8 pt on paper.
591
+ - On phones a wide chart keeps a minimum width and scrolls inside its frame.
592
+ - Motion is optional and carries meaning: bars grow from the base, a line draws, an arc sweeps, all within two seconds. It stops under `prefers-reduced-motion` and never runs in print.
593
+
594
+ # Data patterns
595
+
596
+ Every example on this page is fictitious. Where a rule asks for a non-breaking space, the example contains the real character (U+00A0), so it can be copied as is.
597
+
598
+ ## Numbers (owner ruling 8, as amended on 2026-10-10)
599
+
600
+ | Case | Write | Never |
601
+ | :-- | :-- | :-- |
602
+ | Thousands | `2'460'000`: the straight apostrophe (U+0027) | the curly apostrophe, a space, a comma, a full stop |
603
+ | Decimals | `12.5`: a decimal point, in every language | a decimal comma |
604
+ | Percentage | `12.5 %`: a non-breaking space before `%`, in every language | `12.5%`, a breaking space |
605
+ | Amount | `CHF 2'460'000`: the currency first, joined to the amount by a non-breaking space | `2'460'000 CHF`, `Fr.`, a breaking space |
606
+ | Cents | `CHF 6'826.20`; in a report, round to the franc whenever the cents add nothing | |
607
+ | Millions | `CHF 1.2 mio` (French), `CHF 1.2 Mio.` (German), `CHF 1.2 M` (English); in a sentence the word may be written out | a decimal comma |
608
+ | Negative | `−150'000`: the minus sign U+2212 | a hyphen |
609
+ | Change | `+14 %`, `−3 %`: the sign is enough | a colour or an arrow to show direction |
610
+ | Approximation | `~84`, `≈178`: approximate figures stay approximate | false precision |
611
+
612
+ The Italian abbreviation for millions is not yet defined; the owner is to provide it.
613
+
614
+ - One number format per document. Never mix two thousands separators, even when quoting a source that uses another one.
615
+ - A hero figure stays short, about seven to nine characters. The unit goes in its caption ("CHF of net gap"), not in the figure.
616
+ - A table's unit goes in its header, not in every cell (layout).
617
+ - Shares of a whole are rounded with the largest-remainder method, so the displayed percentages add up to exactly 100.
618
+ - In code, format through one function per pattern (amount, number, percentage) rather than by hand; the specimen script exports such functions.
619
+
620
+ ## Dates and periods
621
+
622
+ | Case | Write |
623
+ | :-- | :-- |
624
+ | Date | `08.10.2026`: day, month, year with full stops |
625
+ | Month (axes, tables) | `10.2026` |
626
+ | Year (axes) | `2024` |
627
+ | Period | `2019 → 2025`, with the arrow |
628
+ | Range | `2019-2025` with a plain hyphen, or in words: "3 to 6", « 3 à 6 » |
629
+
630
+ Never an en dash in a range.
631
+
632
+ ## Null versus zero
633
+
634
+ A zero is a measurement; a missing value is not. Keep them apart everywhere:
635
+
636
+ - **Zero** is written `0` (or `CHF 0`) when the value was measured and is zero.
637
+ - **Missing** (not measured, not applicable, not yet available) is never written as `0` and never left as an empty cell. Write the language's "not available" abbreviation: `n.d.` (French and Italian), `k.A.` (German), `n/a` (English), and explain it once in a note under the table or chart.
638
+ - A dash is not used for a missing value: it reads as a minus sign or a range.
639
+ - An aggregate over values that are all missing is itself missing, never a total of `0`.
640
+ - A chart leaves a gap for a missing point; it never draws it at zero.
641
+
642
+ ## Confidential values
643
+
644
+ A confidential rate, price, refund scale or commercial term is never invented and never shown, not even as an example. Show a mask instead: a lock icon followed by `••••` in Geist Mono, navy.
645
+
646
+ ## Illustrative data
647
+
648
+ - Fictitious figures are flagged on the page itself, in a note (`mq-note`): "Illustrative figures · insurers and medicines anonymised".
649
+ - Fictitious names follow ADR-0005: Assureur A, Assureur B (A being the largest), Médicament X, Médicament Y, round amounts such as `CHF 300'000`.
650
+ - Never name a real client, partner or person, never present a fictitious figure as real, and never cite a figure or a legal article that cannot be traced to its source.
651
+ - In this repository, a line holding a fictitious amount or percentage carries the marker `mq:illustrative`, on the same line or, for a whole file, in its first five lines (as this file does). Inside `examples/`, every amount and every percentage needs it; elsewhere, every currency amount does. The confidentiality check fails on an unmarked figure.
652
+
653
+ # Accessibility
654
+
655
+ ## Target
656
+
657
+ WCAG 2.2 level AA for every medium: apps, the website, HTML reports, slides exported to PDF and newsletters. APCA is not normative and is not used; contrast is measured with the WCAG 2.x formula.
658
+
659
+ ## Colour is never alone
660
+
661
+ Colour never carries meaning on its own (WCAG 1.4.1):
662
+
663
+ - documents show states by mark style (solid, ring, pale, outline, quiet, dashed, struck through) and a page that uses these marks gives their key once, in a legend or a note;
664
+ - apps pair every status colour with an icon or a word;
665
+ - charts label the marks that use series 3 or 4, or give them an outline, since those colours are below 3:1 on the page (charts);
666
+ - a change in a figure is shown by its sign, not by a colour or an arrow alone.
667
+
668
+ ## Contrast pairs
669
+
670
+ Every foreground and background pair the system uses is declared in `tokens/contrast-pairs.json` with its allowed use: text (4.5:1), large text (3:1), non-text (3:1, WCAG 1.4.11) or decorative (no minimum, for marks that carry no information). The token test checks every declared pair and fails on any pairing used in `css/` without a declaration; the specimen shows each pair with its ratio. A consumer that needs a new pair asks for it here rather than eyeballing it.
671
+
672
+ Pairs to remember:
673
+
674
+ | Pair | Ratio | Allowed for |
675
+ | :-- | :-- | :-- |
676
+ | Ink on canvas | 16.65:1 | Text |
677
+ | Muted on canvas | 7.13:1 | Text |
678
+ | Tertiary on canvas, on surface | 4.74:1, 4.95:1 | Text. Not on the recessed surface (exactly 4.50:1, not declared) |
679
+ | Decoration grey on canvas | 3.22:1 | Non-text only, never text |
680
+ | Navy on canvas | 13.90:1 | Text |
681
+ | White on navy | 14.53:1 | Text |
682
+ | On-navy accent on the lighter panel stop | 4.61:1 | Text, narrow margin |
683
+ | On-navy discreet (white at 40 %) on navy | 3.48:1 | Large text or non-text only |
684
+ | Warning text on surface | 4.86:1 | Text |
685
+ | Ink on the warning fill | 5.93:1 | Text; white on the fill is forbidden (2.93:1) |
686
+ | Blue-grey outline on canvas | 4.84:1 | Non-text |
687
+
688
+ Placeholder text in inputs uses the tertiary text colour, never a lighter grey.
689
+
690
+ ## Focus
691
+
692
+ - Every interactive element shows a visible focus ring on keyboard focus (WCAG 2.4.7 and 1.4.11): `--mq-focus-ring-width` (2 px) of `--mq-focus-ring-color` (navy, 13.90:1 on canvas) at `--mq-focus-ring-offset` (2 px) from the element.
693
+ - On navy, the ring is white (`--mq-focus-ring-color-on-navy`, 14.53:1). `css/base.css` and `css/components.css` draw both.
694
+ - Never remove the outline without drawing this ring. A focused input may also change its border to navy, but the ring stays.
695
+
696
+ ## Size and targets
697
+
698
+ - No text below 11 px on screen (typography).
699
+ - Touch targets in apps are at least 44 px high on mobile (buttons, tabs, navigation links), above the 24 px minimum of WCAG 2.5.8.
700
+ - Text reflows: pages work at 320 px wide and at 200 % zoom without horizontal page scrolling; only tables and wide charts scroll inside their frame.
701
+
702
+ ## Motion
703
+
704
+ - Motion is optional, short and meaningful. Interactive elements may use short transitions (about 120 ms) on colour and background; documents do not animate on hover.
705
+ - Never blur, zoom, reflections, spotlight effects or looping animation.
706
+ - Everything respects `prefers-reduced-motion: reduce` (no animation at all) and print shows the final state.
707
+
708
+ ## Structure
709
+
710
+ - One `h1` per page and headings in order; the eyebrow is not a heading.
711
+ - Set the page language (`lang`) and mark passages in another language.
712
+ - An SVG chart has `role="img"` and an accessible name and description (`<title>` and `<desc>`, or `aria-labelledby`); the figure's key values also appear in text or in a table.
713
+ - Icons that carry meaning have a label; decorative icons are hidden (`aria-hidden="true"`).
714
+ - PDFs exported from HTML are tagged and carry an outline (Playwright `tagged` and `outline`); the specimen test exports one.
715
+
716
+ # Specialising the design system
717
+
718
+ The design system is the single source of the MedQuantis visual identity (ADR-0002). A consumer uses it as released and adds only what it alone needs.
719
+
720
+ ## Framework neutrality
721
+
722
+ The design system ships framework-neutral outputs only: CSS custom properties (`dist/tokens.css`), resolved values (`dist/tokens.json`), a Tailwind theme (`dist/tailwind.css`), the kit contract for kit renderers (`dist/kit-contract.css`), the shared `mq-` CSS, fonts, icons and brand files. It ships no framework component.
723
+
724
+ - Wiring the tokens into a component library (Nuxt UI, shadcn/ui, Radix, MUI) belongs to the consumer. For example, a component library that names its error colour `error` maps it to `--mq-danger` in the app, not here.
725
+ - When two consumers need the same wiring, it may ship here as a separate optional export generated from the tokens, never as part of the core outputs.
726
+ - Apps with a component library take the tokens and the Tailwind theme only. They do not load the `mq-` component CSS and never load `kit-contract.css`, whose unprefixed names collide with framework variables.
727
+
728
+ ## Use what exists first
729
+
730
+ - Build documents from the shared `mq-` classes with their documented markup. Every shared class carries the `mq-` prefix so it never collides with a consumer's classes.
731
+ - Add no colour, font, shadow, radius or spacing that is not a token. When a need is not covered, combine existing components before inventing one.
732
+ - The specimen (`make specimen`, then `dist/specimen/index.html`) is the visual reference; when a rendering is in doubt, it decides.
733
+ - Pin an exact release; never a range or a branch.
734
+
735
+ ## The four rules
736
+
737
+ 1. **Core and semantic tokens are never overridden in a consumer.** A consumer does not redefine `--mq-accent` or any other `--mq-*` name.
738
+ 2. **A product-level variation is a theme in this repository**, never a local override. There is no theme in v1 (ADR-0003).
739
+ 3. **Local additions use the consumer's own prefix** (`--deck-*`, `--app-*`) and reference `var(--mq-*)` only. The shared stylelint config (`@medquantis/design-system/stylelint`) rejects literal colours, fonts and shadows, `!important`, unknown custom properties and any radius other than the three radius tokens. A repository whose dense views need a sans body may override its own body family locally under its prefix.
740
+ 4. **A component invented locally in two consumers is a candidate for promotion** into this repository.
741
+
742
+ ## Promotion tests
743
+
744
+ A local component is promoted only if it passes all four tests:
745
+
746
+ | Test | Question |
747
+ | :-- | :-- |
748
+ | Useful | Is it needed in more than one place? |
749
+ | Unique | Does it avoid duplicating an existing component? |
750
+ | Consistent | Is it built from existing tokens and styles only? |
751
+ | Versatile | Does it fit uses beyond the two that produced it? |
752
+
753
+ ## The one-off log
754
+
755
+ Every local one-off (a component or a token a consumer adds under its own prefix) is logged in `docs/one-offs.md`, one line each: the consumer, what was added, the date, and the outcome. The outcome is one of: promoted, kept local (with the reason), or replaced by an existing component. The log is how two independent one-offs are noticed and become a promotion candidate. Proposals follow the two contribution tiers of GOVERNANCE.md.
756
+
757
+ # Tokens
758
+
759
+ Every token of release 1.0.0, generated from dist/tokens.json. Consumers use the semantic names; the `--mq-core-*` names exist so semantic tokens can point at them. A deprecated token names its replacement.
760
+
761
+ ## Semantic tokens
762
+
763
+ | Token | Value | Use |
764
+ | :-- | :-- | :-- |
765
+ | `--mq-chart-series-1` | `#0a2463` | Categorical series 1 of 4, always used first; also the highlight in highlight-on-grey charts. |
766
+ | `--mq-chart-series-2` | `#5d6f91` | Categorical series 2 of 4. |
767
+ | `--mq-chart-series-3` | `#8795b3` | Categorical series 3 of 4. |
768
+ | `--mq-chart-series-4` | `#c3cbdc` | Categorical series 4 of 4; context bars in highlight-on-grey charts. |
769
+ | `--mq-chart-rest` | `#dde3ee` | Remainder or empty fill, never a categorical series; too close to series 4 under colour-vision deficiency, so draw it with a series 4 outline. |
770
+ | `--mq-chart-axis` | `#8c8c8c` | Axis lines and ticks (non-text, Owner ruling 1, 2026-10-09); axis labels use tertiary. |
771
+ | `--mq-chart-baseline` | `#dddbd6` | Gridlines and baselines (decorative). |
772
+ | `--mq-accent` | `#0a2463` | The single brand accent: links, active states, figures, navy panels (ADR-0003). |
773
+ | `--mq-accent-hover` | `#061a4d` | Hover state of accent-coloured controls. |
774
+ | `--mq-accent-pale` | `#eaeef7` | Pale accent fill for a highlighted row, tag or state. |
775
+ | `--mq-accent-pale-2` | `#f2f4f9` | Quieter pale accent fill. |
776
+ | `--mq-on-accent` | `#ffffff` | Text and icons on an accent fill, 14.53:1 on navy. |
777
+ | `--mq-ink` | `#1a1a1a` | Primary text. |
778
+ | `--mq-muted` | `#555555` | Secondary text. |
779
+ | `--mq-tertiary` | `#707070` | Owner ruling 1, 2026-10-09: tertiary text, captions and footers. |
780
+ | `--mq-decoration` | `#8c8c8c` | Owner ruling 1, 2026-10-09: non-text decoration only (axis lines, ticks, icons beside a label), never text. |
781
+ | `--mq-canvas` | `#fafaf8` | Owner ruling 9, 2026-10-09: background of every document page (A4 report, paper, slide). |
782
+ | `--mq-surface` | `#ffffff` | Owner ruling 9, 2026-10-09: cards and panels on the page. |
783
+ | `--mq-surface-alt` | `#f5f4f1` | Recessed surface: table headers, grouped areas. |
784
+ | `--mq-desk` | `#e9e8e4` | Owner ruling 9, 2026-10-09: on screen only, around a page preview; never inside a document. |
785
+ | `--mq-border` | `#dddbd6` | Borders and dividers. |
786
+ | `--mq-border-light` | `#ebeae6` | Hairlines and card borders. |
787
+ | `--mq-border-strong` | `#5d6f91` | Outline of outlined and dashed state marks in documents (badges, legend swatches), 3:1 or more on canvas and surface for WCAG 1.4.11 (increment 07 component need, ADR-0004: states by mark style). |
788
+ | `--mq-panel-start` | `#0f2a5e` | Light end of the navy panel gradient; the worst case for text on navy. |
789
+ | `--mq-panel-end` | `#0a2047` | Dark end of the navy panel gradient. |
790
+ | `--mq-on-navy-title` | `#ffffff` | Owner ruling 2, 2026-10-09: titles, figures and icons on navy. |
791
+ | `--mq-on-navy-secondary` | `rgba(255, 255, 255, 0.68)` | Owner ruling 2, 2026-10-09: secondary text and labels on navy. |
792
+ | `--mq-on-navy-second-level` | `#c3cbdc` | Owner ruling 2, 2026-10-09: second-level text on navy. |
793
+ | `--mq-on-navy-accent` | `#8795b3` | Owner ruling 2, 2026-10-09: the one-off accent on navy; replaces the retired sky blue. |
794
+ | `--mq-on-navy-rule` | `rgba(255, 255, 255, 0.16)` | Owner ruling 2, 2026-10-09: rules on navy (decorative). |
795
+ | `--mq-on-navy-rule-strong` | `rgba(255, 255, 255, 0.18)` | Owner ruling 2, 2026-10-09: stronger rules on navy (decorative). |
796
+ | `--mq-on-navy-pill` | `rgba(255, 255, 255, 0.12)` | Owner ruling 2, 2026-10-09: icon-pill fill on navy (decorative); the icon on it stays white. |
797
+ | `--mq-on-navy-discreet` | `rgba(255, 255, 255, 0.4)` | Owner ruling 2, 2026-10-09: discreet numbers on navy; 3.44:1, so large text or non-text only. |
798
+ | `--mq-success` | `#2e7d32` | Apps only: success, always with an icon or a word (ADR-0004). |
799
+ | `--mq-warning` | `#a06400` | Owner ruling 5, 2026-10-09: warning text, icons and borders; apps only (ADR-0004). |
800
+ | `--mq-danger` | `#d8232a` | Apps only: errors and destructive actions, always with an icon or a word (ADR-0003, ADR-0004). |
801
+ | `--mq-info` | `#1565c0` | Apps only: information, always with an icon or a word (ADR-0004). |
802
+ | `--mq-warning-fill` | `#d4850a` | Owner ruling 5, 2026-10-09: warning badge and highlight fill, always with ink text; white on it is forbidden (2.93:1). |
803
+ | `--mq-warning-tint` | `#fbf3e7` | Owner ruling 5, 2026-10-09: warning tint behind ink text; warning strong only for icons and borders on it. |
804
+ | `--mq-dim` | `#707070` | Deprecated: Use --mq-tertiary for text or --mq-decoration for non-text decoration. |
805
+ | `--mq-accent-on-dark` | `#8795b3` | Deprecated: Use --mq-on-navy-title for titles and rules, --mq-on-navy-accent for the one-off accent. |
806
+ | `--mq-focus-ring-color` | `#0a2463` | Focus ring on light backgrounds: 2 px navy with an offset, 13.90:1 on canvas (research note 0001, section 7). |
807
+ | `--mq-focus-ring-color-on-navy` | `#ffffff` | Focus ring on navy backgrounds, 14.53:1. |
808
+ | `--mq-focus-ring-width` | `2px` | Focus ring width (WCAG 2.4.7 and 1.4.11). |
809
+ | `--mq-focus-ring-offset` | `2px` | Gap between the focused element and its ring. |
810
+ | `--mq-radius-small` | `3px` | Owner ruling 3, 2026-10-09: tags, inputs and chips. |
811
+ | `--mq-radius-medium` | `6px` | Owner ruling 3, 2026-10-09: cards and panels. |
812
+ | `--mq-radius-overlay` | `12px` | Owner ruling 3, amended 2026-10-10: dialogs and modals, side drawers and command palettes in apps only; never in documents, slides, cards or website media. |
813
+ | `--mq-space-1` | `4px` | Spacing step 1, 4 px. |
814
+ | `--mq-space-2` | `8px` | Spacing step 2, 8 px. |
815
+ | `--mq-space-3` | `12px` | Spacing step 3, 12 px. |
816
+ | `--mq-space-4` | `16px` | Spacing step 4, 16 px. |
817
+ | `--mq-space-5` | `24px` | Spacing step 5, 24 px. |
818
+ | `--mq-space-6` | `32px` | Spacing step 6, 32 px. |
819
+ | `--mq-space-7` | `48px` | Spacing step 7, 48 px. |
820
+ | `--mq-space-8` | `72px` | Spacing step 8, 72 px. |
821
+ | `--mq-stroke-hairline` | `1px` | Hairline borders and rules (increment 07 component need). |
822
+ | `--mq-stroke-strong` | `2px` | Strong rule, as above a total row (increment 07 component need). |
823
+ | `--mq-stroke-tab` | `3px` | Navy accent tab beside a callout or takeaway (increment 07 component need). |
824
+ | `--mq-shadow-small` | `0px 1px 2px 0px rgba(0, 0, 0, 0.05)` | Cards (increment 07 component need). |
825
+ | `--mq-shadow-medium` | `0px 3px 12px 0px rgba(0, 0, 0, 0.07)` | A slide or page previewed on the desk, never in print (increment 07 component need). |
826
+ | `--mq-shadow-panel` | `0px 14px 36px 0px rgba(10, 36, 99, 0.24)` | Navy panels (increment 07 component need). |
827
+ | `--mq-slide-width` | `1280px` | Slide canvas width (increment 07 component need). |
828
+ | `--mq-slide-height` | `720px` | Slide canvas height (increment 07 component need). |
829
+ | `--mq-page-width` | `1040px` | Content width of a screen document (increment 07 component need). |
830
+ | `--mq-page-measure` | `760px` | Longest line of running text (increment 07 component need). |
831
+ | `--mq-a4-width` | `793.7px` | A4 sheet width (increment 07 component need). |
832
+ | `--mq-a4-height` | `1122.52px` | A4 sheet height (increment 07 component need). |
833
+ | `--mq-font-family-heading` | `Outfit, system-ui, -apple-system, 'Segoe UI', sans-serif` | Headings, column titles and hero figures (Owner ruling 4, 2026-10-09, Owner ruling 10, 2026-10-09). |
834
+ | `--mq-font-family-body` | `Newsreader, Georgia, 'Times New Roman', serif` | Body text of documents and slides, regulatory text in apps (Owner ruling 10, 2026-10-09). |
835
+ | `--mq-font-family-ui` | `Outfit, system-ui, -apple-system, 'Segoe UI', sans-serif` | Labels and app UI (Owner ruling 10, 2026-10-09). |
836
+ | `--mq-font-family-mono` | `'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace` | Figures and codes (Owner ruling 10, 2026-10-09). |
837
+ | `--mq-font-weight-heading` | `500` | Owner ruling 4, 2026-10-09: every heading, column title and hero figure. |
838
+ | `--mq-font-weight-emphasis` | `600` | Owner ruling 4, 2026-10-09: a short highlighted word inside body text, as the Med of the logo. |
839
+ | `--mq-font-weight-body` | `400` | Body text. |
840
+ | `--mq-font-weight-light` | `300` | Owner ruling 6, 2026-10-09: only the Quantis half of the wordmark; never for headings or body text. |
841
+ | `--mq-font-size-hero-min` | `34px` | Hero title at the narrowest viewport. |
842
+ | `--mq-font-size-hero-max` | `56px` | Hero title at the widest viewport. |
843
+ | `--mq-font-size-h2` | `32px` | Section title. |
844
+ | `--mq-font-size-h3` | `20px` | Subsection title. |
845
+ | `--mq-font-size-lead` | `18px` | Lead paragraph. |
846
+ | `--mq-font-size-body` | `16.5px` | Body text on screen. |
847
+ | `--mq-font-size-small` | `15px` | Small body text. |
848
+ | `--mq-font-size-label` | `13px` | Labels. |
849
+ | `--mq-font-size-eyebrow` | `11px` | Eyebrow above a title; 11 px is the floor for any text. |
850
+ | `--mq-font-size-figure` | `50px` | Hero figure. |
851
+ | `--mq-font-size-kpi` | `30px` | KPI value. |
852
+ | `--mq-font-size-stat` | `24px` | Statistic value. |
853
+ | `--mq-font-size-table-header` | `11px` | Table header cell. |
854
+ | `--mq-font-size-table-cell` | `13px` | Table cell with figures. |
855
+ | `--mq-font-size-table-text` | `14px` | Table cell with prose. |
856
+ | `--mq-font-size-takeaway` | `16px` | Takeaway line under a figure. |
857
+ | `--mq-font-size-note` | `12.5px` | Notes and sources. |
858
+ | `--mq-font-size-axis` | `11px` | Chart axis labels. |
859
+ | `--mq-font-size-slide-title` | `36px` | Slide title on the 1280 by 720 canvas (increment 07 component need). |
860
+
861
+ ## Core tokens (never named by a consumer)
862
+
863
+ | Token | Value | Use |
864
+ | :-- | :-- | :-- |
865
+ | `--mq-core-navy` | `#0a2463` | MedQuantis navy, the single brand accent everywhere (ADR-0003). |
866
+ | `--mq-core-navy-hover` | `#061a4d` | Navy hover state (Report design system, 2026-10-08). |
867
+ | `--mq-core-navy-2` | `#0f2a5e` | Lightest stop of the navy panel and hero gradients (Report design system, 2026-10-08). |
868
+ | `--mq-core-navy-3` | `#0a2047` | Middle stop of the navy panel and hero gradients (Report design system, 2026-10-08). |
869
+ | `--mq-core-navy-4` | `#071733` | Darkest stop of the hero gradient (Report design system, 2026-10-08). |
870
+ | `--mq-core-pale` | `#eaeef7` | Pale navy fill for a highlighted state (Report design system, 2026-10-08). |
871
+ | `--mq-core-pale-2` | `#f2f4f9` | Quieter pale navy fill (Report design system, 2026-10-08). |
872
+ | `--mq-core-bluegrey-1` | `#5d6f91` | Blue-grey 1, darkest of the secondary family (Report design system, 2026-10-08). |
873
+ | `--mq-core-bluegrey-2` | `#8795b3` | Blue-grey 2 (Report design system, 2026-10-08). |
874
+ | `--mq-core-bluegrey-3` | `#c3cbdc` | Blue-grey 3 (Report design system, 2026-10-08). |
875
+ | `--mq-core-bluegrey-4` | `#dde3ee` | Blue-grey 4, lightest of the secondary family (Report design system, 2026-10-08). |
876
+ | `--mq-core-grey-950` | `#1a1a1a` | Warm near-black (Report design system, 2026-10-08). |
877
+ | `--mq-core-grey-700` | `#555555` | Warm dark grey (Report design system, 2026-10-08). |
878
+ | `--mq-core-grey-600` | `#707070` | Owner ruling 1, 2026-10-09: the tertiary grey for all text, 4.74:1 on canvas. |
879
+ | `--mq-core-grey-500` | `#8c8c8c` | Owner ruling 1, 2026-10-09: non-text decoration only, 3.22:1 on canvas. |
880
+ | `--mq-core-grey-300` | `#dddbd6` | Warm border grey (Report design system, 2026-10-08). |
881
+ | `--mq-core-grey-250` | `#e9e8e4` | Owner ruling 9, 2026-10-09: the on-screen desk around a page preview. |
882
+ | `--mq-core-grey-200` | `#ebeae6` | Warm hairline grey (Report design system, 2026-10-08). |
883
+ | `--mq-core-grey-100` | `#f5f4f1` | Warm recessed surface (Report design system, 2026-10-08). |
884
+ | `--mq-core-grey-50` | `#fafaf8` | Owner ruling 9, 2026-10-09: warm off-white of every document page. |
885
+ | `--mq-core-white` | `#ffffff` | White (Report design system, 2026-10-08). |
886
+ | `--mq-core-white-alpha-68` | `rgba(255, 255, 255, 0.68)` | Owner ruling 2, 2026-10-09: white at 68 % for secondary text on navy. |
887
+ | `--mq-core-white-alpha-40` | `rgba(255, 255, 255, 0.4)` | Owner ruling 2, 2026-10-09: white at 40 % for discreet numbers on navy. |
888
+ | `--mq-core-white-alpha-18` | `rgba(255, 255, 255, 0.18)` | Owner ruling 2, 2026-10-09: white at 18 % for rules on navy. |
889
+ | `--mq-core-white-alpha-16` | `rgba(255, 255, 255, 0.16)` | Owner ruling 2, 2026-10-09: white at 16 % for rules on navy. |
890
+ | `--mq-core-white-alpha-12` | `rgba(255, 255, 255, 0.12)` | Owner ruling 2, 2026-10-09: white at 12 % for icon-pill fills on navy. |
891
+ | `--mq-core-green` | `#2e7d32` | Success hue for interactive apps (ADR-0004). |
892
+ | `--mq-core-amber` | `#d4850a` | Owner ruling 5, 2026-10-09: warning fill, always with ink text (ADR-0004). |
893
+ | `--mq-core-amber-strong` | `#a06400` | Owner ruling 5, 2026-10-09: warning text, icon and border, 4.86:1 on white (ADR-0004). |
894
+ | `--mq-core-amber-tint` | `#fbf3e7` | Owner ruling 5, 2026-10-09: warning tint, the warning fill at 10 % on white; warning strong on it is 4.42:1, so text on the tint stays ink. |
895
+ | `--mq-core-red` | `#d8232a` | Swiss red, kept only as the danger status colour (ADR-0003, ADR-0004). |
896
+ | `--mq-core-blue` | `#1565c0` | Info hue for interactive apps (ADR-0004). |
897
+ | `--mq-core-font-family-outfit` | `Outfit, system-ui, -apple-system, 'Segoe UI', sans-serif` | Outfit, the sans for headings, labels and app UI (Owner ruling 10, 2026-10-09). |
898
+ | `--mq-core-font-family-newsreader` | `Newsreader, Georgia, 'Times New Roman', serif` | Newsreader, the only serif; Georgia and Times New Roman are fallbacks only (Owner ruling 10, 2026-10-09). |
899
+ | `--mq-core-font-family-geist-mono` | `'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace` | Geist Mono for figures and codes (Owner ruling 10, 2026-10-09). |
900
+ | `--mq-core-font-weight-300` | `300` | Light weight (Owner ruling 6, 2026-10-09: the Quantis half of the wordmark). |
901
+ | `--mq-core-font-weight-400` | `400` | Regular weight for body text (Report design system, 2026-10-08). |
902
+ | `--mq-core-font-weight-500` | `500` | Owner ruling 4, 2026-10-09: medium weight for every heading, column title and hero figure. |
903
+ | `--mq-core-font-weight-600` | `600` | Owner ruling 4, 2026-10-09: semibold only for a short highlighted word inside body text. |
904
+ | `--mq-core-font-size-11` | `11px` | Font size 11 px (Report design system, 2026-10-08). |
905
+ | `--mq-core-font-size-13` | `13px` | Font size 13 px (Report design system, 2026-10-08). |
906
+ | `--mq-core-font-size-14` | `14px` | Font size 14 px (Report design system, 2026-10-08). |
907
+ | `--mq-core-font-size-15` | `15px` | Font size 15 px (Report design system, 2026-10-08). |
908
+ | `--mq-core-font-size-16` | `16px` | Font size 16 px (Report design system, 2026-10-08). |
909
+ | `--mq-core-font-size-18` | `18px` | Font size 18 px (Report design system, 2026-10-08). |
910
+ | `--mq-core-font-size-20` | `20px` | Font size 20 px (Report design system, 2026-10-08). |
911
+ | `--mq-core-font-size-24` | `24px` | Font size 24 px (Report design system, 2026-10-08). |
912
+ | `--mq-core-font-size-30` | `30px` | Font size 30 px (Report design system, 2026-10-08). |
913
+ | `--mq-core-font-size-32` | `32px` | Font size 32 px (Report design system, 2026-10-08). |
914
+ | `--mq-core-font-size-34` | `34px` | Font size 34 px (Report design system, 2026-10-08). |
915
+ | `--mq-core-font-size-36` | `36px` | Font size 36 px (increment 07 component need: the slide title, Report design system, 2026-10-08). |
916
+ | `--mq-core-font-size-50` | `50px` | Font size 50 px (Report design system, 2026-10-08). |
917
+ | `--mq-core-font-size-56` | `56px` | Font size 56 px (Report design system, 2026-10-08). |
918
+ | `--mq-core-font-size-12-5` | `12.5px` | Font size 12.5 px (Report design system, 2026-10-08). |
919
+ | `--mq-core-font-size-16-5` | `16.5px` | Font size 16.5 px (Report design system, 2026-10-08). |
920
+ | `--mq-core-radius-3` | `3px` | Owner ruling 3, 2026-10-09: small items (tags, inputs, chips). |
921
+ | `--mq-core-radius-6` | `6px` | Owner ruling 3, 2026-10-09: cards and panels; the maximum anywhere, no pill shapes. |
922
+ | `--mq-core-radius-12` | `12px` | Owner ruling 3, amended 2026-10-10: the one exception above 6 px, for app dialogs and modals, side drawers and command palettes only; never in documents, slides, cards or website media. |
923
+ | `--mq-core-shadow-small` | `0px 1px 2px 0px rgba(0, 0, 0, 0.05)` | Small elevation for cards (increment 07 component need, Report design system, 2026-10-08). |
924
+ | `--mq-core-shadow-medium` | `0px 3px 12px 0px rgba(0, 0, 0, 0.07)` | Medium elevation for a slide or page shown on the desk (increment 07 component need, Report design system, 2026-10-08). |
925
+ | `--mq-core-shadow-panel` | `0px 14px 36px 0px rgba(10, 36, 99, 0.24)` | Navy-tinted elevation for navy panels (increment 07 component need, Report design system, 2026-10-08). |
926
+ | `--mq-core-size-720` | `720px` | Slide canvas height, 720 px (increment 07 component need: the 1280 by 720 slide canvas). |
927
+ | `--mq-core-size-760` | `760px` | Reading measure, 760 px (increment 07 component need, Report design system, 2026-10-08). |
928
+ | `--mq-core-size-1040` | `1040px` | Content width of a screen document, 1040 px (increment 07 component need, Report design system, 2026-10-08). |
929
+ | `--mq-core-size-1280` | `1280px` | Slide canvas width, 1280 px (increment 07 component need: the 1280 by 720 slide canvas). |
930
+ | `--mq-core-size-a4-width` | `793.7px` | A4 sheet width, 210 mm at 96 px per inch (increment 07 component need: the A4 print page). |
931
+ | `--mq-core-size-a4-height` | `1122.52px` | A4 sheet height, 297 mm at 96 px per inch (increment 07 component need: the A4 print page). |
932
+ | `--mq-core-space-4` | `4px` | Spacing step 4 px on the 4 and 8 px grid (Report design system, 2026-10-08). |
933
+ | `--mq-core-space-8` | `8px` | Spacing step 8 px on the 4 and 8 px grid (Report design system, 2026-10-08). |
934
+ | `--mq-core-space-12` | `12px` | Spacing step 12 px on the 4 and 8 px grid (Report design system, 2026-10-08). |
935
+ | `--mq-core-space-16` | `16px` | Spacing step 16 px on the 4 and 8 px grid (Report design system, 2026-10-08). |
936
+ | `--mq-core-space-24` | `24px` | Spacing step 24 px on the 4 and 8 px grid (Report design system, 2026-10-08). |
937
+ | `--mq-core-space-32` | `32px` | Spacing step 32 px on the 4 and 8 px grid (Report design system, 2026-10-08). |
938
+ | `--mq-core-space-48` | `48px` | Spacing step 48 px on the 4 and 8 px grid (Report design system, 2026-10-08). |
939
+ | `--mq-core-space-72` | `72px` | Spacing step 72 px on the 4 and 8 px grid (Report design system, 2026-10-08). |
940
+ | `--mq-core-stroke-1` | `1px` | Hairline stroke (Report design system, 2026-10-08). |
941
+ | `--mq-core-stroke-2` | `2px` | Focus ring stroke (research note 0001, section 7). |
942
+ | `--mq-core-stroke-3` | `3px` | Accent tab and rule stroke, 3 px (increment 07 component need: the navy tab of calm columns, callouts and takeaways, Report design system, 2026-10-08). |