@pnx-mixtape/mxds 0.1.0-rc.3 → 0.1.0-rc.5

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 (230) hide show
  1. package/.claude/skills/create-mxds-component/SKILL.md +77 -0
  2. package/DESIGN.md +595 -0
  3. package/README.md +1 -2
  4. package/dist/build/accordion.css +1 -1
  5. package/dist/build/accordion.entry.js +2 -1
  6. package/dist/build/autocomplete.entry.js +1 -1
  7. package/dist/build/back-to-top.css +1 -0
  8. package/dist/build/back-to-top.entry.js +1 -0
  9. package/dist/build/base.css +1 -1
  10. package/dist/build/button.css +1 -1
  11. package/dist/build/card.css +1 -1
  12. package/dist/build/carousel.css +1 -1
  13. package/dist/build/chunks/Accordion-D2wp8hBG.js +44 -0
  14. package/dist/build/chunks/AccordionGroup-BYtoAFxg.js +47 -0
  15. package/dist/build/chunks/AccordionMobile-D3sTeiM5.js +26 -0
  16. package/dist/build/chunks/Autocomplete-kRo8RNbC.js +135 -0
  17. package/dist/build/chunks/BackToTop-4M-Wl7z3.js +64 -0
  18. package/dist/build/chunks/ClosableAlert-yy84gae6.js +55 -0
  19. package/dist/build/chunks/CookieConsent-wd8gQ2Oe.js +18 -0
  20. package/dist/build/chunks/Dialog-DWoXW-7Z.js +48 -0
  21. package/dist/build/chunks/DropMenu-CSTZq0Zt.js +68 -0
  22. package/dist/build/chunks/FeedbackForm-BochXEDx.js +64 -0
  23. package/dist/build/chunks/Gallery-Rkfv7Mbb.js +165 -0
  24. package/dist/build/chunks/GlobalToggle-CzlkpLpc.js +82 -0
  25. package/dist/build/chunks/InPageNavigation-D1Kk-rCm.js +86 -0
  26. package/dist/build/chunks/Navigation-CDQnN61h.js +147 -0
  27. package/dist/build/chunks/Popover-CiTAftNU.js +30 -0
  28. package/dist/build/chunks/Sticky-DoVndENm.js +51 -0
  29. package/dist/build/chunks/Tabs-BDlxCDNh.js +160 -0
  30. package/dist/build/chunks/Translate-bmM38j6z.js +46 -0
  31. package/dist/build/chunks/cookie-compliance-CG6x-TcV.js +119 -0
  32. package/dist/build/chunks/enums-BrHxPZZ_.js +36 -0
  33. package/dist/build/chunks/polyfills-D-qh1a_2.js +33 -0
  34. package/dist/build/chunks/utilities-Dd-08SW6.js +255 -0
  35. package/dist/build/constants.css +1 -1
  36. package/dist/build/content-block.css +1 -1
  37. package/dist/build/cookie-consent.css +1 -1
  38. package/dist/build/cookie-consent.entry.js +1 -1
  39. package/dist/build/dialog.css +1 -1
  40. package/dist/build/dialog.entry.js +1 -1
  41. package/dist/build/drop-menu.entry.js +1 -1
  42. package/dist/build/elements.js +147 -1
  43. package/dist/build/feedback-form.css +1 -0
  44. package/dist/build/feedback-form.entry.js +1 -0
  45. package/dist/build/filters.entry.js +145 -1
  46. package/dist/build/form.css +1 -1
  47. package/dist/build/gallery.entry.js +1 -1
  48. package/dist/build/global-alert.css +1 -1
  49. package/dist/build/global-alert.entry.js +1 -1
  50. package/dist/build/grid.css +1 -1
  51. package/dist/build/header.css +1 -1
  52. package/dist/build/header.entry.js +1 -1
  53. package/dist/build/icon.css +1 -1
  54. package/dist/build/in-page-navigation.entry.js +1 -1
  55. package/dist/build/navigation.css +1 -1
  56. package/dist/build/navigation.entry.js +1 -1
  57. package/dist/build/pagination.css +1 -1
  58. package/dist/build/popover.css +1 -1
  59. package/dist/build/popover.entry.js +1 -1
  60. package/dist/build/react.js +2270 -1
  61. package/dist/build/sticky.entry.js +1 -1
  62. package/dist/build/tabs.css +1 -1
  63. package/dist/build/tabs.entry.js +1 -1
  64. package/dist/build/translate.css +1 -0
  65. package/dist/build/translate.entry.js +1 -0
  66. package/dist/build/utility-list.entry.js +53 -1
  67. package/dist/types/Component/BackToTop/BackToTop.d.ts +20 -0
  68. package/dist/types/Component/BackToTop/BackToTop.d.ts.map +1 -0
  69. package/dist/types/Component/BackToTop/Elements/BackToTop.d.ts +27 -0
  70. package/dist/types/Component/BackToTop/Elements/BackToTop.d.ts.map +1 -0
  71. package/dist/types/Component/BackToTop/back-to-top.entry.d.ts +2 -0
  72. package/dist/types/Component/BackToTop/back-to-top.entry.d.ts.map +1 -0
  73. package/dist/types/Component/DropMenu/DropMenu.d.ts +2 -1
  74. package/dist/types/Component/DropMenu/DropMenu.d.ts.map +1 -1
  75. package/dist/types/Component/Tabs/Components/TabDropMenu.d.ts.map +1 -1
  76. package/dist/types/Component/Tabs/Elements/Tabs.d.ts.map +1 -1
  77. package/dist/types/Component/Translate/Elements/Translate.d.ts +23 -0
  78. package/dist/types/Component/Translate/Elements/Translate.d.ts.map +1 -0
  79. package/dist/types/Component/Translate/Translate.d.ts +37 -0
  80. package/dist/types/Component/Translate/Translate.d.ts.map +1 -0
  81. package/dist/types/Component/Translate/languages.d.ts +11 -0
  82. package/dist/types/Component/Translate/languages.d.ts.map +1 -0
  83. package/dist/types/Component/Translate/translate.entry.d.ts +2 -0
  84. package/dist/types/Component/Translate/translate.entry.d.ts.map +1 -0
  85. package/dist/types/Form/FeedbackForm/Elements/FeedbackForm.d.ts +37 -0
  86. package/dist/types/Form/FeedbackForm/Elements/FeedbackForm.d.ts.map +1 -0
  87. package/dist/types/Form/FeedbackForm/FeedbackForm.d.ts +36 -0
  88. package/dist/types/Form/FeedbackForm/FeedbackForm.d.ts.map +1 -0
  89. package/dist/types/Form/FeedbackForm/feedback-form.entry.d.ts +2 -0
  90. package/dist/types/Form/FeedbackForm/feedback-form.entry.d.ts.map +1 -0
  91. package/dist/types/Utility/Elements/google-translate-widget.d.ts +91 -0
  92. package/dist/types/Utility/Elements/google-translate-widget.d.ts.map +1 -0
  93. package/dist/types/Utility/utilities.d.ts +2 -0
  94. package/dist/types/Utility/utilities.d.ts.map +1 -1
  95. package/dist/types/elements.d.ts +3 -0
  96. package/dist/types/elements.d.ts.map +1 -1
  97. package/dist/types/enums.d.ts +3 -1
  98. package/dist/types/enums.d.ts.map +1 -1
  99. package/dist/types/react.d.ts +3 -0
  100. package/dist/types/react.d.ts.map +1 -1
  101. package/docs/API.md +1215 -0
  102. package/docs/CSSGuidelines.md +891 -0
  103. package/docs/CodeQuality.md +940 -0
  104. package/docs/ComponentArchitecture.md +714 -0
  105. package/docs/Contributing.md +626 -0
  106. package/docs/MemoryManagement.md +598 -0
  107. package/docs/Migrations.md +6 -0
  108. package/docs/README.md +100 -0
  109. package/docs/Security.md +444 -0
  110. package/docs/Testing.md +739 -0
  111. package/docs/Troubleshooting.md +674 -0
  112. package/package.json +6 -3
  113. package/src/Atom/Button/Button.tsx +1 -1
  114. package/src/Atom/Button/__snapshots__/Button.stories.tsx.snap +2 -2
  115. package/src/Atom/Button/_buttons.css +1 -0
  116. package/src/Atom/Icon/README.md +1 -1
  117. package/src/Atom/Icon/_icon.css +1 -0
  118. package/src/Atom/Icon/images/thumb.svg +1 -0
  119. package/src/Atom/Media/__snapshots__/Media.stories.ts.snap +4 -9
  120. package/src/Atom/Media/media.twig +4 -5
  121. package/src/Atom/_generic.css +0 -10
  122. package/src/Component/Accordion/accordion.css +3 -1
  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/Carousel/carousel.css +1 -1
  140. package/src/Component/ContentBlock/Components/ContentBlockMedia.tsx +1 -1
  141. package/src/Component/ContentBlock/content-block.css +1 -1
  142. package/src/Component/CookieConsent/cookie-consent.css +3 -0
  143. package/src/Component/Dialog/dialog.css +5 -2
  144. package/src/Component/DropMenu/DropMenu.stories.ts +21 -2
  145. package/src/Component/DropMenu/DropMenu.tsx +14 -4
  146. package/src/Component/DropMenu/__snapshots__/DropMenu.stories.ts.snap +3 -3
  147. package/src/Component/DropMenu/__snapshots__/DropMenu.stories.tsx.snap +2 -2
  148. package/src/Component/DropMenu/drop-menu.twig +7 -1
  149. package/src/Component/GlobalAlert/global-alert.css +3 -0
  150. package/src/Component/HeroBanner/__snapshots__/HeroBanner.stories.tsx.snap +1 -1
  151. package/src/Component/InPageNavigation/__snapshots__/InPageNavigation.stories.ts.snap +48 -13
  152. package/src/Component/InPageNavigation/in-page-navigation.twig +4 -6
  153. package/src/Component/ListItem/Components/ListItemMedia.tsx +1 -1
  154. package/src/Component/Navigation/_navigation-collapsible.css +3 -1
  155. package/src/Component/Navigation/_navigation-dropdown.css +3 -1
  156. package/src/Component/Pagination/Pagination.stories.ts +57 -27
  157. package/src/Component/Pagination/pagination.css +16 -7
  158. package/src/Component/Popover/__snapshots__/Popover.stories.tsx.snap +3 -3
  159. package/src/Component/Popover/popover.css +3 -1
  160. package/src/Component/Tabs/Components/TabDropMenu.tsx +7 -1
  161. package/src/Component/Tabs/Elements/Tabs.ts +13 -3
  162. package/src/Component/Tabs/Tabs.stories.ts +33 -12
  163. package/src/Component/Tabs/Tabs.stories.tsx +28 -14
  164. package/src/Component/Tabs/__snapshots__/Tabs.stories.ts.snap +3 -3
  165. package/src/Component/Tabs/__snapshots__/Tabs.stories.tsx.snap +2 -2
  166. package/src/Component/Tabs/tabs.css +4 -5
  167. package/src/Component/Translate/Elements/Translate.ts +76 -0
  168. package/src/Component/Translate/README.md +283 -0
  169. package/src/Component/Translate/Translate.stories.ts +87 -0
  170. package/src/Component/Translate/Translate.stories.tsx +77 -0
  171. package/src/Component/Translate/Translate.tsx +213 -0
  172. package/src/Component/Translate/__snapshots__/Translate.stories.ts.snap +18 -0
  173. package/src/Component/Translate/__snapshots__/Translate.stories.tsx.snap +3 -0
  174. package/src/Component/Translate/languages.ts +39 -0
  175. package/src/Component/Translate/translate.css +62 -0
  176. package/src/Component/Translate/translate.entry.js +1 -0
  177. package/src/Component/Translate/translate.twig +44 -0
  178. package/src/Form/Autocomplete/Autocomplete.stories.tsx +2 -1
  179. package/src/Form/FeedbackForm/Elements/FeedbackForm.ts +122 -0
  180. package/src/Form/FeedbackForm/FeedbackForm.stories.ts +99 -0
  181. package/src/Form/FeedbackForm/FeedbackForm.stories.tsx +73 -0
  182. package/src/Form/FeedbackForm/FeedbackForm.tsx +196 -0
  183. package/src/Form/FeedbackForm/README.md +233 -0
  184. package/src/Form/FeedbackForm/__snapshots__/FeedbackForm.stories.ts.snap +125 -0
  185. package/src/Form/FeedbackForm/__snapshots__/FeedbackForm.stories.tsx.snap +5 -0
  186. package/src/Form/FeedbackForm/feedback-form.css +74 -0
  187. package/src/Form/FeedbackForm/feedback-form.entry.js +1 -0
  188. package/src/Form/FeedbackForm/feedback-form.twig +80 -0
  189. package/src/Form/form.css +5 -3
  190. package/src/Layout/Grid/Grid.stories.ts +1 -0
  191. package/src/Layout/Grid/Grid.stories.tsx +26 -0
  192. package/src/Layout/Grid/__snapshots__/Grid.stories.tsx.snap +2 -0
  193. package/src/Layout/Grid/grid.css +12 -0
  194. package/src/Layout/Header/Components/GlobalToggle.tsx +1 -1
  195. package/src/Layout/Header/Header.stories.ts +53 -48
  196. package/src/Layout/Header/Header.stories.tsx +35 -22
  197. package/src/Layout/Header/Header.tsx +2 -2
  198. package/src/Layout/Header/__snapshots__/Header.stories.ts.snap +14 -10
  199. package/src/Layout/Header/__snapshots__/Header.stories.tsx.snap +2 -2
  200. package/src/Layout/Header/_header.css +4 -2
  201. package/src/Layout/Header/_toggles.css +9 -6
  202. package/src/Layout/Page/__snapshots__/Page.stories.tsx.snap +1 -1
  203. package/src/Utility/Elements/google-translate-widget.ts +293 -0
  204. package/src/Utility/_mixins.css +35 -13
  205. package/src/Utility/global.d.ts +4 -0
  206. package/src/Utility/utilities.ts +2 -0
  207. package/src/_custom-media.css +2 -2
  208. package/src/constants.css +3 -13
  209. package/src/elements.ts +3 -0
  210. package/src/enums.ts +2 -0
  211. package/src/react.ts +3 -0
  212. package/dist/build/chunks/Accordion-GN0sME4W.js +0 -1
  213. package/dist/build/chunks/AccordionGroup-Bzqp5__q.js +0 -1
  214. package/dist/build/chunks/AccordionMobile-DG5jSe8Q.js +0 -1
  215. package/dist/build/chunks/Autocomplete-B4RtkAyh.js +0 -1
  216. package/dist/build/chunks/ClosableAlert-DEhj8Nxm.js +0 -1
  217. package/dist/build/chunks/CookieConsent-BkCMRVST.js +0 -1
  218. package/dist/build/chunks/Dialog-Haahn-Yn.js +0 -1
  219. package/dist/build/chunks/DropMenu-1baQc8Yc.js +0 -1
  220. package/dist/build/chunks/Gallery-D8NGXy2Q.js +0 -1
  221. package/dist/build/chunks/GlobalToggle-B52fdBQu.js +0 -1
  222. package/dist/build/chunks/InPageNavigation-Dyn2TR-N.js +0 -1
  223. package/dist/build/chunks/Navigation-hOrfLq7h.js +0 -1
  224. package/dist/build/chunks/Popover-Cxg-s5Jn.js +0 -1
  225. package/dist/build/chunks/Sticky-BGCuuEJK.js +0 -1
  226. package/dist/build/chunks/Tabs-DYy1YTdU.js +0 -15
  227. package/dist/build/chunks/cookie-compliance-Bbm-0vpj.js +0 -1
  228. package/dist/build/chunks/enums-DLV_1NAf.js +0 -1
  229. package/dist/build/chunks/polyfills-C7pRt54M.js +0 -1
  230. package/dist/build/chunks/utilities-_Bq3TxAQ.js +0 -1
