@pnx-mixtape/mxds 0.1.0-rc.4 → 0.1.0-rc.6

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 (236) hide show
  1. package/.claude/skills/create-mxds-component/SKILL.md +77 -0
  2. package/DESIGN.md +595 -0
  3. package/README.md +2 -3
  4. package/dist/build/accordion.entry.js +2 -1
  5. package/dist/build/autocomplete.entry.js +1 -1
  6. package/dist/build/back-to-top.css +1 -0
  7. package/dist/build/back-to-top.entry.js +1 -0
  8. package/dist/build/base.css +1 -1
  9. package/dist/build/button.css +1 -1
  10. package/dist/build/card.css +1 -1
  11. package/dist/build/chunks/Accordion-Bqe8vTNR.js +44 -0
  12. package/dist/build/chunks/AccordionGroup-BYtoAFxg.js +47 -0
  13. package/dist/build/chunks/AccordionMobile-D517oXYZ.js +26 -0
  14. package/dist/build/chunks/Autocomplete-kRo8RNbC.js +135 -0
  15. package/dist/build/chunks/BackToTop-4M-Wl7z3.js +64 -0
  16. package/dist/build/chunks/ClosableAlert-CZ114JsL.js +55 -0
  17. package/dist/build/chunks/CookieConsent-wd8gQ2Oe.js +18 -0
  18. package/dist/build/chunks/Dialog-DoYcGqhW.js +48 -0
  19. package/dist/build/chunks/DropMenu-CSTZq0Zt.js +68 -0
  20. package/dist/build/chunks/FeedbackForm-BsL7fv8s.js +64 -0
  21. package/dist/build/chunks/Gallery-DqJPujX5.js +165 -0
  22. package/dist/build/chunks/GlobalToggle-7H3F1Wvc.js +82 -0
  23. package/dist/build/chunks/InPageNavigation-D7m3IN89.js +86 -0
  24. package/dist/build/chunks/Navigation-CRModT40.js +142 -0
  25. package/dist/build/chunks/Popover-CiTAftNU.js +30 -0
  26. package/dist/build/chunks/Sticky-C1H8MNqK.js +51 -0
  27. package/dist/build/chunks/Tabs-BJD3kABL.js +160 -0
  28. package/dist/build/chunks/Translate-yAgySwet.js +46 -0
  29. package/dist/build/chunks/cookie-compliance-CG6x-TcV.js +119 -0
  30. package/dist/build/chunks/enums-BrHxPZZ_.js +36 -0
  31. package/dist/build/chunks/polyfills-D-qh1a_2.js +33 -0
  32. package/dist/build/chunks/utilities-B9mNRs7V.js +255 -0
  33. package/dist/build/content-block.css +1 -1
  34. package/dist/build/cookie-consent.entry.js +1 -1
  35. package/dist/build/dialog.entry.js +1 -1
  36. package/dist/build/drop-menu.entry.js +1 -1
  37. package/dist/build/elements.js +147 -1
  38. package/dist/build/feedback-form.css +1 -0
  39. package/dist/build/feedback-form.entry.js +1 -0
  40. package/dist/build/filters.entry.js +145 -1
  41. package/dist/build/form.css +1 -1
  42. package/dist/build/gallery.entry.js +1 -1
  43. package/dist/build/global-alert.entry.js +1 -1
  44. package/dist/build/header.css +1 -1
  45. package/dist/build/header.entry.js +1 -1
  46. package/dist/build/icon.css +1 -1
  47. package/dist/build/in-page-navigation.entry.js +1 -1
  48. package/dist/build/navigation.css +1 -1
  49. package/dist/build/navigation.entry.js +1 -1
  50. package/dist/build/pagination.css +1 -1
  51. package/dist/build/popover.entry.js +1 -1
  52. package/dist/build/react.js +2291 -1
  53. package/dist/build/side-navigation.css +1 -1
  54. package/dist/build/sidebar.css +1 -1
  55. package/dist/build/sticky.entry.js +1 -1
  56. package/dist/build/tabs.entry.js +1 -1
  57. package/dist/build/translate.css +1 -0
  58. package/dist/build/translate.entry.js +1 -0
  59. package/dist/build/utility-list.entry.js +53 -1
  60. package/dist/types/Component/BackToTop/BackToTop.d.ts +20 -0
  61. package/dist/types/Component/BackToTop/BackToTop.d.ts.map +1 -0
  62. package/dist/types/Component/BackToTop/Elements/BackToTop.d.ts +27 -0
  63. package/dist/types/Component/BackToTop/Elements/BackToTop.d.ts.map +1 -0
  64. package/dist/types/Component/BackToTop/back-to-top.entry.d.ts +2 -0
  65. package/dist/types/Component/BackToTop/back-to-top.entry.d.ts.map +1 -0
  66. package/dist/types/Component/DropMenu/DropMenu.d.ts +2 -1
  67. package/dist/types/Component/DropMenu/DropMenu.d.ts.map +1 -1
  68. package/dist/types/Component/Navigation/Elements/Navigation.d.ts +2 -3
  69. package/dist/types/Component/Navigation/Elements/Navigation.d.ts.map +1 -1
  70. package/dist/types/Component/SideNavigation/Components/SideNavigationTree.d.ts +3 -3
  71. package/dist/types/Component/SideNavigation/Components/SideNavigationTree.d.ts.map +1 -1
  72. package/dist/types/Component/SideNavigation/SideNavigation.d.ts +3 -1
  73. package/dist/types/Component/SideNavigation/SideNavigation.d.ts.map +1 -1
  74. package/dist/types/Component/Tabs/Components/TabDropMenu.d.ts.map +1 -1
  75. package/dist/types/Component/Tabs/Elements/Tabs.d.ts.map +1 -1
  76. package/dist/types/Component/Translate/Elements/Translate.d.ts +23 -0
  77. package/dist/types/Component/Translate/Elements/Translate.d.ts.map +1 -0
  78. package/dist/types/Component/Translate/Translate.d.ts +37 -0
  79. package/dist/types/Component/Translate/Translate.d.ts.map +1 -0
  80. package/dist/types/Component/Translate/languages.d.ts +11 -0
  81. package/dist/types/Component/Translate/languages.d.ts.map +1 -0
  82. package/dist/types/Component/Translate/translate.entry.d.ts +2 -0
  83. package/dist/types/Component/Translate/translate.entry.d.ts.map +1 -0
  84. package/dist/types/Form/FeedbackForm/Elements/FeedbackForm.d.ts +37 -0
  85. package/dist/types/Form/FeedbackForm/Elements/FeedbackForm.d.ts.map +1 -0
  86. package/dist/types/Form/FeedbackForm/FeedbackForm.d.ts +36 -0
  87. package/dist/types/Form/FeedbackForm/FeedbackForm.d.ts.map +1 -0
  88. package/dist/types/Form/FeedbackForm/feedback-form.entry.d.ts +2 -0
  89. package/dist/types/Form/FeedbackForm/feedback-form.entry.d.ts.map +1 -0
  90. package/dist/types/Utility/Elements/google-translate-widget.d.ts +91 -0
  91. package/dist/types/Utility/Elements/google-translate-widget.d.ts.map +1 -0
  92. package/dist/types/Utility/utilities.d.ts +2 -0
  93. package/dist/types/Utility/utilities.d.ts.map +1 -1
  94. package/dist/types/elements.d.ts +3 -0
  95. package/dist/types/elements.d.ts.map +1 -1
  96. package/dist/types/enums.d.ts +3 -1
  97. package/dist/types/enums.d.ts.map +1 -1
  98. package/dist/types/react.d.ts +3 -0
  99. package/dist/types/react.d.ts.map +1 -1
  100. package/dist/types/tokens.d.ts +1 -0
  101. package/dist/types/tokens.d.ts.map +1 -1
  102. package/docs/API.md +1215 -0
  103. package/docs/CSSGuidelines.md +893 -0
  104. package/docs/CodeQuality.md +940 -0
  105. package/docs/ComponentArchitecture.md +714 -0
  106. package/docs/Contributing.md +626 -0
  107. package/docs/MemoryManagement.md +598 -0
  108. package/docs/Migrations.md +6 -0
  109. package/docs/README.md +100 -0
  110. package/docs/Security.md +444 -0
  111. package/docs/Testing.md +739 -0
  112. package/docs/Troubleshooting.md +674 -0
  113. package/package.json +9 -6
  114. package/src/Atom/Button/Button.tsx +1 -1
  115. package/src/Atom/Button/__snapshots__/Button.stories.tsx.snap +2 -2
  116. package/src/Atom/Button/_buttons.css +1 -0
  117. package/src/Atom/Icon/README.md +1 -1
  118. package/src/Atom/Icon/_icon.css +1 -0
  119. package/src/Atom/Icon/images/thumb.svg +1 -0
  120. package/src/Atom/Link/_links.css +1 -0
  121. package/src/Atom/Media/__snapshots__/Media.stories.ts.snap +4 -9
  122. package/src/Atom/Media/media.twig +4 -5
  123. package/src/Component/BackToTop/BackToTop.stories.ts +127 -0
  124. package/src/Component/BackToTop/BackToTop.stories.tsx +53 -0
  125. package/src/Component/BackToTop/BackToTop.tsx +120 -0
  126. package/src/Component/BackToTop/Elements/BackToTop.ts +119 -0
  127. package/src/Component/BackToTop/README.md +164 -0
  128. package/src/Component/BackToTop/__snapshots__/BackToTop.stories.ts.snap +24 -0
  129. package/src/Component/BackToTop/__snapshots__/BackToTop.stories.tsx.snap +3 -0
  130. package/src/Component/BackToTop/back-to-top.css +70 -0
  131. package/src/Component/BackToTop/back-to-top.entry.js +1 -0
  132. package/src/Component/BackToTop/back-to-top.twig +26 -0
  133. package/src/Component/Card/Components/CardContent.tsx +1 -1
  134. package/src/Component/Card/Components/CardMedia.tsx +1 -1
  135. package/src/Component/Card/__snapshots__/Card.stories.tsx.snap +3 -3
  136. package/src/Component/Card/card.css +1 -1
  137. package/src/Component/Carousel/Carousel.stories.ts +66 -36
  138. package/src/Component/Carousel/__snapshots__/Carousel.stories.tsx.snap +5 -5
  139. package/src/Component/ContentBlock/Components/ContentBlockMedia.tsx +1 -1
  140. package/src/Component/ContentBlock/content-block.css +1 -1
  141. package/src/Component/DropMenu/DropMenu.stories.ts +21 -2
  142. package/src/Component/DropMenu/DropMenu.tsx +14 -4
  143. package/src/Component/DropMenu/__snapshots__/DropMenu.stories.ts.snap +3 -3
  144. package/src/Component/DropMenu/__snapshots__/DropMenu.stories.tsx.snap +2 -2
  145. package/src/Component/DropMenu/drop-menu.twig +7 -1
  146. package/src/Component/HeroBanner/__snapshots__/HeroBanner.stories.tsx.snap +1 -1
  147. package/src/Component/InPageNavigation/__snapshots__/InPageNavigation.stories.ts.snap +48 -13
  148. package/src/Component/InPageNavigation/in-page-navigation.twig +4 -6
  149. package/src/Component/ListItem/Components/ListItemMedia.tsx +1 -1
  150. package/src/Component/Navigation/Elements/Navigation.ts +25 -29
  151. package/src/Component/Navigation/README.md +11 -10
  152. package/src/Component/Navigation/__snapshots__/Navigation.stories.ts.snap +8 -8
  153. package/src/Component/Navigation/_navigation-dropdown.css +9 -11
  154. package/src/Component/Navigation/_navigation-mega.css +5 -11
  155. package/src/Component/Navigation/_navigation.css +5 -3
  156. package/src/Component/Navigation/menu.twig +1 -1
  157. package/src/Component/Navigation/navigation.twig +0 -1
  158. package/src/Component/Pagination/Pagination.stories.ts +57 -27
  159. package/src/Component/Pagination/pagination.css +16 -7
  160. package/src/Component/Popover/__snapshots__/Popover.stories.tsx.snap +3 -3
  161. package/src/Component/SideNavigation/Components/SideNavigationTree.tsx +68 -24
  162. package/src/Component/SideNavigation/README.md +78 -32
  163. package/src/Component/SideNavigation/SideNavigation.stories.ts +41 -2
  164. package/src/Component/SideNavigation/SideNavigation.stories.tsx +31 -0
  165. package/src/Component/SideNavigation/SideNavigation.tsx +13 -3
  166. package/src/Component/SideNavigation/__snapshots__/SideNavigation.stories.ts.snap +87 -3
  167. package/src/Component/SideNavigation/__snapshots__/SideNavigation.stories.tsx.snap +2 -0
  168. package/src/Component/SideNavigation/side-navigation.css +3 -3
  169. package/src/Component/SideNavigation/side-navigation.twig +10 -3
  170. package/src/Component/Tabs/Components/TabDropMenu.tsx +7 -1
  171. package/src/Component/Tabs/Elements/Tabs.ts +13 -3
  172. package/src/Component/Tabs/Tabs.stories.ts +33 -12
  173. package/src/Component/Tabs/Tabs.stories.tsx +28 -14
  174. package/src/Component/Tabs/__snapshots__/Tabs.stories.ts.snap +3 -3
  175. package/src/Component/Tabs/__snapshots__/Tabs.stories.tsx.snap +2 -2
  176. package/src/Component/Translate/Elements/Translate.ts +76 -0
  177. package/src/Component/Translate/README.md +285 -0
  178. package/src/Component/Translate/Translate.stories.ts +87 -0
  179. package/src/Component/Translate/Translate.stories.tsx +77 -0
  180. package/src/Component/Translate/Translate.tsx +213 -0
  181. package/src/Component/Translate/__snapshots__/Translate.stories.ts.snap +18 -0
  182. package/src/Component/Translate/__snapshots__/Translate.stories.tsx.snap +3 -0
  183. package/src/Component/Translate/languages.ts +39 -0
  184. package/src/Component/Translate/translate.css +62 -0
  185. package/src/Component/Translate/translate.entry.js +1 -0
  186. package/src/Component/Translate/translate.twig +44 -0
  187. package/src/Form/Autocomplete/Autocomplete.stories.tsx +2 -1
  188. package/src/Form/FeedbackForm/Elements/FeedbackForm.ts +122 -0
  189. package/src/Form/FeedbackForm/FeedbackForm.stories.ts +99 -0
  190. package/src/Form/FeedbackForm/FeedbackForm.stories.tsx +73 -0
  191. package/src/Form/FeedbackForm/FeedbackForm.tsx +196 -0
  192. package/src/Form/FeedbackForm/README.md +233 -0
  193. package/src/Form/FeedbackForm/__snapshots__/FeedbackForm.stories.ts.snap +125 -0
  194. package/src/Form/FeedbackForm/__snapshots__/FeedbackForm.stories.tsx.snap +5 -0
  195. package/src/Form/FeedbackForm/feedback-form.css +74 -0
  196. package/src/Form/FeedbackForm/feedback-form.entry.js +1 -0
  197. package/src/Form/FeedbackForm/feedback-form.twig +80 -0
  198. package/src/Form/form.css +17 -19
  199. package/src/Introduction.mdx +1 -1
  200. package/src/Layout/Footer/__snapshots__/Footer.stories.ts.snap +3 -3
  201. package/src/Layout/Header/Components/GlobalToggle.tsx +1 -1
  202. package/src/Layout/Header/Header.stories.ts +53 -48
  203. package/src/Layout/Header/Header.stories.tsx +35 -22
  204. package/src/Layout/Header/Header.tsx +2 -2
  205. package/src/Layout/Header/__snapshots__/Header.stories.ts.snap +18 -14
  206. package/src/Layout/Header/__snapshots__/Header.stories.tsx.snap +2 -2
  207. package/src/Layout/Header/_toggles.css +7 -7
  208. package/src/Layout/Page/__snapshots__/Page.stories.tsx.snap +1 -1
  209. package/src/Layout/Sidebar/sidebar.css +10 -3
  210. package/src/Utility/Elements/google-translate-widget.ts +293 -0
  211. package/src/Utility/global.d.ts +4 -0
  212. package/src/Utility/utilities.ts +2 -0
  213. package/src/_custom-media.css +2 -0
  214. package/src/elements.ts +3 -0
  215. package/src/enums.ts +2 -0
  216. package/src/react.ts +3 -0
  217. package/src/tokens.js +1 -0
  218. package/dist/build/chunks/Accordion-GN0sME4W.js +0 -1
  219. package/dist/build/chunks/AccordionGroup-Bzqp5__q.js +0 -1
  220. package/dist/build/chunks/AccordionMobile-DG5jSe8Q.js +0 -1
  221. package/dist/build/chunks/Autocomplete-B4RtkAyh.js +0 -1
  222. package/dist/build/chunks/ClosableAlert-DEhj8Nxm.js +0 -1
  223. package/dist/build/chunks/CookieConsent-BkCMRVST.js +0 -1
  224. package/dist/build/chunks/Dialog-Haahn-Yn.js +0 -1
  225. package/dist/build/chunks/DropMenu-1baQc8Yc.js +0 -1
  226. package/dist/build/chunks/Gallery-D8NGXy2Q.js +0 -1
  227. package/dist/build/chunks/GlobalToggle-B52fdBQu.js +0 -1
  228. package/dist/build/chunks/InPageNavigation-Dyn2TR-N.js +0 -1
  229. package/dist/build/chunks/Navigation-hOrfLq7h.js +0 -1
  230. package/dist/build/chunks/Popover-Cxg-s5Jn.js +0 -1
  231. package/dist/build/chunks/Sticky-BGCuuEJK.js +0 -1
  232. package/dist/build/chunks/Tabs-DYy1YTdU.js +0 -15
  233. package/dist/build/chunks/cookie-compliance-Bbm-0vpj.js +0 -1
  234. package/dist/build/chunks/enums-DLV_1NAf.js +0 -1
  235. package/dist/build/chunks/polyfills-C7pRt54M.js +0 -1
  236. package/dist/build/chunks/utilities-_Bq3TxAQ.js +0 -1
