@mattilsynet/design 3.2.9 → 3.3.1

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 (98) hide show
  1. package/mtds/ai/AGENTS.md +892 -0
  2. package/mtds/ai/alert.mdx +63 -0
  3. package/mtds/ai/alert.stories.tsx +128 -0
  4. package/mtds/ai/analytics.mdx +185 -0
  5. package/mtds/ai/app.mdx +60 -0
  6. package/mtds/ai/app.stories.tsx +897 -0
  7. package/mtds/ai/atlas.mdx +82 -0
  8. package/mtds/ai/atlas.stories.tsx +424 -0
  9. package/mtds/ai/avatar.mdx +45 -0
  10. package/mtds/ai/avatar.stories.tsx +109 -0
  11. package/mtds/ai/badge.mdx +70 -0
  12. package/mtds/ai/badge.stories.tsx +122 -0
  13. package/mtds/ai/breadcrumbs.mdx +36 -0
  14. package/mtds/ai/breadcrumbs.stories.tsx +158 -0
  15. package/mtds/ai/button.mdx +179 -0
  16. package/mtds/ai/button.stories.tsx +440 -0
  17. package/mtds/ai/card.mdx +51 -0
  18. package/mtds/ai/card.stories.tsx +469 -0
  19. package/mtds/ai/chart.mdx +67 -0
  20. package/mtds/ai/chart.stories.tsx +519 -0
  21. package/mtds/ai/chip.mdx +71 -0
  22. package/mtds/ai/chip.stories.tsx +211 -0
  23. package/mtds/ai/details.mdx +33 -0
  24. package/mtds/ai/details.stories.tsx +91 -0
  25. package/mtds/ai/dialog.mdx +38 -0
  26. package/mtds/ai/dialog.stories.tsx +373 -0
  27. package/mtds/ai/divider.mdx +19 -0
  28. package/mtds/ai/divider.stories.tsx +50 -0
  29. package/mtds/ai/errorsummary.mdx +26 -0
  30. package/mtds/ai/errorsummary.stories.tsx +137 -0
  31. package/mtds/ai/field.mdx +86 -0
  32. package/mtds/ai/field.stories.tsx +863 -0
  33. package/mtds/ai/fieldset.mdx +126 -0
  34. package/mtds/ai/fieldset.stories.tsx +298 -0
  35. package/mtds/ai/fileupload.mdx +16 -0
  36. package/mtds/ai/fileupload.stories.tsx +126 -0
  37. package/mtds/ai/helptext.mdx +24 -0
  38. package/mtds/ai/helptext.stories.tsx +106 -0
  39. package/mtds/ai/input.mdx +223 -0
  40. package/mtds/ai/input.stories.tsx +352 -0
  41. package/mtds/ai/law.mdx +115 -0
  42. package/mtds/ai/law.stories.tsx +168 -0
  43. package/mtds/ai/layout.mdx +145 -0
  44. package/mtds/ai/layout.stories.tsx +443 -0
  45. package/mtds/ai/link.mdx +45 -0
  46. package/mtds/ai/link.stories.tsx +44 -0
  47. package/mtds/ai/logo.mdx +86 -0
  48. package/mtds/ai/logo.stories.tsx +146 -0
  49. package/mtds/ai/pagination.mdx +136 -0
  50. package/mtds/ai/pagination.stories.tsx +404 -0
  51. package/mtds/ai/popover.mdx +86 -0
  52. package/mtds/ai/popover.stories.tsx +355 -0
  53. package/mtds/ai/print.mdx +96 -0
  54. package/mtds/ai/print.stories.tsx +839 -0
  55. package/mtds/ai/progress.mdx +41 -0
  56. package/mtds/ai/progress.stories.tsx +141 -0
  57. package/mtds/ai/skeleton.mdx +26 -0
  58. package/mtds/ai/skeleton.stories.tsx +131 -0
  59. package/mtds/ai/spinner.mdx +26 -0
  60. package/mtds/ai/spinner.stories.tsx +72 -0
  61. package/mtds/ai/steps.mdx +37 -0
  62. package/mtds/ai/steps.stories.tsx +568 -0
  63. package/mtds/ai/table.mdx +124 -0
  64. package/mtds/ai/table.stories.tsx +1715 -0
  65. package/mtds/ai/tabs.mdx +106 -0
  66. package/mtds/ai/tabs.stories.tsx +159 -0
  67. package/mtds/ai/tag.mdx +49 -0
  68. package/mtds/ai/tag.stories.tsx +111 -0
  69. package/mtds/ai/toast.mdx +67 -0
  70. package/mtds/ai/toast.stories.tsx +215 -0
  71. package/mtds/ai/togglegroup.mdx +75 -0
  72. package/mtds/ai/togglegroup.stories.tsx +96 -0
  73. package/mtds/ai/tooltip.mdx +32 -0
  74. package/mtds/ai/tooltip.stories.tsx +34 -0
  75. package/mtds/ai/typography.mdx +67 -0
  76. package/mtds/ai/typography.stories.tsx +798 -0
  77. package/mtds/ai/validation.mdx +19 -0
  78. package/mtds/ai/validation.stories.tsx +45 -0
  79. package/mtds/app/app-observer.js +1 -1
  80. package/mtds/app/app-toggle.js +10 -26
  81. package/mtds/app/app-toggle.js.map +1 -1
  82. package/mtds/app/app-toggle2.js +26 -10
  83. package/mtds/app/app-toggle2.js.map +1 -1
  84. package/mtds/app/app.js +1 -1
  85. package/mtds/atlas/atlas-element.js +1 -1
  86. package/mtds/chart/chart-lines.js +19 -19
  87. package/mtds/chart/chart-lines.js.map +1 -1
  88. package/mtds/chart/chart.css.js +16 -1
  89. package/mtds/chart/chart.css.js.map +1 -1
  90. package/mtds/chart/chart.stories.d.ts +1 -0
  91. package/mtds/index.iife.js +32 -17
  92. package/mtds/index.js +21 -20
  93. package/mtds/index.js.map +1 -1
  94. package/mtds/package.json.js +1 -1
  95. package/mtds/styles.css +1 -1
  96. package/mtds/table/table-observer.js +26 -15
  97. package/mtds/table/table-observer.js.map +1 -1
  98. package/package.json +4 -2