@@ -0,0 +1,891 @@
1
+ # CSS Guidelines
2
+
3
+ CSS/Styling conventions for the Mixtape Design System.
4
+
5
+ ## Table of Contents
6
+
7
+ - [PostCSS Pipeline](#postcss-pipeline)
8
+ - [BEM Naming](#bem-naming)
9
+ - [File Organization](#file-organization)
10
+ - [Custom Media](#custom-media)
11
+ - [Design Tokens](#design-tokens)
12
+ - [Custom Property Fallbacks](#custom-property-fallbacks)
13
+ - [Color Scheme (light-dark)](#color-scheme-light-dark)
14
+ - [Logical Properties](#logical-properties)
15
+ - [Cascade Layers](#cascade-layers)
16
+
17
+ ---
18
+
19
+ ## PostCSS Pipeline
20
+
21
+ The build process transforms non-standard CSS syntax into valid browser CSS. Understanding these transforms is essential for reading and writing component styles.
22
+
23
+ ### Plugins & What They Do
24
+
25
+ | Plugin | Syntax it handles | Output |
26
+ |---|---|---|
27
+ | `postcss-design-tokens` | `token("spacing.m")` | CSS custom property value |
28
+ | `@csstools/postcss-global-data` | `@media (--medium-up)` | Custom media available globally |
29
+ | `postcss-mixins` | `@define-mixin`, `@add-mixin` | Inline CSS |
30
+ | `postcss-preset-env` (stage 0) | Modern CSS syntax | Cross-browser CSS |
31
+ | `postcss-prepend-layer` | (automatic) | Wraps all CSS in `@layer design-system.*` |
32
+
33
+ ### token() Function
34
+
35
+ The `token()` function is provided by `postcss-design-tokens` and resolves values from `src/tokens.js` at build time:
36
+
37
+ ```css
38
+ /* Source */
39
+ @custom-media --medium-up (width >= token("breakpoint.m"));
40
+ padding: token("spacing.m");
41
+
42
+ /* Compiled output */
43
+ @custom-media --medium-up (width >= 900px);
44
+ padding: 1rem;
45
+ ```
46
+
47
+ Token paths mirror the structure of `src/tokens.js`. See the [Design Tokens](#design-tokens) section for available categories.
48
+
49
+ ### SVG Images
50
+
51
+ SVG files are referenced with a plain `url()` — Vite inlines them as a data URI (or hashes them as an asset) at build time:
52
+
53
+ ```css
54
+ background-image: url("../images/icon-close.svg");
55
+ ```
56
+
57
+ ### Custom Media Queries
58
+
59
+ Custom media queries (defined in `src/_custom-media.css`) use `@csstools/postcss-global-data` to make them available to every file without needing an explicit `@import`. At build time they compile to standard `@media` queries:
60
+
61
+ ```css
62
+ /* Source */
63
+ @media (--medium-up) { ... }
64
+
65
+ /* Compiled output */
66
+ @media (width >= 900px) { ... }
67
+ ```
68
+
69
+ The full list of available custom media names is in the [Custom Media](#custom-media) section.
70
+
71
+ ---
72
+
73
+ ## BEM Naming
74
+
75
+ ### Structure
76
+
77
+ Block Element Modifier (BEM) methodology is **strictly enforced** by Stylelint.
78
+
79
+ ```css
80
+ /* Block: Component/standalone entity */
81
+ .mx-card {
82
+ }
83
+
84
+ /* Element: Part of block */
85
+ .mx-card__header {
86
+ }
87
+ .mx-card__body {
88
+ }
89
+ .mx-card__footer {
90
+ }
91
+
92
+ /* Modifier: Variation of block or element */
93
+ .mx-card--reversed {
94
+ }
95
+ .mx-card--block {
96
+ }
97
+ .mx-card__header--large {
98
+ }
99
+ ```
100
+
101
+ ### Naming Rules
102
+
103
+ ✅ **Allowed:**
104
+
105
+ ```css
106
+ .mx-component /* Block */
107
+ .mx-component__element /* Element */
108
+ .mx-component--modifier /* Modifier */
109
+ .mx-component__element--modifier /* Element with modifier */
110
+ ```
111
+
112
+ ❌ **Not Allowed:**
113
+
114
+ ```css
115
+ .mx-component-element /* Wrong separator */
116
+ .mx-component.modifier /* Not BEM */
117
+ .mx-componentElement /* camelCase not allowed */
118
+ .component /* Missing mx- prefix */
119
+ ```
120
+
121
+ ### Prefix Convention
122
+
123
+ All design system classes use the `mx-` prefix:
124
+
125
+ - **mx** = Mixtape
126
+ - Prevents conflicts with consumer styles
127
+ - Clear namespace for design system components
128
+
129
+ ### Nesting with &
130
+
131
+ ```css
132
+ /* ✅ GOOD - Use & for nesting, reduce specificity */
133
+ .mx-card {
134
+ display: flex;
135
+ }
136
+
137
+ .mx-card--reversed {
138
+ flex-direction: row-reverse;
139
+ }
140
+
141
+ .mx-card__media {
142
+ & img {
143
+ aspect-ratio: var(--ratio);
144
+ }
145
+ }
146
+ ```
147
+
148
+ ### Stylelint Enforcement
149
+
150
+ Your `.stylelintrc.json` enforces BEM:
151
+
152
+ ```javascript
153
+ "selector-class-pattern": [
154
+ "^([a-z])([a-z0-9]+)((-[a-z0-9]+)+)?(((--)?(__)?)([a-z0-9]+)((-[a-z0-9]+)+)?)?(((--)?(__)?)([a-z0-9]+)((-[a-z0-9]+)+)?)?$",
155
+ {
156
+ message: "Expected class selector to be BEM selector matching either .block__element or .block--modifier"
157
+ }
158
+ ]
159
+ ```
160
+
161
+ ---
162
+
163
+ ## File Organization
164
+
165
+ ### Component Structure
166
+
167
+ Components provide multiple CSS files for flexibility:
168
+
169
+ ```
170
+ Component/
171
+ ├── component.css # Public API - imports all partials
172
+ ├── _component-base.css # Base styles (partial)
173
+ ├── _component-modifiers.css # Modifier variations (partial)
174
+ ```
175
+
176
+ #### Example: Button component
177
+
178
+ ```
179
+ Button/
180
+ ├── button.css # Full button styles (imports both partials)
181
+ ├── _buttons.css # Base button styles
182
+ └── _buttons-styles.css # Button style variations
183
+ ```
184
+
185
+ ### Import Patterns
186
+
187
+ You can import the **full component** or **individual partials** depending on your needs:
188
+
189
+ #### Option 1: Import Full Component (Recommended)
190
+
191
+ ```css
192
+ /* Gets all button styles */
193
+ @import "@pnx-mixtape/mxds/src/Atom/Button/button.css";
194
+ ```
195
+
196
+ This is the simplest approach and includes all styles for the component.
197
+
198
+ #### Option 2: Import Partials (Granular Control)
199
+
200
+ ```css
201
+ /* Import only what you need */
202
+ @import "@pnx-mixtape/mxds/src/Atom/Button/_buttons.css";
203
+ @import "@pnx-mixtape/mxds/src/Atom/Button/_buttons-styles.css";
204
+
205
+ /* Then override specific styles */
206
+ .mx-button--primary {
207
+ --button-background: var(--colour-brand-primary);
208
+ }
209
+ ```
210
+
211
+ Use this when you:
212
+
213
+ - Only need specific parts of a component
214
+ - Want to customize before other styles load
215
+ - Need finer control over what's included
216
+
217
+ ### Partial Files Convention
218
+
219
+ Files prefixed with underscore are **partials**:
220
+
221
+ - `_component-base.css` - Internal partial, can be imported separately
222
+ - `component.css` - Public API, imports all partials
223
+
224
+ **Why use partials?**
225
+
226
+ - Modular - Import only what you need
227
+ - Customizable - Override between partial imports
228
+ - Flexible - Mix and match for your use case
229
+
230
+ ---
231
+
232
+ ## Custom Media
233
+
234
+ ### Always Import
235
+
236
+ This is only required if you're not using something like [@csstools/postcss-global-data](https://www.npmjs.com/package/@csstools/postcss-global-data).
237
+
238
+ Import custom media in every CSS file that uses them:
239
+
240
+ ```css
241
+ /* MUST be first import in every file */
242
+ @import "../../_custom-media.css";
243
+
244
+ .mx-component {
245
+ display: block;
246
+
247
+ @media (--medium-up) {
248
+ display: flex;
249
+ }
250
+ }
251
+ ```
252
+
253
+ ### Available Breakpoints
254
+
255
+ ```css
256
+ /* Mobile first breakpoints */
257
+ @media (--x-small-up) /* >= 375px */
258
+ @media (--small-up) /* >= 600px */
259
+ @media (--medium-up) /* >= 900px */
260
+ @media (--large-up) /* >= 1200px */
261
+ @media (--x-large-up) /* >= 1800px */
262
+
263
+ /* Desktop first breakpoints */
264
+ @media (--x-small-down) /* < 375px */
265
+ @media (--small-down) /* < 600px */
266
+ @media (--medium-down) /* < 900px */
267
+ @media (--large-down) /* < 1200px */
268
+ @media (--x-large-down) /* < 1800px */
269
+
270
+ /* Between breakpoints */
271
+ @media (--x-small-to-small) /* 375px to 600px */
272
+ @media (--small-to-medium) /* 600px to 900px */
273
+ @media (--medium-to-large) /* 900px to 1200px */
274
+ @media (--large-to-x-large) /* 1200px to 1800px */
275
+
276
+ /* Special breakpoints */
277
+ @media (--global-nav-up) /* >= 720px - Navigation breakpoint */
278
+ @media (--global-nav-down) /* < 720px */
279
+ @media (--collapse-card-up) /* >= 400px - Card collapse */
280
+ @media (--collapse-card-down) /* < 400px */
281
+
282
+ /* Interaction */
283
+ @media (--touch) /* Touch devices (no hover) */
284
+ @media (--mouse) /* Mouse devices (has hover) */
285
+ ```
286
+
287
+ ### Mobile First Approach
288
+
289
+ ```css
290
+ /* ✅ GOOD - Mobile first */
291
+ .mx-component {
292
+ /* Mobile styles (default) */
293
+ display: block;
294
+ padding: 1rem;
295
+
296
+ /* Tablet */
297
+ @media (--medium-up) {
298
+ display: flex;
299
+ padding: 2rem;
300
+ }
301
+
302
+ /* Desktop */
303
+ @media (--large-up) {
304
+ padding: 3rem;
305
+ }
306
+ }
307
+
308
+ /* ❌ BAD - Desktop first */
309
+ .mx-component {
310
+ display: flex; /* Desktop default */
311
+
312
+ @media (--medium-down) {
313
+ display: block; /* Override for mobile */
314
+ }
315
+ }
316
+ ```
317
+
318
+ ---
319
+
320
+ ## Design Tokens
321
+
322
+ ### How Tokens Work
323
+
324
+ Design tokens in `src/tokens.js` are used during the build process to generate `src/constants.css`, which defines all CSS custom properties. Load this file once at the page level to make all custom properties available globally. Components can then use these custom properties for consistent styling.
325
+
326
+ **Workflow:**
327
+
328
+ 1. Define/override tokens in `src/tokens.js`
329
+ 2. Build process generates `src/constants.css` with CSS custom properties
330
+ 3. Components use the custom properties
331
+
332
+ ### Using Custom Properties
333
+
334
+ ```css
335
+ .mx-component {
336
+ /* Colors */
337
+ color: var(--colour-foreground);
338
+ background: var(--colour-background);
339
+
340
+ /* Spacing */
341
+ padding: var(--spacing-m);
342
+ margin-block-start: var(--spacing-l);
343
+
344
+ /* Typography */
345
+ font-size: var(--font-size-m);
346
+ line-height: var(--line-height);
347
+
348
+ /* Layout */
349
+ max-inline-size: var(--container-max-width);
350
+ gap: var(--spacing-s);
351
+
352
+ /* Borders */
353
+ border-radius: var(--border-radius);
354
+ }
355
+ ```
356
+
357
+ ### Available Token Categories
358
+
359
+ The `src/tokens.js` file defines tokens in these categories:
360
+
361
+ - `colour.*` - Colors (text, background, brand, etc.)
362
+ - `spacing.*` - Spacing scale (xxs, xs, s, m, l, xl, xxl)
363
+ - `font.*` - Typography (size, family, weight, lineHeight)
364
+ - `layout.*` - Layout values (measure, gutter, etc.)
365
+ - `radius.*` - Border radius (s, m, l)
366
+ - `border.*` - Border properties
367
+ - `breakpoint.*` - Breakpoint values
368
+ - `shadow.*` - Box shadows
369
+ - `transition.*` - Transition values
370
+
371
+ These are converted to CSS custom properties like:
372
+
373
+ - `colour.text.primary` → `--colour-text-primary`
374
+ - `spacing.m` → `--spacing-m`
375
+ - `font.size.body` → `--font-size-m`
376
+
377
+ ### Overriding Tokens
378
+
379
+ In your project, override tokens before the build process:
380
+
381
+ ```javascript
382
+ // project-tokens.js
383
+ import tokens from "@pnx-mixtape/mxds/tokens"
384
+
385
+ // Override existing tokens
386
+ tokens.colour.brand.primary = "rgb(0, 92, 250)"
387
+ tokens.spacing.m = "1.5rem"
388
+
389
+ // Add new tokens
390
+ tokens.colour.brand.tertiary = "rgb(100, 200, 50)"
391
+
392
+ export default tokens
393
+ ```
394
+
395
+ Then configure your build tool (Vite, Webpack, etc.) with [postcss-design-tokens](https://www.npmjs.com/package/postcss-design-tokens) to use your project tokens instead of the default ones.
396
+
397
+ The build process will generate custom properties based on your overridden tokens.
398
+
399
+ #### Swapping the type scale
400
+
401
+ Every `--font-size-*` (other than `--font-size-m`, which is the anchor) is derived from a single ratio via `pow()`, so swapping `font.size.ratio` reshapes the whole scale at once. The `global.typeScales` table exposes the eight standard musical scales — pick the named ratio rather than hard-coding a number:
402
+
403
+ ```javascript
404
+ import tokens, { global } from "@pnx-mixtape/mxds/tokens"
405
+
406
+ // Tighter UI-style scale (less display-y, denser)
407
+ tokens.font.size.ratio = global.typeScales.perfectFourth // 1.333
408
+ tokens.font.size.ratioSmall = global.typeScales.majorSecond // 1.125
409
+
410
+ // Or editorial / display-heavy
411
+ tokens.font.size.ratio = global.typeScales.goldenRatio // 1.618
412
+ ```
413
+
414
+ Available scales:
415
+
416
+ | Name | Ratio | Feel |
417
+ | ----------------- | ----- | -------------------------------------------- |
418
+ | `minorSecond` | 1.067 | Very tight — UI/dense data |
419
+ | `majorSecond` | 1.125 | Tight |
420
+ | `minorThird` | 1.2 | Compact (current mobile default) |
421
+ | `majorThird` | 1.25 | Balanced |
422
+ | `perfectFourth` | 1.333 | Generous body / UI hybrid |
423
+ | `augmentedFourth` | 1.414 | Display-leaning (current desktop default) |
424
+ | `perfectFifth` | 1.5 | Punchy display |
425
+ | `goldenRatio` | 1.618 | Editorial / magazine |
426
+
427
+ `ratio` controls the desktop scale; `ratioSmall` is applied automatically below the `--medium-down` breakpoint, so you can pick a more dramatic ratio for desktop and a tighter one for mobile without writing any media queries.
428
+
429
+ ### Generated Custom Properties
430
+
431
+ The `src/constants.css` file (generated from tokens by PostCSS) looks like this:
432
+
433
+ ```css
434
+ :root {
435
+ --colour-text-primary: rgb(0, 0, 0);
436
+ --colour-background-secondary: rgb(245, 245, 245);
437
+ --spacing-m: 1rem;
438
+ --font-size-m: 1rem;
439
+ /* ... many more custom properties ... */
440
+ }
441
+ ```
442
+
443
+ **Load this file once at the page level** - it defines all custom properties in `:root`, making them available globally to all components without duplication.
444
+
445
+ ---
446
+
447
+ ## Custom Property Fallbacks
448
+
449
+ ### Cascading Fallback Pattern
450
+
451
+ Components use a **cascading fallback pattern** with custom properties, allowing consumers to override values at different levels without modifying component CSS.
452
+
453
+ **Pattern:**
454
+
455
+ ```css
456
+ property: var(--override, var(--default));
457
+ ```
458
+
459
+ This creates an override point that consumers can set, falling back to the design system default if not set.
460
+
461
+ ### Example: Background Component
462
+
463
+ ```css
464
+ .mx-background--primary {
465
+ /* Allows consumer override, falls back to design system default */
466
+ background-color: var(--background, var(--colour-background));
467
+ color: var(--foreground, var(--colour-foreground));
468
+
469
+ /* Multiple fallback levels for flexibility */
470
+ --scheme: var(--primary-scheme, var(--colour-primary-scheme, var(--colour-scheme)));
471
+ }
472
+ ```
473
+
474
+ ### How It Works
475
+
476
+ **1. Component defines fallback chain:**
477
+
478
+ ```css
479
+ .mx-card {
480
+ padding: var(--card-padding, var(--spacing-m));
481
+ background: var(--card-background, var(--colour-background));
482
+ border: var(--line-width, 2px) solid var(--line-colour, var(--colour-border));
483
+ }
484
+ ```
485
+
486
+ **2. Consumer overrides at any level:**
487
+
488
+ ```css
489
+ /* Override globally */
490
+ :root {
491
+ --line-colour: blue; /* Changes all components using --line-colour */
492
+ }
493
+
494
+ /* Override specific component */
495
+ .mx-card {
496
+ --card-padding: 2rem; /* Only affects cards */
497
+ }
498
+
499
+ /* Override specific instance */
500
+ .hero-card {
501
+ --card-background: var(--colour-primary);
502
+ }
503
+ ```
504
+
505
+ ### Common Override Points
506
+
507
+ Components expose these common override variables:
508
+
509
+ **Spacing:**
510
+
511
+ - `--card-padding` → `--spacing-m`
512
+ - `--section-gap` → `--spacing-xl`
513
+ - `--gap` → `--spacing-s`
514
+
515
+ **Colors:**
516
+
517
+ - `--background` → `--colour-background`
518
+ - `--foreground` → `--colour-foreground`
519
+ - `--line-colour` → `--colour-border`
520
+
521
+ **Borders:**
522
+
523
+ - `--line-width` → `1px` or `2px`
524
+ - `--border-radius` → design system default
525
+
526
+ **Typography:**
527
+
528
+ - `--font-weight` → `--font-weight-bold`
529
+ - `--font-size` → size-specific default
530
+
531
+ ### Benefits
532
+
533
+ ✅ **No component CSS modification** - Override via custom properties
534
+ ✅ **Scoped changes** - Target specific components or instances
535
+ ✅ **Global changes** - Set at `:root` for site-wide updates
536
+ ✅ **Graceful fallbacks** - Always falls back to design system defaults
537
+ ✅ **Inheritance** - Child elements inherit parent overrides
538
+
539
+ ### Real Example
540
+
541
+ ```css
542
+ /* Component CSS (in design system) */
543
+ .mx-blockquote {
544
+ padding-inline-start: var(--line-gap, var(--gap));
545
+ border-inline-start: var(--line-width, 6px) solid var(--line-colour, var(--colour-border));
546
+ }
547
+
548
+ /* Consumer override (in your project) */
549
+ .special-quote {
550
+ --line-colour: var(--colour-accent);
551
+ --line-width: 10px;
552
+ }
553
+ ```
554
+
555
+ **Result:** The blockquote uses custom colors and width without touching component CSS.
556
+
557
+ ---
558
+
559
+ ## Color Scheme (light-dark)
560
+
561
+ ### Automatic Light/Dark Mode
562
+
563
+ The design system uses the CSS `light-dark()` function and `color-scheme` property for automatic light/dark mode support.
564
+
565
+ ### How It Works
566
+
567
+ **1. Set color-scheme:**
568
+
569
+ ```css
570
+ .mx-background--primary {
571
+ color-scheme: var(--scheme, var(--colour-scheme));
572
+ }
573
+ ```
574
+
575
+ The `color-scheme` property tells the browser which color scheme is in use (light or dark), affecting system UI and enabling `light-dark()`.
576
+
577
+ **2. Use light-dark() for colors:**
578
+
579
+ ```css
580
+ .mx-background--primary {
581
+ --line-colour: light-dark(var(--colour-primary-darker), var(--colour-primary-lighter));
582
+ }
583
+ ```
584
+
585
+ The `light-dark()` function automatically picks the first value in light mode, second value in dark mode.
586
+
587
+ ### Background Component Example
588
+
589
+ ```css
590
+ :where([class*="mx-background--"]) {
591
+ background-color: var(--background, var(--colour-background));
592
+ color: var(--foreground, var(--colour-foreground));
593
+ color-scheme: var(--scheme, var(--colour-scheme));
594
+ }
595
+
596
+ .mx-background--primary {
597
+ --scheme: var(--primary-scheme, var(--colour-primary-scheme, var(--colour-scheme)));
598
+ --background: var(--colour-primary);
599
+ --line-colour: light-dark(var(--colour-primary-darker), var(--colour-primary-lighter));
600
+ --colour-foreground-alt: var(--colour-primary-light);
601
+ }
602
+
603
+ .mx-background--reverse {
604
+ --scheme: var(--reverse-scheme, var(--colour-reverse-scheme, dark));
605
+ }
606
+ ```
607
+
608
+ ### Setting Color Scheme
609
+
610
+ **Global (page level):**
611
+
612
+ ```css
613
+ :root {
614
+ --colour-scheme: light; /* or dark */
615
+ }
616
+ ```
617
+
618
+ **Per section:**
619
+
620
+ ```css
621
+ .dark-section {
622
+ --scheme: dark;
623
+ }
624
+
625
+ .light-section {
626
+ --scheme: light;
627
+ }
628
+ ```
629
+
630
+ **Automatic (user preference):**
631
+
632
+ ```css
633
+ :root {
634
+ color-scheme: light dark; /* Supports both */
635
+ }
636
+
637
+ @media (prefers-color-scheme: dark) {
638
+ :root {
639
+ --colour-scheme: dark;
640
+ }
641
+ }
642
+ ```
643
+
644
+ ### Using light-dark()
645
+
646
+ **Syntax:**
647
+
648
+ ```css
649
+ property: light-dark(<light-value>, <dark-value>);
650
+ ```
651
+
652
+ **Examples:**
653
+
654
+ ```css
655
+ /* Text colors */
656
+ color: light-dark(var(--colour-text-dark), var(--colour-text-light));
657
+
658
+ /* Backgrounds */
659
+ background: light-dark(#ffffff, #000000);
660
+
661
+ /* Borders */
662
+ border-color: light-dark(var(--colour-primary), var(--colour-primary-light));
663
+
664
+ /* Shadows */
665
+ box-shadow: light-dark(0 2px 8px rgba(0, 0, 0, 0.1), 0 2px 8px rgba(255, 255, 255, 0.1));
666
+ ```
667
+
668
+ ### When to Use
669
+
670
+ **Use `light-dark()` for:**
671
+
672
+ - Colors that need to adapt to light/dark mode
673
+ - UI elements with different appearances per mode
674
+ - Borders, shadows, and subtle UI details
675
+
676
+ **Use `color-scheme` for:**
677
+
678
+ - Declaring which mode a section uses
679
+ - Enabling `light-dark()` function
680
+ - Affecting browser chrome (scrollbars, form controls)
681
+
682
+ ### Benefits
683
+
684
+ ✅ **Automatic switching** - Browser handles light/dark logic
685
+ ✅ **No JavaScript required** - Pure CSS solution
686
+ ✅ **Respects user preference** - Works with `prefers-color-scheme`
687
+ ✅ **Scoped modes** - Different sections can use different schemes
688
+ ✅ **System integration** - Browser chrome matches color scheme
689
+
690
+ ### Complete Example
691
+
692
+ ```css
693
+ /* Define color scheme modes in constants.css */
694
+ :root {
695
+ --colour-scheme: light;
696
+ --colour-primary: #003366;
697
+ --colour-primary-light: #6699cc;
698
+ }
699
+
700
+ /* Component uses light-dark() */
701
+ .mx-component {
702
+ color-scheme: var(--colour-scheme);
703
+ border-color: light-dark(var(--colour-primary), var(--colour-primary-light));
704
+ }
705
+
706
+ /* Consumer changes scheme for a section */
707
+ .dark-hero {
708
+ --scheme: dark;
709
+ }
710
+ ```
711
+
712
+ **Result:** The hero section automatically uses dark mode colors while rest of page uses light mode.
713
+
714
+ ---
715
+
716
+ ## Logical Properties
717
+
718
+ ### Use Logical Properties
719
+
720
+ **ENFORCED** by stylelint-use-logical-spec plugin.
721
+
722
+ ```css
723
+ /* ✅ GOOD - Logical properties (RTL-friendly) */
724
+ .mx-component {
725
+ padding-inline: 1rem; /* left/right in LTR, right/left in RTL */
726
+ padding-block: 2rem; /* top/bottom always */
727
+ margin-inline-start: 1rem; /* left in LTR, right in RTL */
728
+ margin-block-start: 1rem; /* top always */
729
+ border-inline-end: 1px solid; /* right in LTR, left in RTL */
730
+ inset-inline-start: 0; /* left in LTR, right in RTL */
731
+ }
732
+
733
+ /* ❌ BAD - Physical properties */
734
+ .mx-component {
735
+ padding-left: 1rem; /* Doesn't flip for RTL */
736
+ padding-right: 1rem;
737
+ margin-top: 1rem; /* OK but inconsistent */
738
+ border-right: 1px; /* Doesn't flip for RTL */
739
+ left: 0; /* Doesn't flip for RTL */
740
+ }
741
+ ```
742
+
743
+ ### Property Mapping
744
+
745
+ | Physical | Logical |
746
+ | ---------------- | ---------------------- |
747
+ | `padding-left` | `padding-inline-start` |
748
+ | `padding-right` | `padding-inline-end` |
749
+ | `padding-top` | `padding-block-start` |
750
+ | `padding-bottom` | `padding-block-end` |
751
+ | `margin-left` | `margin-inline-start` |
752
+ | `margin-right` | `margin-inline-end` |
753
+ | `border-left` | `border-inline-start` |
754
+ | `border-right` | `border-inline-end` |
755
+ | `left` | `inset-inline-start` |
756
+ | `right` | `inset-inline-end` |
757
+ | `top` | `inset-block-start` |
758
+ | `bottom` | `inset-block-end` |
759
+ | `width` | `inline-size` |
760
+ | `height` | `block-size` |
761
+ | `max-width` | `max-inline-size` |
762
+ | `min-height` | `min-block-size` |
763
+
764
+ ### Shorthand Logical Properties
765
+
766
+ ```css
767
+ /* Inline (horizontal in LTR) */
768
+ padding-inline: 1rem; /* Both sides */
769
+ margin-inline: 1rem 2rem; /* Start and end */
770
+
771
+ /* Block (vertical) */
772
+ padding-block: 1rem; /* Top and bottom */
773
+ margin-block: 1rem 2rem; /* Start and end */
774
+
775
+ /* Inset (position) */
776
+ inset: 0; /* All sides */
777
+ inset-inline: 0; /* Left and right in LTR */
778
+ inset-block: 0; /* Top and bottom */
779
+ ```
780
+
781
+ ### Exception: Float
782
+
783
+ `float` is exempt from logical properties (no logical equivalent):
784
+
785
+ ```css
786
+ .mx-component {
787
+ float: left; /* OK - Exception defined in config */
788
+ }
789
+ ```
790
+
791
+ ---
792
+
793
+ ## Cascade Layers
794
+
795
+ All design system CSS is wrapped in cascade layers for **proper specificity control**.
796
+
797
+ ### Layer Order
798
+
799
+ ```css
800
+ @layer popover-polyfill, design-system.defaults, design-system.atoms, design-system.layouts, design-system.utilities, design-system.components;
801
+ ```
802
+
803
+ ### Using Layers
804
+
805
+ ```css
806
+ /* Automatically handled by build process */
807
+ @layer design-system.components {
808
+ .mx-card {
809
+ /* Component styles */
810
+ }
811
+ }
812
+
813
+ @layer design-system.utilities {
814
+ .mx-text--center {
815
+ /* Utility styles */
816
+ }
817
+ }
818
+ ```
819
+
820
+ ### Layer Benefits
821
+
822
+ - ✅ **Predictable specificity** - Layers override regardless of selector specificity
823
+ - ✅ **Easy overrides** - Consumer styles automatically override design system
824
+ - ✅ **No !important needed** - Layer order handles precedence
825
+ - ✅ **Better organization** - Clear separation of concerns
826
+
827
+ ### Consumer Overrides
828
+
829
+ Consumers can easily override design system styles:
830
+
831
+ ```css
832
+ /* Consumer styles (unlayered) always win */
833
+ .mx-card {
834
+ padding: 3rem; /* Overrides design system */
835
+ }
836
+
837
+ /* Or use their own layers */
838
+ @layer my-app {
839
+ .mx-card {
840
+ padding: 3rem; /* Also overrides */
841
+ }
842
+ }
843
+ ```
844
+
845
+ ---
846
+
847
+ ## CSS Checklist
848
+
849
+ Before shipping styles:
850
+
851
+ - [ ] BEM naming convention followed
852
+ - [ ] `mx-` prefix on all classes
853
+ - [ ] Custom media imported at top of file (if needed)
854
+ - [ ] Mobile-first responsive approach
855
+ - [ ] Custom properties used (not hardcoded values)
856
+ - [ ] Logical properties used (not physical)
857
+ - [ ] Cascade layers applied
858
+ - [ ] Stylelint passes (`pnpm lint-css`)
859
+ - [ ] Styles work in RTL mode
860
+ - [ ] Tested across breakpoints
861
+ - [ ] No descending specificity issues
862
+ - [ ] Performance checked (no expensive selectors)
863
+
864
+ ---
865
+
866
+ ## Stylelint Configuration
867
+
868
+ Key rules from `.stylelintrc.json`:
869
+
870
+ ```javascript
871
+ {
872
+ "extends": ["stylelint-config-standard"],
873
+ "plugins": ["stylelint-use-logical-spec"],
874
+ "rules": {
875
+ "selector-class-pattern": "...", // BEM enforcement
876
+ "selector-nested-pattern": "^&", // Must nest with &
877
+ "liberty/use-logical-spec": [true, { "except": ["float"] }],
878
+ "no-descending-specificity": null, // Disabled for flexibility
879
+ "import-notation": "string"
880
+ }
881
+ }
882
+ ```
883
+
884
+ ---
885
+
886
+ ## Related Documentation
887
+
888
+ - [Code Quality Guidelines](./CodeQuality.md)
889
+ - [Component Architecture](./ComponentArchitecture.md)
890
+ - [Design Tokens](../src/tokens.js)
891
+ - [Custom Media](../src/_custom-media.css)