package/DESIGN.md ADDED
@@ -0,0 +1,595 @@
1
+ # Mixtape Design System — Design Reference
2
+
3
+ > This file is a structured reference for AI Design based tool onboarding (eg. Claude Design). It maps the design system's
4
+ > tokens, components, conventions, and rules so the Agent can accurately generate designs and prototypes
5
+ > using this system without ambiguity.
6
+ >
7
+ > **Read this as instruction, not advice.** Every "read X" below is a directive, not a suggestion — if a
8
+ > section says to read a file or use a specific class, do that; do not infer an alternative from context.
9
+ > When in doubt, prefer an existing class or token over inventing one.
10
+ >
11
+ > **When linking this repo to an AI Design tool:**
12
+ >
13
+ > - ✅ Include `dist/build/` — Browser-ready CSS with all tokens resolved, for accurate design generation
14
+ > - ✅ Include `src/` — source files for reference on component structure, token definitions, and CSS architecture
15
+ > - ✅ Include `docs/` — how-to guides, component architecture, CSS conventions
16
+ > - ✅ Include `mockups/` — full page composition examples showing how components assemble together
17
+ > - ❌ Exclude `notes/` — internal development notes, not relevant to design generation
18
+ > - ❌ Exclude build/config files (`pnpm-lock.yaml`, `vite.config.js`, `docker-compose*.yml`, `vitest.config.js`) — these add noise without design value
19
+
20
+ ---
21
+
22
+ ## Package
23
+
24
+ ```
25
+ @pnx-mixtape/mxds
26
+ ```
27
+
28
+ - Storybook: https://mxds.pnx.io/
29
+ - npm: https://www.npmjs.com/package/@pnx-mixtape/mxds
30
+
31
+ ---
32
+
33
+ ## Reference materials
34
+
35
+ **For full-page composition examples, read [`mockups/HomePage.stories.ts`](./mockups/HomePage.stories.ts) first.** It shows how Atoms, Components, and Layouts assemble into a complete page using real classes — before generating anything, read at least one mockup end-to-end.
36
+
37
+ **Mockups are Storybook stories; the `args` field is the source HTML.** Ignore the `meta`, decorators, and Storybook boilerplate — the composition you want lives in each story's `args`. Other full-page examples in [`mockups/`](./mockups/): `ArticlePage`, `ArticleListingPage`, `BasicPage`, `ContactPage`, `EventPage`, `EventListingPage`, `LandingPage`, `SearchResultPage`, `SidebarPage`.
38
+
39
+ Each component README ends with a `→ Used in context:` footer pointing at the mockup line where it's composed — follow it to see the component in a real page.
40
+
41
+ ---
42
+
43
+ ## Design Tokens
44
+
45
+ Tokens are defined in **`src/tokens.js`** and compiled into CSS custom properties via `postcss-design-tokens`.
46
+
47
+ The resolved custom properties live in **`src/constants.css`** inside `@layer design-system.defaults`.
48
+
49
+ ### Colours
50
+
51
+ | Token path | CSS custom property | Value |
52
+ | ----------------------- | ----------------------------- | --------------------------------- |
53
+ | `colour.primary.colour` | `--colour-primary` | `hsl(223 100% 50%)` — vivid blue |
54
+ | `colour.accent.colour` | `--colour-accent` | `hsl(60, 94%, 68%)` — warm yellow |
55
+ | `colour.main.fg` | `--colour-foreground` | `hsl(60 30% 6%)` — near-black |
56
+ | `colour.main.bg` | `--colour-background` | `hsl(60 0% 100%)` — white |
57
+ | `colour.main.fgAlt` | `--colour-foreground-alt` | `hsl(60 30% 20%)` |
58
+ | `colour.main.bgAlt` | `--colour-background-alt` | `hsl(60 30% 95%)` |
59
+ | `colour.main.border` | `--colour-border` | `hsl(60 5% 85%)` |
60
+ | `colour.reverse.fg` | `--colour-foreground-reverse` | `hsl(60 0% 100%)` |
61
+ | `colour.reverse.bg` | `--colour-background-reverse` | `hsl(60 30% 6%)` |
62
+ | `colour.error` | `--colour-error` | `hsl(348 100% 33%)` — red |
63
+ | `colour.success` | `--colour-success` | `hsl(120 100% 26%)` — green |
64
+ | `colour.warning` | `--colour-warning` | `hsl(35 100% 32%)` — amber |
65
+ | `colour.info` | `--colour-info` | `hsl(223 100% 50%)` — blue |
66
+
67
+ Light/dark mode: colours use `light-dark()` CSS function. The scheme is controlled by `--scheme` (`light | dark`).
68
+
69
+ Tints are derived automatically via `color-mix()`:
70
+
71
+ - `--colour-primary-light` — primary + 90% white
72
+ - `--colour-primary-lighter` — primary + 20% white
73
+ - `--colour-primary-darker` — primary + 10% black
74
+
75
+ ### Typography
76
+
77
+ The size scale is generated from a single ratio (`--type-ratio`, default `1.414` — augmentedFourth) using `pow()`, so each step is `base × ratio^n`.
78
+ The ratio comes from `font.size.ratio` in `src/tokens.js`; on `--medium-down` viewports it is replaced with `font.size.ratioSmall` (default `1.2` — minorThird) so the scale tightens automatically on mobile.
79
+ Both values index into a `global.typeScales` table of named scales (`minorSecond` 1.067 → `goldenRatio` 1.618) — swap either token to apply a different musical scale across the whole system.
80
+
81
+ | CSS custom property | Value / formula |
82
+ | ---------------------- | --------------------------------------------------------- |
83
+ | `--font-family` | `system-ui, sans-serif` |
84
+ | `--base-font-size` | `max(1rem, 16px)` |
85
+ | `--type-ratio` | `1.414` desktop / `1.2` mobile (`--medium-down` override) |
86
+ | `--font-size` | base (1rem) — used as the inherited default |
87
+ | `--font-size-xs` | base × `pow(--type-ratio, -0.5)` |
88
+ | `--font-size-s` | base × `pow(--type-ratio, -0.25)` |
89
+ | `--font-size-m` | `1rem` (anchor — equal to base) |
90
+ | `--font-size-ml` | base × `pow(--type-ratio, 0.5)` |
91
+ | `--font-size-l` | base × `pow(--type-ratio, 1)` |
92
+ | `--font-size-xl` | base × `pow(--type-ratio, 2)` |
93
+ | `--font-size-xxl` | base × `pow(--type-ratio, 3)` |
94
+ | `--font-size-xxxl` | base × `pow(--type-ratio, 4)` |
95
+ | `--font-size-diff` | `0.3` — fluid-clamp drop, used by `clamp()` text sizing |
96
+ | `--font-weight-normal` | 400 |
97
+ | `--font-weight-bold` | 700 |
98
+ | `--line-height` | 1.6 (body) |
99
+ | `--line-height-h` | 1.2 (headings) |
100
+ | `--line-height-ui` | `0.9rem` (form controls) |
101
+
102
+ Because `--type-ratio` swaps on the breakpoint, every `--font-size-*` (other than `m`) recalculates fluidly — there is no separate mobile size scale to maintain.
103
+
104
+ > See [`docs/CSSGuidelines.md → Swapping the type scale`](./docs/CSSGuidelines.md#swapping-the-type-scale) for a worked example of overriding to a different musical scale (perfect fourth, golden ratio, etc.).
105
+
106
+ ### Spacing
107
+
108
+ Scale is `em`-based. All values map to `--spacing-{size}`:
109
+
110
+ | Size | Value |
111
+ | ------- | ------- |
112
+ | `xxxxs` | 0.25em |
113
+ | `xxxs` | 0.5em |
114
+ | `xxs` | 0.75em |
115
+ | `xs` | 0.875em |
116
+ | `s` | 1em |
117
+ | `m` | 1.5em |
118
+ | `l` | 2em |
119
+ | `xl` | 2.5em |
120
+ | `xxl` | 3em |
121
+ | `xxxl` | 3.5em |
122
+ | `xxxxl` | 4em |
123
+ | `ul` | 4.5em |
124
+ | `uul` | 5em |
125
+ | `uuul` | 5.5em |
126
+
127
+ Gap shortcuts: `--gap-s` (1em), `--gap` (1.5em), `--gap-l` (2em), `--gap-xl` (2.5em)
128
+
129
+ ### Breakpoints
130
+
131
+ | Name | Value | Custom media |
132
+ | ----- | ------ | --------------------------------- |
133
+ | `xxs` | 320px | — |
134
+ | `xs` | 420px | `--x-small-up` / `--x-small-down` |
135
+ | `s` | 540px | `--small-up` / `--small-down` |
136
+ | `m` | 720px | `--medium-up` / `--medium-down` |
137
+ | `l` | 946px | `--large-up` / `--large-down` |
138
+ | `xl` | 1100px | `--x-large-up` / `--x-large-down` |
139
+
140
+ Additional utility media queries available: `--touch`, `--mouse`, `--dark`, `--light`, `--use-motion`, `--reduce-motion`, `--high-contrast`, `--portrait`, `--landscape`.
141
+
142
+ This system is **mobile-first** — use `--medium-up` etc. to progressively enhance.
143
+
144
+ ### Layout
145
+
146
+ | CSS custom property | Value |
147
+ | ------------------------------ | --------------------------------- |
148
+ | `--container-max-width` | `76ch` (aligned) |
149
+ | `--container-max-width-narrow` | `58ch` (narrow) |
150
+ | `--gutter-min` | `1em` |
151
+ | `--gutter-max` | `2em` |
152
+ | `--border-radius` | `4px` |
153
+ | `--border-radius-l` | `2em` (pill) |
154
+ | `--border-radius-round` | `50%` (circle) |
155
+ | `--box-shadow` | `0 0 0.875em hsl(0 0% 13% / 15%)` |
156
+
157
+ ---
158
+
159
+ ## CSS Architecture
160
+
161
+ → See [`docs/CSSGuidelines.md`](./docs/CSSGuidelines.md) for full details on PostCSS pipeline, BEM naming, cascade layers, custom media, logical properties, and override patterns.
162
+
163
+ **Key facts for quick reference:**
164
+
165
+ - All styles are in named `@layer` sub-layers (`design-system.defaults` → `.atoms` → `.layout` → `.components` → `.utilities`)
166
+ - Class prefix: `mx-` — modifiers are BEM-style `mx-component--modifier`
167
+ - Each component has `component.css` (full), `_component.css` (structure), `_component-styles.css` (colour variants)
168
+ - Any **unlayered CSS wins** over all design system styles — no specificity battles
169
+
170
+ ---
171
+
172
+ ## Canonical class inventory
173
+
174
+ > **This is the complete list of public `mx-*` classes that exist in the CSS.** Generated from `src/**/*.css`.
175
+ > To regenerate: `grep -rhoE '\.mx-[a-z0-9][a-zA-Z0-9-]*' src --include="*.css" | sort -u`
176
+ >
177
+ > **Nothing else exists — do not invent classes.** If a class you want is not in this list, it is not part of
178
+ > the system. Use an existing class, a CSS custom property override, or unlayered CSS instead.
179
+
180
+ ### Atoms
181
+
182
+ | Class | Purpose |
183
+ | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
184
+ | `mx-background--primary` `--accent` `--alt` `--reverse` `--box` `--image` | Coloured background regions |
185
+ | `mx-button` | Base button |
186
+ | `mx-button--dark` `--light` `--accent` `--secondary` `--destructive` `--white` | Button colour variants |
187
+ | `mx-button--outline` | Outline style — **requires a colour modifier** (see grammar) |
188
+ | `mx-button--small` `--large` `--full-width` `--icon-only` | Button layout/size |
189
+ | `mx-heading--xs` `--s` `--m` `--l` `--xl` `--xxl` | Heading size overrides |
190
+ | `mx-headline` | Display headline |
191
+ | `mx-icon` | Base icon |
192
+ | `mx-icon--{name}` | Icon glyph — `{name}` from the `Icons` enum (e.g. `--close`) |
193
+ | `mx-icon--color-brand` `--color-accent` `--color-error` `--color-info` `--color-success` `--color-warning` | Icon colour |
194
+ | `mx-icon--size-sm` `--size-md` `--size-lg` `--size-xl` | Icon size |
195
+ | `mx-icon--rotate-90` `--rotate-180` `--rotate-270` | Icon rotation |
196
+ | `mx-icon--end` `--only` `--status` | Icon placement / icon-only |
197
+ | `mx-link` | Base link |
198
+ | `mx-link--external` `--download` `--more` | Link variants |
199
+ | `mx-list` | Base `<ul>`/`<ol>` list |
200
+ | `mx-list--notes` `--refs` `--stats` `--columns` `--summary` `__action` | List variants — footnotes, hanging-indent references, stat grid, column grid, and (`DefinitionList`-only) review-answers summary rows with an action slot |
201
+ | `mx-media--left` `--center` `--right` `--video` | Media alignment / video aspect |
202
+ | `mx-rich-text` | Rich text (CMS content) region |
203
+ | `mx-table--bordered` `--striped` `--flush` `--small` `--responsive` `--reset` | Table variants |
204
+ | `mx-text--xs` `--s` `--m` `--l` `--xl` `--xxl` `--xxxl` | Text size |
205
+ | `mx-text--primary` `--accent` `--alt` | Text colour |
206
+ | `mx-text--left` `--center` `--right` | Text alignment |
207
+ | `mx-text--eyebrow` `--lede` `--meta` `--embellished` `--embellished-headline` `--section-headline` `--fluid` | Special text styles |
208
+ | `mx-video` | Video embed |
209
+ | `mx-spacing--{side}-{size}` `mx-spacing--reset` `mx-spacing--{side}-reset` | Padding utility — `{side}` = top/bottom/left/right, `{size}` = spacing scale |
210
+ | `mx-margin--{side}-{size}` `mx-margin--reset` `mx-margin--{side}-reset` | Margin utility — same `{side}`/`{size}` grammar as spacing |
211
+ | `mx-animated--fade-in` `--fade-out` `--scale-up` `--scale-down` `--spin` | Animation utilities |
212
+
213
+ ### Components
214
+
215
+ | Class | Purpose |
216
+ | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
217
+ | `mx-accordion` `mx-accordions` `mx-accordion--divided` | Accordion + group |
218
+ | `mx-back-to-top` `mx-back-to-top--l` | Scroll-to-top trigger (breakpoint-gated) |
219
+ | `mx-callout` | Callout aside |
220
+ | `mx-card` `mx-card--block` `mx-card--collapse` `mx-card--reversed` | Card + variants |
221
+ | `mx-carousel` | Carousel |
222
+ | `mx-content-block` | Rich content region |
223
+ | `mx-cookie-consent` `mx-cookie-consent__actions` `mx-cookie-consent__inner` | Site-wide cookie consent banner |
224
+ | `mx-dialog` `mx-dialog--fullscreen` | Modal dialog |
225
+ | `mx-drop-menu` | Dropdown menu |
226
+ | `mx-filters` `mx-filters--right` `mx-filters--sticky` `mx-filter-item` | Filter controls |
227
+ | `mx-gallery` `mx-gallery__preview` `mx-gallery__trigger` | Image preview → fullscreen carousel modal |
228
+ | `mx-global-alert` `mx-global-alert--critical` | Site-wide alert banner |
229
+ | `mx-hero-banner` `mx-hero-banner--hero` | Hero banner (also used by HeroSearch) |
230
+ | `mx-in-page-navigation` | In-page TOC nav |
231
+ | `mx-link-list` | Link list |
232
+ | `mx-list-item` | List item (extends Card) |
233
+ | `mx-nav` | Base navigation |
234
+ | `mx-nav--breadcrumbs` `--collapsible` `--dropdown` `--mega-nav` `--inline` `--reverse` `--footer` `--open` | Navigation variants + state |
235
+ | `mx-pagination` | Pagination |
236
+ | `mx-popover` | Popover panel |
237
+ | `mx-progress-indicator` `__count` `__track` `__marker` `--done` `--now` `__steps` `__step` `--done` | Horizontal step-progress tracker for wizards/forms |
238
+ | `mx-results-bar` | Results count + sort bar |
239
+ | `mx-side-nav` | Secondary vertical nav |
240
+ | `mx-social-links` | Social profile links |
241
+ | `mx-social-share` | Share-to-social buttons |
242
+ | `mx-steps` `mx-steps--counters` `--fill` `--dark` `--supplementary` | Step indicator |
243
+ | `mx-sticky` `mx-sticky--m` `mx-sticky--l` | Sticky wrapper (breakpoint-gated) |
244
+ | `mx-tabs` `mx-tabs--lined` `mx-tabs--centered` | Tabs |
245
+ | `mx-tag` `mx-tags` `mx-tag--dismissible` | Tag + tag list. **No colour/outline variants exist** |
246
+ | `mx-translate` `__trigger` `__code` `__menu` `__item` `__notice` | Language switcher, drives Google's Website Translator |
247
+ | `mx-utility-list` | Utility link bar |
248
+
249
+ ### Forms
250
+
251
+ | Class | Purpose |
252
+ | --------------------------------------------------------------------------- | ----------------------------------------------------- |
253
+ | `mx-autocomplete` `mx-autocomplete__listbox` `mx-autocomplete__option` | Editable combobox with a suggestion listbox |
254
+ | `mx-feedback-form` `__rating` `__option` `__secondary` `__error` `__reveal` | Yes/no feedback control with a revealed comment field |
255
+ | `mx-form-actions` `mx-form--inline-button` | Form actions row / inline button |
256
+ | `mx-form-item` `mx-form-item--inline` | Field group |
257
+ | `mx-fieldset` `mx-fieldset--inline` `mx-fieldset--plain` | Fieldset |
258
+ | `mx-legend` | Fieldset legend |
259
+ | `mx-label` `mx-label--inline` | Field label |
260
+ | `mx-input` `mx-input--icon` `mx-input--small` `mx-input--wide` | Text input |
261
+ | `mx-checkbox` `mx-radio` | Checkbox / radio |
262
+ | `mx-choice-card` `mx-choice-card__hint` `mx-choice-divider` | Card-style checkbox/radio + shared "or" divider |
263
+ | `mx-description` | Field helper text |
264
+ | `mx-required` | Required indicator |
265
+ | `mx-error-message` `mx-success-message` | Field status messages |
266
+
267
+ ### Layout
268
+
269
+ | Class | Purpose |
270
+ | ------------------------------------------------------------------------ | ---------------------------------------------------------------------- |
271
+ | `mx-page` `mx-page--full` `mx-page--feature` `mx-page--narrow` | Page grid wrapper + track widths |
272
+ | `mx-container` | Container-query context (**not** a width constraint) |
273
+ | `mx-section` | Page section |
274
+ | `mx-section--s` `--m` `--l` `--xl` | Section padding scale |
275
+ | `mx-section--top-s/-m/-l/-xl` `mx-section--bottom-s/-m/-l/-xl` | Directional section padding |
276
+ | `mx-section--flow` `--group` `--divider` `--full` `--feature` `--narrow` | Section modes / layout |
277
+ | `mx-section--has-background` | Legacy `:has()` fallback for containing background images (no padding) |
278
+ | `mx-grid` `mx-grid-item` | Grid wrapper + item |
279
+ | `mx-grid--cols-{bp}-{n}` | Column count per breakpoint (`bp` = xs/sm/md/lg/xl, `n` = 2/3/4) |
280
+ | `mx-grid--collapse` `--collapse-cols` `--collapse-rows` | Grid gap collapse |
281
+ | `mx-grid--sidebar` `--sidebar-rev` `--sidebar-rev-lg` | Sidebar grid variants |
282
+ | `mx-header` | Site header |
283
+ | `mx-masthead` | Top branding bar |
284
+ | `mx-footer` | Site footer |
285
+ | `mx-logo` | Logo |
286
+ | `mx-skip-links` | Skip-link container |
287
+
288
+ ### Utilities
289
+
290
+ | Class | Purpose |
291
+ | ------------------------------------------------------------------ | --------------------------- |
292
+ | `mx-vertical-flow` `mx-vertical-flow-flex` `mx-vertical-flow-grid` | Vertical flow spacing |
293
+ | `mx-horizontal-flow-flex` | Horizontal flow spacing |
294
+ | `skeleton--bg` | Loading skeleton background |
295
+
296
+ ---
297
+
298
+ ## Composition grammar
299
+
300
+ The rules below live in CSS and are invisible to a consumer reading a README. **Follow them exactly.**
301
+
302
+ ### Modifiers that require a colour partner
303
+
304
+ - `mx-button--outline` does **nothing on its own** — it only styles when combined with a colour modifier:
305
+ `mx-button--outline mx-button--dark` (also works with `--accent`, `--destructive`, `--white`). Outline + `--light`/`--secondary` has no effect.
306
+
307
+ ### Backgrounds & full-bleed
308
+
309
+ `mx-page` **defines** a named column grid (`full` / `container` / `feature` / `narrow`) — see [Page layout](./src/Layout/Page/README.md). **Only a _direct grid child_ of `mx-page` can span the full-bleed width.** This is the most common invisible-rule bug: a background applied at the wrong nesting level silently fails to span.
310
+
311
+ - **Put `mx-background--*` on a section-level wrapper that is a direct child of `mx-page`** — not on inner content. When it is, that element spans `full` and inherits the parent's tracks as a **subgrid**, so its own children fall back to the `container` track automatically (the colour bleeds edge-to-edge while text stays aligned). Only these nested full-bleed children (and nested `mx-page` elements) become subgrids — the top-level `mx-page` is the grid definition itself, not a subgrid.
312
+ - **Add section padding** with a spacing modifier (`mx-section--m` / `--l` / etc.) — a coloured region with no padding looks broken. Padding comes from the spacing classes, _not_ from the background.
313
+ - **`mx-section--has-background`** is a legacy `:has()` fallback (for browsers without `:has()` support) that sets `overflow`/`position` so a background image is contained — it does **not** add padding. Modern browsers derive this from `:has(.mx-background--image)` automatically.
314
+ - **Exception:** `mx-background--box` is an inline, non-bleeding background (a boxed panel) — it does _not_ trigger the subgrid span and can sit on inner content.
315
+
316
+ Correct nesting:
317
+
318
+ ```
319
+ mx-page
320
+ └─ mx-section mx-section--l mx-background--primary ← direct child, spans full-bleed (--l adds padding)
321
+ └─ content ← stays on the container track
322
+ ```
323
+
324
+ Wrong (background won't span — applied below the grid child):
325
+
326
+ ```
327
+ mx-page
328
+ └─ mx-section
329
+ └─ div.mx-background--primary ← not a direct grid child; no full-bleed
330
+ ```
331
+
332
+ ### Card layout requires a container-query wrapper
333
+
334
+ `mx-card`'s two-column (media + content) layout is driven by **container queries**, not viewport breakpoints. It only activates when the card sits inside an element that establishes the `card` container context — in practice, wrap the card in `mx-container` (or place it as a direct child of `mx-grid`, which sets it up).
335
+
336
+ - ✅ `<div class="mx-container"><div class="mx-card">…</div></div>` → card can switch to side-by-side at wide container widths.
337
+ - ❌ A bare `mx-card` with no `mx-container` / `mx-grid` ancestor → stays stacked forever, regardless of available width. Same invisible-rule class as `mx-button--outline` without a colour: the class is correct but a required companion is missing.
338
+
339
+ ### Modifiers that combine
340
+
341
+ - **Button:** one colour (`--dark`/`--light`/`--accent`/`--secondary`/`--destructive`/`--white`) + optionally `--outline` + optionally one size (`--small`/`--large`) + optionally `--full-width` or `--icon-only`.
342
+ - **Steps:** `mx-steps--counters` adds numbered counters; combine with a colour mode (`--dark`/`--supplementary`) and/or `--fill`.
343
+ - **Section:** a padding scale (`--s`/`--m`/`--l`/`--xl`) + optionally `--flow` or `--group`. For colour, add an `mx-background--*` class (the padding still comes from the scale class). `--has-background` is only the legacy `:has()` fallback, not part of this composition.
344
+
345
+ ### Modifiers that do NOT exist (common false positives)
346
+
347
+ - ❌ `mx-button--primary` — use `mx-button--dark`
348
+ - ❌ `mx-section--primary` — use `mx-section` + `mx-background--primary`
349
+ - ❌ `mx-tag--accent`, `mx-tag--outline`, `mx-tag--primary` — Tag has **no colour or outline variants**; only `mx-tag--dismissible`
350
+ - ❌ `mx-hero__eyebrow` or any custom eyebrow class — use `mx-text--eyebrow`
351
+ - ❌ `mx-card--primary` / colour modifiers on Card — set a background via `mx-background--*` on the card or its section
352
+
353
+ ---
354
+
355
+ ## Anti-patterns — things that look right but aren't
356
+
357
+ - **`mx-button--outline` without a colour modifier.** Renders invisible. Always pair with a colour (see [Composition grammar](#composition-grammar)).
358
+ - **A `mx-background--*` region that doesn't bleed.** Almost always caused by applying it below the direct child of `mx-page` — see [Backgrounds & full-bleed](#backgrounds--full-bleed).
359
+ - **A `mx-card` stuck in stacked layout.** Missing the `mx-container` / `mx-grid` wrapper that provides its container-query context — see [Card layout requires a container-query wrapper](#card-layout-requires-a-container-query-wrapper).
360
+
361
+ > Reinventing classes that don't exist (`mx-button--primary`, custom eyebrow utilities, `--primary` colour modifiers, etc.) is covered in [Modifiers that do NOT exist](#modifiers-that-do-not-exist-common-false-positives) — don't do it.
362
+
363
+ ---
364
+
365
+ ## What to use for X — cheatsheet
366
+
367
+ Common visual intents mapped to the idiomatic Mixtape class. Reach for these before inventing anything.
368
+
369
+ | I want… | Use |
370
+ | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
371
+ | Small uppercase label above a heading (eyebrow) | `mx-text--eyebrow` (with underbar: `mx-text--embellished`) |
372
+ | A section with a brand-coloured background | `mx-section` + `mx-background--primary` |
373
+ | A bold call-to-action button on a light surface | `mx-button--dark` |
374
+ | A CTA button on a dark/reverse surface | `mx-button--white` |
375
+ | A secondary/outline button | `mx-button--outline` **+** a colour (e.g. `mx-button--dark`) |
376
+ | An accent-coloured button | `mx-button--accent` |
377
+ | A large display heading | `mx-headline` or `mx-heading--xl` / `--xxl` |
378
+ | Lead / intro paragraph | `mx-text--lede` |
379
+ | A responsive multi-column card grid | `mx-grid` + `mx-grid--cols-lg-3` (etc.) |
380
+ | A category label/badge | `mx-tag` (no colour variants — style via `--tag-*` tokens) |
381
+ | Constrain content width | Content inside `mx-page` sits in the `container` track (`76ch`) by default; use `mx-section--narrow` (`58ch`) for reading width, `mx-section--feature` / `mx-section--full` to widen. See [Page layout](./src/Layout/Page/README.md). `mx-container` is **not** a width constraint — it establishes a container-query context. |
382
+
383
+ ---
384
+
385
+ ## Public token API
386
+
387
+ These CSS custom properties are the **intended override surface** — set them (scoped to a context class) to customise a component. They are recognisable in source by the `var(--token, fallback)` pattern and are marked `/* @public */` in the CSS. **Everything else (`--line-width`, `--counter-top`, `--font-min`, `--plus`/`--minus`, `--grid-repeat`, positioning tokens, etc.) is internal — do not override.**
388
+
389
+ ### Button
390
+
391
+ | Property | Default | Intent |
392
+ | -------------------------------------------------------------------- | ---------------------------------------------- | -------------------------- |
393
+ | `--button-dark-bg` / `--button-dark-fg` / `--button-dark-line` | `--colour-link` / reverse fg / `--colour-link` | Dark button colours |
394
+ | `--button-accent-bg` / `--button-accent-fg` / `--button-accent-line` | accent / `--colour-foreground` / accent | Accent button colours |
395
+ | `--button-light-bg` / `--button-light-fg` / `--button-light-line` | transparent / link / transparent | Light button colours |
396
+ | `--button-accent-scheme` | `light` | Colour scheme for accent |
397
+ | `--button-font-size` | inherited | Button text size |
398
+ | `--button-gap` | `--spacing-s` | Gap between button content |
399
+ | `--button-min-height` | — | Minimum height |
400
+
401
+ ### Tag
402
+
403
+ | Property | Default | Intent |
404
+ | ------------------ | --------------------- | ---------------- |
405
+ | `--tag-background` | `--colour-background` | Tag fill |
406
+ | `--tag-foreground` | `--colour-foreground` | Tag text |
407
+ | `--tag-font-size` | `--font-size-xs` | Tag text size |
408
+ | `--tags-gap` | `--spacing-s` | Gap between tags |
409
+
410
+ ### Card
411
+
412
+ | Property | Default | Intent |
413
+ | ------------------ | --------- | --------------------------- |
414
+ | `--card-gap` | `--gap` | Gap between card regions |
415
+ | `--card-alignment` | `stretch` | Cross-axis alignment |
416
+ | `--large-card-gap` | `6rem` | Gap for large/feature cards |
417
+
418
+ ### Alert (GlobalAlert / InPageAlert)
419
+
420
+ | Property | Default | Intent |
421
+ | -------------------- | ------------------------ | ------------- |
422
+ | `--alert-background` | `--colour-primary-light` | Alert fill |
423
+ | `--alert-foreground` | `--colour-foreground` | Alert text |
424
+ | `--alert-scheme` | `light` | Colour scheme |
425
+
426
+ ### HeroBanner / HeroSearch
427
+
428
+ | Property | Default | Intent |
429
+ | --------------------- | ----------------- | ------------------- |
430
+ | `--hero-height` | `600px` | Minimum hero height |
431
+ | `--hero-columns` | `50% 50%` | Content/aside split |
432
+ | `--hero-align` | `center` | Vertical alignment |
433
+ | `--hero-image-radius` | `--border-radius` | Aside image radius |
434
+
435
+ ### Popover
436
+
437
+ | Property | Default | Intent |
438
+ | ---------------------- | --------------------- | ------------- |
439
+ | `--popover-padding` | `--spacing-xs` | Inner padding |
440
+ | `--popover-background` | `--colour-background` | Fill |
441
+ | `--popover-foreground` | `--colour-foreground` | Text |
442
+ | `--popover-radius` | `--border-radius` | Corner radius |
443
+ | `--popover-width` | `30ch` | Max width |
444
+
445
+ ### Section
446
+
447
+ | Property | Default | Intent |
448
+ | -------------------------------------------------------------- | ------------- | --------------------------------- |
449
+ | `--section-s` / `--section-m` / `--section-l` / `--section-xl` | spacing scale | Per-size section padding override |
450
+
451
+ ### Lines & borders (global)
452
+
453
+ Cross-cutting tokens used by borders, dividers, underlines, and focus outlines across many components (forms, buttons, tags, popover, etc.). Scope them to a context class to restyle lines in bulk, or override per-component.
454
+
455
+ | Property | Default (per component) | Intent |
456
+ | --------------- | ---------------------------------------- | ----------------------- |
457
+ | `--line-width` | `2px` (forms/buttons), `1px` (tags/etc.) | Border / line thickness |
458
+ | `--line-colour` | `--colour-border` (varies per component) | Border / line colour |
459
+
460
+ > Global tokens (`--colour-*`, `--font-size-*`, `--spacing-*`, `--gap*`, `--border-radius*`, `--box-shadow`, breakpoints) documented in [Design Tokens](#design-tokens) above are also public and overridable.
461
+
462
+ ---
463
+
464
+ ## Component Modifiers (from `@pnx-mixtape/ids-shape`)
465
+
466
+ > Modifier enums live in [`@pnx-mixtape/ids-shape`](https://www.npmjs.com/package/@pnx-mixtape/ids-shape).
467
+ > Full API reference: [TypeDoc-generated docs](https://unpkg.com/@pnx-mixtape/ids-shape/docs/index.html)
468
+
469
+ → See individual README.md files (eg. src/Atom/Button/README.md) for full modifier reference, React props, and CSS custom property overrides.
470
+
471
+ ---
472
+
473
+ ## Component Inventory
474
+
475
+ > This lists components by name with descriptions. For the exhaustive list of every CSS **class**, see [Canonical class inventory](#canonical-class-inventory) above.
476
+
477
+ ### Atoms (`src/Atom/`)
478
+
479
+ Smallest, single-purpose elements. Always use these as building blocks; never reproduce their styles.
480
+
481
+ | Component | Description |
482
+ | ---------------- | --------------------------------------------------------------- |
483
+ | `Background` | Coloured background regions with scheme switching |
484
+ | `Blockquote` | Styled `<blockquote>` for pull quotes |
485
+ | `Button` | All button and button-link variants |
486
+ | `DefinitionList` | Styled `<dl>` for key/value pairs |
487
+ | `Heading` | Typographic headings (h1–h6) with size/weight modifiers |
488
+ | `Icon` | SVG icon via CSS mask-image, sized with `--icon-size` |
489
+ | `Image` | Responsive image wrapper with ratio control |
490
+ | `InlineSvg` | Inline SVG component |
491
+ | `Link` | Base anchor with hover/focus styles |
492
+ | `LinkedImage` | Image wrapped in a link |
493
+ | `List` | Styled `<ul>`/`<ol>` with notes, references, and stats variants |
494
+ | `Media` | Generic media container (images, video) |
495
+ | `Spacing` | Whitespace utility component |
496
+ | `Table` | Accessible, responsive table |
497
+ | `Text` | Body text wrapper |
498
+ | `Video` | Video embed with aspect ratio |
499
+
500
+ ### Components (`src/Component/`)
501
+
502
+ Composed from Atoms. Have their own interaction behaviour.
503
+
504
+ | Component | Description |
505
+ | ------------------- | -------------------------------------------------------------------------------------------------------------------- |
506
+ | `Accordion` | Collapsible content panels (Web Component: `<mx-accordion>`) |
507
+ | `BackToTop` | Trigger that appears after a scroll threshold and jumps back to a target element (Web Component: `<mx-back-to-top>`) |
508
+ | `Breadcrumb` | Hierarchical navigation trail |
509
+ | `Callout` | Highlighted aside/tip block |
510
+ | `Card` | Content card with image, title, body, and actions |
511
+ | `Carousel` | Scrollable item carousel |
512
+ | `ContentBlock` | Rich text content region |
513
+ | `CookieConsent` | Site-wide cookie consent banner, fixed to viewport bottom |
514
+ | `Dialog` | Modal dialog (Web Component) |
515
+ | `DropMenu` | Dropdown navigation menu |
516
+ | `Filters` | Filter controls for listing pages |
517
+ | `Gallery` | Image preview that opens a fullscreen carousel modal |
518
+ | `GlobalAlert` | Site-wide dismissible alert banner |
519
+ | `HeroBanner` | Full-width hero with image and headline |
520
+ | `HeroSearch` | Hero with integrated search input |
521
+ | `InPageAlert` | Inline status alert (info/success/warning/error) |
522
+ | `InPageNavigation` | Anchor-link navigation for long pages |
523
+ | `LinkList` | Vertical or horizontal list of links |
524
+ | `ListItem` | Single item within a list context |
525
+ | `Navigation` | Primary site navigation |
526
+ | `Pagination` | Page navigation controls |
527
+ | `Popover` | Floating contextual content panel |
528
+ | `ProgressIndicator` | Horizontal step-progress tracker for multi-step forms/wizards |
529
+ | `ResultsBar` | Shows result count and sort controls |
530
+ | `SideNavigation` | Secondary vertical navigation |
531
+ | `SocialLinks` | Links to social media profiles |
532
+ | `SocialShare` | Share-to-social buttons |
533
+ | `Steps` | Numbered step indicator |
534
+ | `Sticky` | Sticky-positioned wrapper |
535
+ | `Tabs` | Tab panel navigation |
536
+ | `Tag` | Label/badge for categorisation |
537
+ | `Translate` | Language switcher that drives Google's Website Translator widget, built on DropMenu |
538
+ | `UtilityList` | Utility link bar |
539
+
540
+ ### Forms (`src/Form/`)
541
+
542
+ | Component | Description |
543
+ | -------------- | -------------------------------------------------------------------------------------------- |
544
+ | `Autocomplete` | Editable combobox with a suggestion listbox |
545
+ | `Checkbox` | Styled checkbox input |
546
+ | `CheckboxCard` | Card-style checkbox with a larger tap target |
547
+ | `Description` | Helper/hint text for form fields |
548
+ | `FeedbackForm` | Yes/no feedback control that reveals a comment field, with a submit contract for any backend |
549
+ | `Form` | Form wrapper with spacing |
550
+ | `FormItem` | Field group (label + input + description + error) |
551
+ | `Label` | Form field label |
552
+ | `Radio` | Styled radio input |
553
+ | `RadioCard` | Card-style radio with a larger tap target |
554
+ | `Search` | Search input with button |
555
+ | `Select` | Styled `<select>` dropdown |
556
+ | `Textarea` | Styled `<textarea>` |
557
+ | `TextInput` | Styled text `<input>` |
558
+
559
+ ### Layout (`src/Layout/`)
560
+
561
+ | Component | Description |
562
+ | ---------- | ------------------------- |
563
+ | `Footer` | Site footer |
564
+ | `Grid` | CSS grid layout wrapper |
565
+ | `Header` | Site header |
566
+ | `Masthead` | Top-of-page branding bar |
567
+ | `Page` | Full page layout wrapper |
568
+ | `Section` | Page section with spacing |
569
+ | `Sidebar` | Two-column sidebar layout |
570
+
571
+ ### Utilities (`src/Utility/`)
572
+
573
+ Utility classes, hooks, and context providers. Includes print styles, layout utilities, Drupal-specific helpers, and React hooks.
574
+
575
+ ---
576
+
577
+ ## React & Web Component Usage
578
+
579
+ → See [`docs/ComponentArchitecture.md`](./docs/ComponentArchitecture.md) for full patterns.
580
+
581
+ React components are exported from `src/react.ts`. Web Components auto-register on import and use the `mx-` custom element prefix (e.g. `<mx-accordion>`).
582
+
583
+ ---
584
+
585
+ ## Accessibility
586
+
587
+ → WCAG 2.2 AA compliant. See [`docs/CSSGuidelines.md`](./docs/CSSGuidelines.md) for media query hooks (`--use-motion`, `--high-contrast`, etc.) and [`docs/ComponentArchitecture.md`](./docs/ComponentArchitecture.md) for ARIA patterns.
588
+
589
+ ---
590
+
591
+ ## Overriding Styles
592
+
593
+ → See [`docs/CSSGuidelines.md`](./docs/CSSGuidelines.md) for the full override guide.
594
+
595
+ **Short version:** prefer CSS custom property overrides scoped to a context class. Unlayered CSS wins globally without needing `!important`.
package/README.md CHANGED
@@ -206,7 +206,7 @@ import { Button } from "@pnx-mixtape/mxds/compiled/react"
206
206
  - ✅ **Framework-agnostic** - Web Components, React, Twig templates
207
207
  - ✅ **Design Tokens** - Customizable theming via tokens
208
208
  - ✅ **CSS Layers** - Easy overrides without specificity wars
209
- - ✅ **Accessible** - WCAG 2.0 AA compliant
209
+ - ✅ **Accessible** - WCAG 2.2 AA compliant
210
210
  - ✅ **Responsive** - Mobile-first approach
211
211
  - ✅ **Modern CSS** - Logical properties, custom media, container queries
212
212
  - ✅ **TypeScript** - Full type support
@@ -222,8 +222,7 @@ Mixtape uses [@layers](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer)
222
222
  @import "@pnx-mixtape/mxds/src/Atom/base.css";
223
223
 
224
224
  /* Or manually define layer order */
225
- @layer design-system.defaults, design-system.atoms, design-system.layout,
226
- design-system.components, design-system.utilities;
225
+ @layer design-system.defaults, design-system.atoms, design-system.layout, design-system.components, design-system.utilities;
227
226
 
228
227
  /* Your unlayered CSS automatically overrides design system */
229
228
  .mx-button {