@@ -0,0 +1,892 @@
1
+ # @mattilsynet/design — LLM Reference
2
+
3
+ You are a senior frontend engineer who converts Figma sketches/screenshots into production-ready React code, and iterates on existing code, using the `@mattilsynet/design` (mtds) design system. Make no assumptions. Create no new components. This file is your full source of truth.
4
+
5
+ Use **components** from `@mattilsynet/design/react`, **attributes** (`data-*`) for variants and density, and **CSS tokens** (`--mtds-*`) for any custom styling. Never use raw `px`, hex colors, or inline `style` for layout/spacing/color. Avoid creating new class names unless strictly necessary.
6
+
7
+ ---
8
+
9
+ ## 0. Quick start (read first, every time)
10
+
11
+ ```ts
12
+ // In the application entry file, ONCE:
13
+ import '@mattilsynet/design';
14
+ import '@mattilsynet/design/styles.css';
15
+ ```
16
+
17
+ ```tsx
18
+ // In any file that uses components:
19
+ import { Button, Card, Flex, Grid, Heading /* ... */ } from '@mattilsynet/design/react';
20
+ import { CheckIcon /* ... */ } from '@phosphor-icons/react/ssr';
21
+ ```
22
+
23
+ The minimal correct page skeleton:
24
+
25
+ ```tsx
26
+ <App>
27
+ <App.Header><Logo href="/">App name</Logo></App.Header>
28
+ <App.Toggle />
29
+ <App.Sidebar><App.Sticky as="menu">{/* icon-only buttons */}</App.Sticky></App.Sidebar>
30
+ <App.Main>
31
+ <Flex data-center="2xl" data-gap="6">
32
+ <Card>{/* every leaf node lives inside Card or Group */}</Card>
33
+ </Flex>
34
+ </App.Main>
35
+ </App>
36
+ ```
37
+
38
+ The five rules that catch 80% of mistakes:
39
+
40
+ 1. Every leaf node inside `<App.Main>` lives inside a `<Card>` or `<Group>` — never directly in `<App.Main>`.
41
+ 2. `data-center` goes on `<Flex>`/`<Grid>` **inside** `<Card>` or `<Group>`. Never on `<App>` or direct children of `<App.Main>`.
42
+ 3. No raw `<h1>`–`<h6>`. Use `<Heading as="hN" data-size="…">`.
43
+ 4. No raw `px`, `rem`, hex, `rgb()`, named colors, inline `style`, or Tailwind for layout/spacing/color/radius/typography. Use `data-pad` or `data-gap`, and css tokens when absolutely necessary.
44
+ 5. Sidebar Buttons are icon-only. Label via `data-tooltip="…"` (and `aria-label` when needed).
45
+
46
+ When in doubt, read `@mattilsynet/design/mtds/ai/<name>.mdx` for the component you're using.
47
+
48
+ ---
49
+
50
+ ## 1. Mandatory rules (MUST / MUST NOT)
51
+
52
+ 1. Import `'@mattilsynet/design'` and `'@mattilsynet/design/styles.css'` once in the entry file.
53
+ 2. Do **not** set `data-color-scheme` on `<html>`.
54
+ 3. Import React components from `@mattilsynet/design/react`. Import icons from `@phosphor-icons/react/ssr` (ensure `@phosphor-icons/react` is installed).
55
+ 4. Do **not** use raw `px`, `rem`, hex, `rgb()`, named colors, inline `style`, or Tailwind utilities for layout, spacing, color, radius, or typography. Use design tokens or component attributes.
56
+ 5. Use `<App>` as the page shell (see §6).
57
+ 6. Do **not** create a new container component when `Card`, `Group`, `Flex`, or `Grid` already cover the case.
58
+ 7. Do **not** write raw `<h1>`–`<h6>`. Use `<Heading as="hN">`.
59
+ 8. Read `@mattilsynet/design/mtds/ai/<name>.mdx` (and `<name>.stories.tsx`) before using a component you have not used in this session.
60
+ 9. For genuinely custom CSS, use a CSS file or CSS Module that references `--mtds-*` tokens. Never inline `style`.
61
+ 10. Verify all requirements against the **§11 checklist** before returning code.
62
+
63
+ ---
64
+
65
+ ## 2. Forbidden patterns (read before generating)
66
+
67
+ | Don't | Do |
68
+ |---|---|
69
+ | `style={{…}}` for layout, spacing, or color | Layout component, `data-*` attribute, or token in CSS |
70
+ | `className="p-4 gap-3 text-red-500"` (Tailwind) | Layout components with attributes (or tokens if absolutely necessary) |
71
+ | Hex / `rgb()` / named colors (`#c83719`, `red`) | `var(--mtds-color-…)` under the appropriate `data-color` parent |
72
+ | Raw `px`/`rem` for spacing (`padding: 16px`) | `var(--mtds-4)`, or `data-gap` / `data-pad` on a layout component |
73
+ | `<div style="display:flex">` | `<Flex>` |
74
+ | `<h2>Title</h2>` | `<Heading as="h2">Title</Heading>` |
75
+ | `<small>helper</small>`, `<p style="font-size:1.3em">` | `<Muted>`, `<Ingress>` |
76
+ | Made-up tokens: `var(--mtds-16)`, `var(--mtds-20)` | Snap to the nearest existing token (see §5.1) |
77
+ | Hard-coded palette token: `var(--mtds-color-danger-base-default)` | Set `data-color="danger"` on a parent and use the palette-agnostic token (`var(--mtds-color-base-default)`) |
78
+ | `data-center` on `<App>` or directly on `<App.Main>`'s child | Apply on `<Card>`/`<Group>`, or a `<Flex>`/`<Grid>` inside them |
79
+ | `<aside>` / `<nav>` for primary nav | `<App.Sidebar>` |
80
+ | Custom React state for sidebar open/close | `<App.Toggle>` |
81
+ | Visible text in a sidebar button | Icon only + `data-tooltip="Label"` |
82
+ | `<label>Name<input/></label>` outside `<Field>` | `<Field as="input" label="Name" />` (or compose with `<Field>`+`<Field.Label>`+`<Input>`) |
83
+
84
+ ---
85
+
86
+ ## 3. Decision tree (intent → component)
87
+
88
+ ### 3.1 Layout — pick the right container
89
+
90
+ ```
91
+ Need a page shell? → <App> (see §6)
92
+ Need a content surface? → <Card> (white surface; one related unit)
93
+ Need a region of cards? → <Group> (tinted surface; collection of cards / meta UI)
94
+ Need to lay out children?
95
+ ├─ Equal-width / stack → <Grid> (data-items="300" for responsive cols)
96
+ └─ Mixed widths / toolbar → <Flex>
97
+ Need text rhythm? → <Prose> (auto vertical spacing for body text)
98
+ ```
99
+
100
+ `Card` MAY be nested in `Group`. Avoid `Card` inside `Card`. `Flex`/`Grid` MAY sit between `<App.Main>` and the `Card`/`Group` to apply `data-center` and `data-gap`.
101
+
102
+ ### 3.2 Intent → component
103
+
104
+ | You need to… | Use |
105
+ |---|---|
106
+ | Render a heading | `<Heading as="hN" data-size="…">` |
107
+ | Render lead/intro text | `<Ingress>` |
108
+ | Render small/secondary text | `<Muted>` |
109
+ | Render a label + value pair (optionally with icon) | `<Info>` |
110
+ | Trigger an action | `<Button>` (renders `<a>` when `href` is present) |
111
+ | Navigate to another URL inline in text | `<Link>` |
112
+ | Single form field (label + input + validation) | `<Field>` (see §9) |
113
+ | Group several related form fields | `<Fieldset>` (see §9) |
114
+ | Show validation errors at the top of a form | `<Errorsummary>` (single capital R) |
115
+ | Show a modal | `<Dialog>` |
116
+ | Show a non-modal floating overlay anchored to a trigger | `<Popover>` (uses native popover API) |
117
+ | Show a tooltip on an element | `data-tooltip="…"` on the element |
118
+ | Show inline contextual feedback (info/success/warning/danger) | `<Alert>` |
119
+ | Tabular data | `<Table>` |
120
+ | Tabbed content panels | `<Tabs>` |
121
+ | Multi-step progress / timeline | `<Steps>` |
122
+ | Read-only label/keyword | `<Tag>` |
123
+ | Status indicator on top of another element | `<Badge>` |
124
+ | Single-select toggle button group | `<Togglegroup>` (single capital G) |
125
+ | Interactive filter chip | `<Chip>` |
126
+ | Switch palette for a region | `data-color="…"` on any ancestor |
127
+ | Switch density for a region | `data-size="sm│md│lg"` on a layout container |
128
+
129
+ For anything else, find the right component in the **§12 index**.
130
+
131
+ ---
132
+
133
+ ## 4. Global cascading attributes
134
+
135
+ These cascade to descendants from any element they're set on.
136
+
137
+ ### 4.1 `data-color` — palette
138
+
139
+ | Value | Palette |
140
+ |---|---|
141
+ | `main` | Mattilsynet primary green (default) |
142
+ | `neutral` | Grey |
143
+ | `success` | Green |
144
+ | `info` | Blue |
145
+ | `warning` | Orange |
146
+ | `danger` | Red |
147
+ | `inverted` | Dark green with light text |
148
+
149
+ These seven are the only valid values. All `--mtds-color-*` tokens inside resolve against the nearest ancestor's palette automatically.
150
+
151
+ ```tsx
152
+ <section data-color="danger">
153
+ <Heading>Feilseksjon</Heading>
154
+ <Button data-variant="primary">Slett</Button>
155
+ </section>
156
+ ```
157
+
158
+ ### 4.2 `data-size` — density vs. component-local size
159
+
160
+ On layout containers (`Flex`, `Grid`, `Card`, `Group`, `<section>`, etc.), `data-size` controls **UI density** (padding, control heights) for descendants. Values: `sm` (compact), `md` (default), `lg` (spacious).
161
+
162
+ > ⚠ **Name collision.** On `Heading`, `Button`, `Info`, and several other components, `data-size` is a **component-local visual size** (e.g. `2xs`–`2xl` on `Heading`), not density. Always check the component's doc. Do not use `data-size` to change font-size on plain HTML elements — wrap in `<Heading>`, `<Ingress>`, or `<Muted>` instead.
163
+
164
+ ### 4.3 `data-tooltip` — tooltip text
165
+
166
+ Place on any element. Tooltip text is automatically exposed to assistive tech. Use `data-tooltip-position="top│right│bottom│left"` to reposition.
167
+
168
+ ```tsx
169
+ <Button data-tooltip="Save your changes">Save</Button>
170
+ ```
171
+
172
+ ---
173
+
174
+ ## 5. Token system
175
+
176
+ Tokens are namespaced `--mtds-*` (system) and `--mtdsc-*` (per-component override). All pixel values are **informative only** — the scale is fluid (resizes with density and root font-size). Always reference the token, never the literal value.
177
+
178
+ ### 5.1 Spacing — `--mtds-{n}`
179
+
180
+ Prefer layout primitives (`Flex`, `Grid`, `Card`, `Group`) with `data-gap`, `data-pad`, or `data-items` over raw spacing tokens. Do **not** set `margin` — use `data-gap` or `data-pad`.
181
+
182
+ Valid `n` values: **`0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 22, 26, 30`** (note the gap above 15). At default density, `n × 4 ≈ pixels`. Other indexes (`16`, `17`, `19`, `20`–`21`, `23`–`25`, `27`–`29`) **do not exist**.
183
+
184
+ ```css
185
+ /* Do */
186
+ .x { padding: var(--mtds-4); gap: var(--mtds-3); }
187
+
188
+ /* Don't */
189
+ .x { padding: 16px; } /* raw px */
190
+ .x { padding: var(--mtds-16); } /* not in the scale */
191
+ ```
192
+
193
+ ### 5.2 Color — `--mtds-color-{role}-{variant}`
194
+
195
+ Use **palette-agnostic** tokens. They resolve against the nearest ancestor's `data-color`.
196
+
197
+ | Role | Variants |
198
+ |---|---|
199
+ | `background` | `default`, `tinted` |
200
+ | `surface` | `default`, `tinted`, `hover`, `active` |
201
+ | `border` | `subtle`, `default`, `strong` |
202
+ | `text` | `subtle`, `default` |
203
+ | `base` | `default`, `hover`, `active`, `contrast-subtle`, `contrast-default` |
204
+
205
+ Roles are **not interchangeable**: text tokens are for text, surface tokens are for surfaces, etc.
206
+
207
+ ```css
208
+ /* Do — works under any data-color */
209
+ .my-very-custom-component {
210
+ background: var(--mtds-color-surface-default);
211
+ color: var(--mtds-color-text-default);
212
+ border: 1px solid var(--mtds-color-border-default);
213
+ }
214
+ ```
215
+
216
+ Palette-prefixed tokens like `--mtds-color-danger-surface-tinted` exist in the CSS but **must not** be used directly. To get a danger surface, set `data-color="danger"` on a parent and use the agnostic token.
217
+
218
+ ### 5.3 Typography
219
+
220
+ Prefer the components (`Heading`, `Ingress`, `Muted`, `Info`) over raw font-size tokens in markup. For custom CSS only:
221
+
222
+ ```css
223
+ --mtds-font-family /* "Mattilsynet Sans" */
224
+ --mtds-font-weight-regular /* 400 */
225
+ --mtds-font-weight-medium /* 500 */
226
+ --mtds-font-weight-semibold /* 600 */
227
+ --mtds-font-weight-bold /* 700 */
228
+ --mtds-font-size-muted /* used by <Muted> */
229
+ --mtds-line-height-sm | -md
230
+ ```
231
+
232
+ Heading sizes (`2xs`–`2xl`) and body sizes (`xs`–`xl`) are exposed via the typography components — use `<Heading data-size="lg">`, not the underlying token.
233
+
234
+ ### 5.4 Other tokens
235
+
236
+ ```css
237
+ --mtds-border-radius-sm | -md | -lg | -xl | -full
238
+ --mtds-border-width-default | -focus
239
+ --mtds-box-shadow-sm | -md | -lg
240
+ --mtds-icon-size /* = --mtds-6 */
241
+ --mtds-icon-size-sm /* = --mtds-5 */
242
+ ```
243
+
244
+ ### 5.5 Per-component overrides — `--mtdsc-{component}-{property-path}`
245
+
246
+ Each component exposes scoped custom properties. Discover the available ones for any component at the bottom of `mtds/ai/<name>.mdx` (the `<CssVariables component="…" />` block).
247
+
248
+ ```css
249
+ .scoped { --mtdsc-button-border-color: var(--mtds-color-border-strong); }
250
+ .wide { --mtdsc-prose-max-width: 60rem; }
251
+ ```
252
+
253
+ ---
254
+
255
+ ## 6. App layout (page shell)
256
+
257
+ Every Mattilsynet web application/page MUST be built inside the `App` shell. It is the outermost layout that all other content lives within.
258
+
259
+ | Sub-component | Purpose |
260
+ |---|---|
261
+ | `App` | The shell. Supports `data-variant="mobilebar"` (see §6.6) |
262
+ | `App.Header` | Logo + global actions. `<Logo>` MUST be the first child |
263
+ | `App.Toggle` | Expand/minimize sidebar (also opens it as a modal on mobile) |
264
+ | `App.Sidebar` | Primary navigation. Modal on mobile, rail/expanded on desktop |
265
+ | `App.Sticky` | Scroll-direction-aware sticky wrapper for sidebar contents only |
266
+ | `App.Main` | Page content. Every leaf node MUST sit inside a `<Card>` or `<Group>` (see §6.3) |
267
+ | `App.Footer` | Optional footer |
268
+ | `App.Script` | SSR/Next.js only. Render in `<head>` to prevent FOUC (see §6.7) |
269
+
270
+ Required source order: **`App.Header` → `App.Toggle` → `App.Sidebar` → `App.Main` → `App.Footer`**.
271
+
272
+ ### 6.1 Canonical composition
273
+
274
+ ```tsx
275
+ import { App, Logo, Button, Popover, Avatar, Card } from '@mattilsynet/design/react';
276
+ import { BellIcon, UserIcon, SignOutIcon, GearIcon, SignatureIcon, ListChecksIcon, MagnifyingGlassIcon, PlantIcon } from '@phosphor-icons/react/ssr';
277
+
278
+ <App>
279
+ <App.Header>
280
+ <Logo href="/">
281
+ <PlantIcon weight="fill" />
282
+ Digiplant
283
+ </Logo>
284
+ <Button><BellIcon /></Button>
285
+ <Button aria-label="Meny" popoverTarget="user-menu">
286
+ <Avatar data-size="sm" />
287
+ </Button>
288
+ <Popover as="menu" popover="auto" id="user-menu">
289
+ <li><Button href="/profil"><UserIcon />Profil</Button></li>
290
+ <li><Button href="/innstillinger"><GearIcon />Innstillinger</Button></li>
291
+ <li><Button href="/logout"><SignOutIcon />Logg ut</Button></li>
292
+ </Popover>
293
+ </App.Header>
294
+
295
+ <App.Toggle />
296
+
297
+ <App.Sidebar>
298
+ <App.Sticky as="menu">
299
+ <li><Button href="/soknader" aria-current="page" data-tooltip="Søknader"><SignatureIcon /></Button></li>
300
+ <li><Button href="/behandling" data-tooltip="Behandling"><ListChecksIcon /></Button></li>
301
+ <li><Button href="/sok" data-tooltip="Søk"><MagnifyingGlassIcon /></Button></li>
302
+ </App.Sticky>
303
+ </App.Sidebar>
304
+
305
+ <App.Main>
306
+ <Card>
307
+ <Flex data-center="2xl" data-gap="6">
308
+ {/* page content here — see §6.3 */}
309
+ </Flex>
310
+ </Card>
311
+ </App.Main>
312
+
313
+ <App.Footer>
314
+ <Logo href="/" />
315
+ </App.Footer>
316
+ </App>
317
+ ```
318
+
319
+ ### 6.2 Sidebar buttons MUST be icon-only
320
+
321
+ Every interactive child of `<App.Sidebar>` MUST contain **only an icon** as visible content. The textual label MUST be supplied via `data-tooltip="…"` (and `aria-label` where the icon alone is not self-descriptive).
322
+
323
+ The design system manages how labels appear: when the sidebar is minimized the tooltip is shown on hover; when expanded the design system reveals the label inline automatically. Hard-coding text inside the button breaks both states.
324
+
325
+ `<Button>` elements inside `<App.Sidebar>` are most commonly wrapped in a `<menu>` → `<li>` structure (often via `<App.Sticky as="menu">`) for vertical stacking and good accessibility.
326
+
327
+ ```tsx
328
+ // Do — icon-only, label via data-tooltip
329
+ <Button href="/soknader" data-tooltip="Søknader">
330
+ <SignatureIcon />
331
+ </Button>
332
+
333
+ // Don't — visible text inside a sidebar button
334
+ <Button href="/soknader">
335
+ <SignatureIcon />
336
+ Søknader
337
+ </Button>
338
+ ```
339
+
340
+ ### 6.3 `App.Main` content rules (the centering rule)
341
+
342
+ `<App.Main>` is a layout region, not a content surface.
343
+
344
+ - Every **leaf** node (text, heading, paragraph, raw HTML element) inside `<App.Main>` MUST be wrapped in at least one `<Card>` or `<Group>`.
345
+ - Layout primitives (`<Flex>`, `<Grid>`) MAY sit between `<App.Main>` and the `<Card>`/`<Group>` — but if you need to apply `data-center`, you must have a `<Card>` or `<Group>` as parent.
346
+ - Use `<Card>` for a single related content unit on a solid surface (e.g. one inspection, one entity detail page).
347
+ - Use `<Group>` for a collection of cards or meta-UI on a tinted surface.
348
+
349
+ ```tsx
350
+ // Do
351
+ <App.Main>
352
+ <Card>
353
+ <Grid data-center="2xl" data-gap="6">
354
+ <Heading as="h1" data-size="xl">Tilsyn 12345</Heading>
355
+ <p>…</p>
356
+ <Group>
357
+ <Card>…</Card>
358
+ <Card>…</Card>
359
+ </Group>
360
+ </Grid>
361
+ </Card>
362
+ </App.Main>
363
+
364
+ // Do multiple Cards in Group in App.Main
365
+ <App.Main>
366
+ <Group>
367
+ <Prose>
368
+ <Heading as="h1" data-size="xl">Liste over tilsyn</Heading>
369
+ <Card>…</Card>
370
+ <Card>…</Card>
371
+ </Prose>
372
+ </Group>
373
+ </App.Main>
374
+
375
+ // Don't — bare content directly in App.Main
376
+ <App.Main>
377
+ <Heading as="h1" data-size="xl">Tilsyn 12345</Heading>
378
+ <p>…</p>
379
+ </App.Main>
380
+
381
+ // Don't — data-center on App or App.Main
382
+ <App data-center="2xl">…</App>
383
+
384
+ // Don't — data-center on direct child of App.Main
385
+ <App><App.Main><Grid data-center="2xl"></Grid></App.Main></App>
386
+ ```
387
+
388
+ ### 6.4 Expand / minimize sidebar
389
+
390
+ - `<App.Toggle>` renders the standard expand/minimize button.
391
+ - Do **not** manage sidebar visibility with custom React state — always use `<App.Toggle>`.
392
+
393
+ ### 6.5 Sticky sidebar content
394
+
395
+ Wrap the contents of `<App.Sidebar>` in `<App.Sticky>` to get scroll-direction-aware sticky behavior (the sidebar stays visible when scrolling up and slides away when scrolling down). `<App.Sticky>` is for sidebar contents — do not use it elsewhere.
396
+
397
+ ### 6.6 Mobile bottom bar variant
398
+
399
+ ```tsx
400
+ <App data-variant="mobilebar">…</App>
401
+ ```
402
+
403
+ - Converts the sidebar into a mobile bottom navigation bar.
404
+ - Use only when there are 5 or fewer top-level navigation items.
405
+ - Headings, dividers, and elements with `data-app-expanded="false"` are auto-hidden in this variant.
406
+
407
+ ### 6.7 SSR / Next.js
408
+
409
+ To prevent flash of unstyled content (FOUC) when the persisted expanded/minimized state is restored, render `<App.Script />` inside `<head>`:
410
+
411
+ ```tsx
412
+ // app/layout.tsx (Next.js)
413
+ <html>
414
+ <head>
415
+ <App.Script />
416
+ </head>
417
+ <body>{children}</body>
418
+ </html>
419
+ ```
420
+
421
+ ---
422
+
423
+ ## 7. Layout primitives
424
+
425
+ ### 7.1 When to use which
426
+
427
+ | Component | Use when | Surface |
428
+ |---|---|---|
429
+ | `Flex` | Children have different widths (button rows, toolbars) | none |
430
+ | `Grid` | Children should be equal-width (card grids) or stack vertically | none |
431
+ | `Card` | Group related content as a single unit | `surface-default` (white) |
432
+ | `Group` | Group several cards or meta-UI as a region | `background-tinted` (translucent grey) |
433
+
434
+ `Card` MAY be nested inside `Group`. Avoid `Card` inside `Card`.
435
+
436
+ ### 7.2 Shared attributes — `Flex` and `Grid`
437
+
438
+ | Attribute | Values | Notes |
439
+ |---|---|---|
440
+ | `data-gap`, `data-row-gap`, `data-column-gap` | Same set as §5.1 (`0`–`15`, `18`, `22`, `26`, `30`) | Default `data-gap="3"` |
441
+ | `data-items` | `auto`, `full`, or `25`, `50`, `75`, `100`, `150`, `200`, `250`, `300`, `350`, `400`, `450`, `500` | Min child width in **px** before wrapping. `full` = single column (Flex only). `auto` = intrinsic |
442
+ | `data-align` | `normal`, `stretch`, `start`, `center`, `end` | `align-items` |
443
+ | `data-align-content` | `start`, `center`, `end`, `space-between`, `space-around`, `space-evenly` | `align-content` |
444
+ | `data-justify` | `start`, `center`, `end`, `space-between`, `space-around`, `space-evenly` | `justify-content` |
445
+ | `data-center` | `sm`, `md`, `lg`, `xl`, `2xl` | Max-width + center + side padding. |
446
+ | `data-nowrap` | boolean | Prevent wrapping |
447
+ | `data-fixed` | boolean | Children don't grow (Flex) / `auto-fill` (Grid) |
448
+
449
+ ### 7.3 Flex child attributes
450
+
451
+ | Attribute | Values | Notes |
452
+ |---|---|---|
453
+ | `data-self` | Same set as `data-items` | Min width for this child |
454
+ | `data-align-self` | `start`, `center`, `end`, `stretch` | |
455
+ | `data-justify-self` | `start`, `center`, `end` | |
456
+
457
+ ### 7.4 `Card` and `Group`
458
+
459
+ | Attribute | Values | Notes |
460
+ |---|---|---|
461
+ | `data-pad` | Single index from §5.1, or `{vertical}-{horizontal}` (e.g. `4-6`) | Inner padding. Default `5`. Pair form is fluid between viewport breakpoints |
462
+ | `data-radius` | `sm`, `md`, `lg`, `xl` | Defaults: Card `lg`, Group `xl` |
463
+
464
+ `Card` only:
465
+
466
+ | Attribute | Values | Notes |
467
+ |---|---|---|
468
+ | `href` | string | Renders Card as `<a>` (whole card becomes a link) |
469
+ | `data-clickdelegatefor` | CSS selector | Click anywhere on the card triggers the matching descendant (e.g. `"#details-link"`) |
470
+
471
+ ### 7.5 Quick reference
472
+
473
+ ```tsx
474
+ // Page container, centered, max-width 2xl
475
+ <Card>
476
+ <Grid data-center="2xl">
477
+ <Heading as="h1" data-size="xl">Page title</Heading>
478
+ </Grid>
479
+ </Card>
480
+
481
+ // Button row
482
+ <Flex>
483
+ <Button data-variant="primary">Save</Button>
484
+ <Button>Cancel</Button>
485
+ </Flex>
486
+
487
+ // Responsive equal-width card grid
488
+ <Grid data-items="300" data-gap="6">
489
+ <Card>Card 1</Card>
490
+ <Card>Card 2</Card>
491
+ <Card>Card 3</Card>
492
+ </Grid>
493
+ ```
494
+
495
+ ---
496
+
497
+ ## 8. Typography components
498
+
499
+ ### 8.1 `Heading`
500
+
501
+ | Attribute | Values | Notes |
502
+ |---|---|---|
503
+ | `as` | `h1`–`h6` | **Semantic** level. Default `h2`. Always set explicitly for accessibility |
504
+ | `data-size` | `2xs`, `xs`, `sm`, `md`, `lg`, `xl`, `2xl` | **Visual** size (independent of `as`) |
505
+ | `data-justify` | `start`, `center`, `end` | Text alignment |
506
+
507
+ `Heading` auto-sizes and aligns any `<svg>` child (no inner `<Flex>` needed).
508
+
509
+ ```tsx
510
+ <Heading as="h2" data-size="sm"><CheckIcon /> Approved</Heading>
511
+ ```
512
+
513
+ ### 8.2 `Prose`
514
+
515
+ Wraps body/editorial text and applies typographic margins to **all direct children**. Tuned for `<p>`, `<ul>`, `<ol>`, `<h1>`–`<h6>`, `<figure>`, and `<Heading>`.
516
+
517
+ - Default max-width: `45rem` (override with `--mtdsc-prose-max-width`).
518
+ - Layout primitives (`<Flex>`, `<Grid>`) inside `<Prose>` will also receive the rhythm margin — keep them outside `<Prose>` if you don't want that.
519
+
520
+ ```tsx
521
+ <Prose>
522
+ <Heading as="h2">Section</Heading>
523
+ <p>Body text with automatic rhythm.</p>
524
+ <ul><li>Item</li></ul>
525
+ </Prose>
526
+ ```
527
+
528
+ ### 8.3 `Ingress` and `Muted`
529
+
530
+ ```tsx
531
+ <Ingress>Lead paragraph introducing the topic.</Ingress>
532
+ <Muted>Last updated 06.05.2026</Muted>
533
+ ```
534
+
535
+ ### 8.4 `Info`
536
+
537
+ Responsive label + value layout. Use for metadata, key/value pairs, or a value next to an indicator icon. Wrap the label in `<strong>`.
538
+
539
+ | Attribute | Values | Notes |
540
+ |---|---|---|
541
+ | `data-variant` | `regular` (default), `circle` | `circle` wraps the icon in a colored circle. Use only when the icon must draw visual attention; show **both** label and value |
542
+
543
+ ```tsx
544
+ // Label + value
545
+ <Info><strong>Organization</strong>Fisk AS</Info>
546
+
547
+ // Icon + label + value
548
+ <Info><CheckIcon /><strong>Status</strong>Approved</Info>
549
+
550
+ // Emphasised: icon in colored circle (palette comes from ancestor data-color)
551
+ <Info data-variant="circle">
552
+ <CheckIcon /><strong>Status</strong>Approved
553
+ </Info>
554
+ ```
555
+
556
+ To color the circle, set `data-color` on an ancestor (e.g. wrap the `Info` in a `<div data-color="success">`).
557
+
558
+ ---
559
+
560
+ ## 9. Forms
561
+
562
+ Forms in mtds compose `<Field>` (single input row), `<Fieldset>` (grouped fields), `<Errorsummary>` (top-of-form error list), and `<Validation>` (field-level error message). The exact React export names matter — see §12.
563
+
564
+ ### 9.1 `Field` — two usage modes
565
+
566
+ **Mode A (composition):** wrap children manually. Use `<Field.Label>`, `<Field.Description>`, and an `<Input>` (or other input). Use this when you need fine control.
567
+
568
+ ```tsx
569
+ <Field>
570
+ <Field.Label>Name</Field.Label>
571
+ <Field.Description>Your full legal name.</Field.Description>
572
+ <Input />
573
+ </Field>
574
+ ```
575
+
576
+ **Mode B (polymorphic shorthand):** `<Field as="…" label="…" />` renders the complete row.
577
+
578
+ ```tsx
579
+ <Field
580
+ as="input"
581
+ type="text"
582
+ label="Name"
583
+ description="Your full legal name."
584
+ validation="Name is required."
585
+ helpText="Enter the name as it appears on your ID."
586
+ />
587
+
588
+ <Field as="select" label="Country" options={['Norway', 'Sweden', 'Denmark']} />
589
+
590
+ <Field
591
+ as="textarea"
592
+ label="Comment"
593
+ count={500} /* character counter */
594
+ />
595
+
596
+ <Field
597
+ as={Field.Suggestion}
598
+ label="Search"
599
+ options={[{ label: 'Oslo', value: 'oslo' }]}
600
+ />
601
+ ```
602
+
603
+ Supported `as` values: `"input"`, `"textarea"`, `"select"`, `Field.Suggestion`.
604
+
605
+ Compound members: `Field.Label`, `Field.Description`, `Field.Suggestion`, `Field.Datalist`, `Field.Option`.
606
+
607
+ ### 9.2 `Fieldset` — group related fields
608
+
609
+ Use plain `<legend>` and `<Fieldset.Description>` for grouped options. There is **no** `Fieldset.Legend` component — use the native HTML `<legend>` element when composing manually, or use `<Fieldset.Legend>` only inside the React `<Fieldset>` component (it renders `<legend>`).
610
+
611
+ ```tsx
612
+ <Fieldset>
613
+ <Fieldset.Legend>Hva foretrekker du?</Fieldset.Legend>
614
+ <Fieldset.Description>Pick one option.</Fieldset.Description>
615
+ <Field as="input" type="radio" name="pref" label="Alternative 1" />
616
+ <Field as="input" type="radio" name="pref" label="Alternative 2" />
617
+ </Fieldset>
618
+ ```
619
+
620
+ ### 9.3 `Errorsummary` — top-of-form errors
621
+
622
+ Note the spelling: `Errorsummary` (single capital R). Children are a `<Heading>` + an unordered list of in-page anchors that point to field IDs.
623
+
624
+ ```tsx
625
+ import { Errorsummary, Heading } from '@mattilsynet/design/react';
626
+
627
+ <Errorsummary>
628
+ <Heading>For å gå videre må du rette opp følgende feil:</Heading>
629
+ <ul>
630
+ <li><a href="#name">Name is required</a></li>
631
+ <li><a href="#email">Email must be valid</a></li>
632
+ </ul>
633
+ </Errorsummary>
634
+ ```
635
+
636
+ Behavior rules:
637
+ - Hide the Errorsummary with `hidden` until validation fails.
638
+ - Anchor links in Errorsummary must match field `id` attributes. On click, scroll the target into view and focus it.
639
+
640
+ ### 9.4 `Validation` — field-level error
641
+
642
+ Use `<Validation>` (or `<div data-field="validation">` in plain HTML) as a child of `<Field>` or `<Fieldset>`. In Mode B (`Field as="…"`), pass `validation="…"` instead.
643
+
644
+ ### 9.5 `Togglegroup` — single-select toggle button row
645
+
646
+ Note the spelling: `Togglegroup` (single capital G). Compound: `Togglegroup.Item`.
647
+
648
+ ```tsx
649
+ <Togglegroup data-toggle-group="View">
650
+ <Togglegroup.Item><input type="radio" name="view" defaultChecked /> List</Togglegroup.Item>
651
+ <Togglegroup.Item><input type="radio" name="view" /> Grid</Togglegroup.Item>
652
+ </Togglegroup>
653
+ ```
654
+
655
+ ### 9.6 `Fileupload` (experimental)
656
+
657
+ Note the spelling: `Fileupload`. API may change — read `fileupload.mdx` before use.
658
+
659
+ ### 9.7 `HelpText`
660
+
661
+ Inline contextual help button (renders as a button that toggles a popover). Prefer passing `helpText="…"` and `helpTextLabel="…"` to `<Field>` over composing `<HelpText>` manually.
662
+
663
+ ### 9.8 Worked form example
664
+
665
+ ```tsx
666
+ import { useRef, useState } from 'react';
667
+ import { Button, Card, Errorsummary, Field, Fieldset, Flex, Heading } from '@mattilsynet/design/react';
668
+
669
+ function ApplicationForm() {
670
+ const [errors, setErrors] = useState<Record<string, string>>({});
671
+ const summaryRef = useRef<HTMLHeadingElement>(null);
672
+
673
+ const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
674
+ e.preventDefault();
675
+ const data = new FormData(e.currentTarget);
676
+ const next: Record<string, string> = {};
677
+ if (!data.get('name')) next.name = 'Navn er påkrevd';
678
+ if (!data.get('email')) next.email = 'E-post er påkrevd';
679
+ setErrors(next);
680
+ if (Object.keys(next).length) setTimeout(() => summaryRef.current?.focus());
681
+ };
682
+
683
+ return (
684
+ <Card>
685
+ <form onSubmit={onSubmit}>
686
+ <Flex data-gap="5">
687
+ <Errorsummary hidden={!Object.keys(errors).length}>
688
+ <Heading ref={summaryRef} tabIndex={-1}>
689
+ For å gå videre må du rette opp følgende feil:
690
+ </Heading>
691
+ <ul>
692
+ {errors.name && <li><a href="#name">{errors.name}</a></li>}
693
+ {errors.email && <li><a href="#email">{errors.email}</a></li>}
694
+ </ul>
695
+ </Errorsummary>
696
+
697
+ <Field as="input" id="name" name="name" label="Navn" validation={errors.name} />
698
+ <Field as="input" id="email" name="email" label="E-post" type="email" validation={errors.email} />
699
+
700
+ <Fieldset>
701
+ <Fieldset.Legend>Foretrukket kontakt</Fieldset.Legend>
702
+ <Field as="input" type="radio" name="contact" label="E-post" defaultChecked />
703
+ <Field as="input" type="radio" name="contact" label="Telefon" />
704
+ </Fieldset>
705
+
706
+ <Button type="submit" data-variant="primary">Send inn</Button>
707
+ </Flex>
708
+ </form>
709
+ </Card>
710
+ );
711
+ }
712
+ ```
713
+
714
+ ---
715
+
716
+ ## 10. Worked page example
717
+
718
+ ```tsx
719
+ import { Flex, Grid, Card, Heading, Prose, Muted, Button, Tag } from '@mattilsynet/design/react';
720
+ import { WarningIcon } from '@phosphor-icons/react/ssr';
721
+
722
+ export function InspectionsPage() {
723
+ return (
724
+ <App.Main>
725
+ <Group>
726
+ <Prose>
727
+ <Heading as="h1" data-size="xl">Inspections</Heading>
728
+ {/* Compact toolbar — density cascades */}
729
+ <Flex>
730
+ <Button data-variant="primary">New</Button>
731
+ <Button>Export</Button>
732
+ </Flex>
733
+
734
+ <Grid data-items="300" data-gap="6">
735
+ <Card>
736
+ <Prose>
737
+ <Heading as="h2" data-size="sm">Fisk AS</Heading>
738
+ <Tag data-color="success">Approved</Tag>
739
+ <Muted>Inspected 03.05.2026</Muted>
740
+ </Prose>
741
+ </Card>
742
+
743
+ {/* Single attribute switches whole card to red */}
744
+ <Alert data-color="danger">
745
+ <Prose>
746
+ <Heading as="h2" data-size="sm"><WarningIcon /> Kjøtt &amp; Co</Heading>
747
+ <p>Critical violations. Follow up within 14 days.</p>
748
+ </Prose>
749
+ <Button data-variant="primary">Follow up</Button>
750
+ </Alert>
751
+ </Grid>
752
+ </Prose>
753
+ </Group>
754
+ </App.Main>
755
+ );
756
+ }
757
+ ```
758
+
759
+ ---
760
+
761
+ ## 11. Figma → code & pre-return checklist
762
+
763
+ When the input is a Figma frame/sketch, treat the design as a binding spec for *which design system components to use*, not just a pixel target.
764
+
765
+ ### 11.1 Figma component names map 1:1 to mtds component names
766
+
767
+ A Figma instance named **Card** → `<Card>`. **Field** → `<Field>`. **Errorsummary** → `<Errorsummary>`. **Info** → `<Info>`. Look up the Figma component name in §12 and use the matching React component. There is no name remapping table — if the names differ, the Figma library is out of date; ask before guessing.
768
+
769
+ ### 11.2 Mapping rules
770
+
771
+ - Map every visible Figma component instance to its corresponding component from `@mattilsynet/design/react`. Do **not** substitute custom HTML/CSS to gain layout control.
772
+ - Do **not** reach for raw `<div>`/`<span>` + CSS when a design system component covers the case — even if the component feels harder to make responsive. First try the component plus a wrapper (`Flex`, `Grid`, `Card`) and/or token-based CSS.
773
+ - **Auto-layout:** if children of a Figma auto-layout have equal width or width "fill", prefer `<Grid>` over `<Flex>`.
774
+ - **Metadata** (icon + value, or label + value): MUST use `<Info>` whenever Figma uses an `Info` instance, or whenever the content shape is icon + value or label + value. Custom `<span>`/`<div>` structures for metadata are not allowed unless the user explicitly approves the deviation.
775
+ - **Headings:** any Figma text styled as a heading → `<Heading as="hN" data-size="…">`, never raw `<h1>`–`<h6>` or styled `<div>`.
776
+ - **Lead/intro text** → `<Ingress>`. **Secondary/meta text** → `<Muted>`.
777
+ - **Surface containers:** Figma "Card" → `<Card>`; Figma tinted region grouping cards → `<Group>`.
778
+ - **Buttons, Tags, Chips, Alerts, Tabs, Steps, Dialog, Popover, Table, Field/Fieldset, Errorsummary** → use the matching component from §12. Do not reimplement.
779
+ - **Color regions:** when a Figma frame is in a semantic color (danger/warning/success/info/inverted), set `data-color="…"` on a parent rather than picking palette-prefixed tokens.
780
+ - If you genuinely believe a deviation is required (e.g. the component cannot express the intended behavior), **STOP**. Explain the deviation and the proposed alternative **before** writing code, and wait for explicit approval.
781
+ - If the sketch is unclear (text unreadable, intent unknown, missing state), list assumptions explicitly at the top of your final answer.
782
+
783
+ ### 11.3 Pre-return checklist
784
+
785
+ Before sending the final response, verify every item:
786
+
787
+ **Imports & setup**
788
+ - [ ] React components imported from `@mattilsynet/design/react`; icons from `@phosphor-icons/react/ssr`.
789
+ - [ ] Entry file imports `'@mattilsynet/design'` and `'@mattilsynet/design/styles.css'`.
790
+ - [ ] Exact export names spelled correctly: `Errorsummary`, `Togglegroup`, `Fileupload`, `HelpText`.
791
+
792
+ **Spacing, color, sizing**
793
+ - [ ] No raw `px`/`rem` for spacing — only `data-gap`, `data-pad`, or `var(--mtds-{n})` from the §5.1 scale.
794
+ - [ ] No hex/rgb/named colors — only `var(--mtds-color-*)` (palette-agnostic) under the right `data-color` parent.
795
+ - [ ] No inline `style={{…}}` for layout/color/spacing.
796
+ - [ ] No Tailwind utility classes.
797
+ - [ ] All spacing-token indexes used exist (`0`–`15`, `18`, `22`, `26`, `30`).
798
+ - [ ] `data-size` collisions accounted for (density on containers vs. local size on `Heading`/`Button`/`Info`).
799
+
800
+ **Markup**
801
+ - [ ] No raw `<h1>`–`<h6>` — every heading is `<Heading as="hN">`.
802
+ - [ ] No raw `<div style="display:flex">` — use `<Flex>` or `<Grid>`.
803
+ - [ ] Metadata pairs (icon + value / label + value) use `<Info>`, not custom `<span>`/`<div>`.
804
+
805
+ **App shell**
806
+ - [ ] `<App>` wraps the page; source order `Header → Toggle → Sidebar → Main → Footer`.
807
+ - [ ] Every leaf node inside `<App.Main>` is wrapped in `<Card>` or `<Group>`.
808
+ - [ ] `<Logo>` is the first child of `<App.Header>`.
809
+ - [ ] Sidebar buttons are icon-only with `data-tooltip="Label"`.
810
+ - [ ] Sidebar state uses `<App.Toggle>` and `<App.Sidebar>`
811
+
812
+ **Figma audit (when converting from a sketch)**
813
+ - [ ] Every visible Figma component instance is mapped to its `@mattilsynet/design/react` counterpart, or listed as an explicit, approved deviation.
814
+
815
+ ---
816
+
817
+ ## 12. Component index
818
+
819
+ Each component has full docs at `./ai/<name>.mdx` and examples in `./ai/<name>.stories.tsx`.
820
+ Read the relevant doc before using a component you have not used in this session.
821
+
822
+ ### Layout & structure
823
+
824
+ - **`App`** — page shell with `Header`, `Toggle`, `Sidebar`, `Sticky`, `Main`, `Footer`, `Script`. See §6.
825
+ - **`Card`** — solid white surface for one related content unit. `data-pad`, `data-radius`, `href`, `data-clickdelegatefor`. See §7.4.
826
+ - **`Group`** — tinted surface for a region of cards or meta-UI. Same attrs as `Card`. See §7.4.
827
+ - **`Flex`** — flex container for mixed-width children (toolbars, button rows). See §7.2.
828
+ - **`Grid`** — grid container for equal-width columns or vertical stacks. Use `data-items="300"` for responsive. See §7.2.
829
+ - **`Divider`** — visual separator (`<hr>` styling).
830
+
831
+ ### Typography
832
+
833
+ - **`Heading`** — `as="h1".."h6"` for semantics, `data-size="2xs".."2xl"` for visual size. See §8.1.
834
+ - **`Prose`** — apply vertical typographic rhythm to direct children (body text, lists, headings). See §8.2.
835
+ - **`Ingress`** — lead/intro paragraph. See §8.3.
836
+ - **`Muted`** — small/secondary text. See §8.3.
837
+ - **`Info`** — label + value pair, optionally with icon. `data-variant="regular│circle"`. See §8.4.
838
+ - **`Link`** — inline anchor styled to mtds.
839
+
840
+ ### Forms (see §9)
841
+
842
+ - **`Field`** — single field row. Two modes: composition (`<Field.Label>`+`<Input>`) or polymorphic (`<Field as="input" label="…" />`). Compound: `Label`, `Description`, `Suggestion`, `Datalist`, `Option`.
843
+ - **`Fieldset`** — group related fields. Compound: `Legend`, `Description`.
844
+ - **`Input`** — form control primitive (`<input>`, used inside `<Field>`).
845
+ - **`Validation`** — field-level validation message. Pass via `validation="…"` on `<Field as="…">`, or render directly inside `<Field>`.
846
+ - **`Errorsummary`** — top-of-form error list (note: single capital R). Children: `<Heading>` + `<ul><li><a href="#fieldId">`. See §9.3.
847
+ - **`Togglegroup`** — single-select toggle button row (single capital G). Compound: `Item`. See §9.5.
848
+ - **`Fileupload`** — file upload (experimental). See §9.6.
849
+ - **`HelpText`** — popover-style help button. Prefer `<Field helpText="…" />`. See §9.7.
850
+
851
+ ### Actions
852
+
853
+ - **`Button`** — primary action element. Renders `<a>` when `href` is set. Variants: `data-variant="primary│secondary│tertiary"`. Sizes via `data-size` on the button or its container.
854
+ - **`Chip`** — interactive filter chip / single-select toggle.
855
+
856
+ ### Feedback & status
857
+
858
+ - **`Alert`** — inline contextual feedback. Color via ancestor `data-color="info│success│warning│danger"`.
859
+ - **`Badge`** — small status indicator overlay (count, dot) on top of another element.
860
+ - **`Progress`** — progress bar.
861
+ - **`Skeleton`** — loading placeholder block.
862
+ - **`Spinner`** — loading spinner.
863
+ - **`Tag`** — read-only label/keyword. Color via `data-color`.
864
+ - **`Toast`** — transient notification (managed via toast helpers).
865
+
866
+ ### Navigation
867
+
868
+ - **`Breadcrumbs`** — breadcrumb trail.
869
+ - **`Pagination`** — paged result navigation.
870
+ - **`Steps`** — multi-step progress / timeline. Children are `<li>` with `<mark>`, `<strong>`, optional `<small>`. Set `aria-current="step"` on the active `<li>`. State via `data-state="complete"` on the `<ol>`/`<Steps>`.
871
+ - **`Tabs`** — tabbed content panels. Compound: `List`, `Tab`, `Panel`.
872
+
873
+ ### Display
874
+
875
+ - **`Avatar`** — round user avatar.
876
+ - **`Chart`** — chart wrapper.
877
+ - **`Details`** — disclosure widget. Compound: `Summary`.
878
+ - **`Dialog`** — modal dialog using native `<dialog>`. Open with `command="show-modal"` + `commandfor="id"`; close with `command="request-close"`.
879
+ - **`Popover`** — non-modal floating overlay using native popover API. Polymorphic via `as` (commonly `as="menu"`). Anchor with `popoverTarget="id"` on the trigger.
880
+ - **`Table`** — data table. Compound: `Thead`, `Tbody`, `Tr`, `Th`, `Td`, `ThSortable`.
881
+ - **`Tooltip`** — prefer `data-tooltip="…"` on any element instead of a component.
882
+
883
+ ### Domain & branding
884
+
885
+ - **`Law`** — Mattilsynet legal-text formatting.
886
+ - **`Logo`** — Mattilsynet (or sub-app) logo. Required as the first child of `<App.Header>`.
887
+ - **`Print`** — print-only utilities and breaks.
888
+
889
+ ### Map and Charts
890
+
891
+ - **`Atlas`** — interactive map.
892
+ - **`Chart`** — chart primitives.