@codecademy/gamut 68.6.2-alpha.671e56.0 → 68.6.2-alpha.d2f2df.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/AccordionButtonDeprecated/ButtonDeprecated/index.d.ts +2 -2
  2. package/dist/AccordionButtonDeprecated/ButtonDeprecated/index.js +1 -1
  3. package/dist/Alert/elements.d.ts +2 -2
  4. package/dist/Anchor/index.d.ts +19 -9
  5. package/dist/Anchor/index.js +9 -6
  6. package/dist/BarChart/BarRow/elements.d.ts +47 -45
  7. package/dist/BarChart/utils/hooks.d.ts +2 -2
  8. package/dist/BarChart/utils/hooks.js +3 -1
  9. package/dist/Box/GridBox.d.ts +1 -0
  10. package/dist/Box/GridBox.js +1 -1
  11. package/dist/Box/props.d.ts +1 -1
  12. package/dist/Breadcrumbs/index.d.ts +5 -5
  13. package/dist/Breadcrumbs/index.js +2 -2
  14. package/dist/Button/CTAButton.d.ts +2 -2
  15. package/dist/Button/FillButton.d.ts +4 -4
  16. package/dist/Button/IconButton.d.ts +4 -4
  17. package/dist/Button/StrokeButton.d.ts +4 -4
  18. package/dist/Button/TextButton.d.ts +4 -4
  19. package/dist/Button/shared/InlineIconButton.d.ts +2 -2
  20. package/dist/Button/shared/styles.d.ts +3 -3
  21. package/dist/Button/shared/types.d.ts +1 -1
  22. package/dist/ButtonBase/ButtonBase.d.ts +9 -4
  23. package/dist/ButtonBase/ButtonBase.js +11 -4
  24. package/dist/Card/elements.d.ts +109 -103
  25. package/dist/Card/styles.d.ts +8 -8
  26. package/dist/Coachmark/index.d.ts +1 -1
  27. package/dist/ConnectedForm/ConnectedForm.d.ts +1 -1
  28. package/dist/ConnectedForm/ConnectedFormGroup.js +4 -3
  29. package/dist/ConnectedForm/utils.d.ts +1 -1
  30. package/dist/ConnectedForm/utils.js +1 -1
  31. package/dist/DatePicker/DatePickerInput/index.d.ts +1 -1
  32. package/dist/Disclosure/elements.d.ts +18 -12
  33. package/dist/FeatureShimmer/index.js +1 -1
  34. package/dist/Form/SelectDropdown/SelectDropdown.js +1 -1
  35. package/dist/Form/SelectDropdown/elements/containers.js +1 -1
  36. package/dist/Form/SelectDropdown/elements/controls.js +2 -2
  37. package/dist/Form/SelectDropdown/elements/multi-value.js +2 -2
  38. package/dist/Form/SelectDropdown/types/internal.d.ts +2 -2
  39. package/dist/Form/SelectDropdown/utils.js +2 -1
  40. package/dist/Form/elements/Form.d.ts +15 -15
  41. package/dist/Form/elements/FormGroup.d.ts +1 -1
  42. package/dist/Form/styles/Checkbox-styles.d.ts +1 -1
  43. package/dist/GridForm/GridFormButtons/index.d.ts +4 -4
  44. package/dist/List/ListProvider.d.ts +1 -1
  45. package/dist/List/elements.d.ts +44 -42
  46. package/dist/Menu/MenuItem.js +10 -6
  47. package/dist/Menu/elements.d.ts +2 -2
  48. package/dist/Modals/Dialog.js +6 -2
  49. package/dist/Modals/Modal.js +5 -2
  50. package/dist/Modals/elements.d.ts +1 -1
  51. package/dist/Pagination/AnimatedPaginationButtons.d.ts +31 -29
  52. package/dist/Pagination/EllipsisButton.d.ts +2 -2
  53. package/dist/Pagination/PaginationButton.d.ts +6 -6
  54. package/dist/Pagination/utils.d.ts +31 -29
  55. package/dist/Pagination/utils.js +14 -11
  56. package/dist/Popover/Popover.js +6 -6
  57. package/dist/Popover/types.d.ts +4 -3
  58. package/dist/PopoverContainer/PopoverContainer.js +9 -9
  59. package/dist/PopoverContainer/hooks.d.ts +16 -4
  60. package/dist/PopoverContainer/hooks.js +50 -27
  61. package/dist/PopoverContainer/types.d.ts +2 -1
  62. package/dist/Tabs/TabButton.d.ts +2 -2
  63. package/dist/Tabs/TabNavLink.d.ts +2 -2
  64. package/dist/Tag/elements.d.ts +14 -8
  65. package/dist/Tag/index.js +1 -1
  66. package/dist/Tip/InfoTip/InfoTipButton.d.ts +4 -4
  67. package/dist/Tip/PreviewTip/elements.d.ts +12 -6
  68. package/dist/Tip/__tests__/helpers.d.ts +1 -1
  69. package/dist/Tip/shared/FloatingTip.js +2 -2
  70. package/dist/Tip/shared/types.d.ts +2 -2
  71. package/dist/Tip/shared/utils.js +1 -1
  72. package/dist/utils/nullish.d.ts +10 -0
  73. package/dist/utils/nullish.js +11 -0
  74. package/dist/utils/react.js +4 -2
  75. package/package.json +12 -15
  76. package/agent-tools/.claude-plugin/marketplace.json +0 -16
  77. package/agent-tools/.claude-plugin/plugin.json +0 -7
  78. package/agent-tools/.cursor-plugin/plugin.json +0 -7
  79. package/agent-tools/DESIGN.Codecademy.md +0 -643
  80. package/agent-tools/DESIGN.LXStudio.md +0 -437
  81. package/agent-tools/DESIGN.Percipio.md +0 -433
  82. package/agent-tools/DESIGN.md +0 -1
  83. package/agent-tools/agents/.gitkeep +0 -0
  84. package/agent-tools/rules/accessibility.mdc +0 -78
  85. package/agent-tools/skills/gamut-accessibility/SKILL.md +0 -214
  86. package/agent-tools/skills/gamut-buttons/SKILL.md +0 -96
  87. package/agent-tools/skills/gamut-color-mode/SKILL.md +0 -257
  88. package/agent-tools/skills/gamut-forms/SKILL.md +0 -84
  89. package/agent-tools/skills/gamut-layout/SKILL.md +0 -109
  90. package/agent-tools/skills/gamut-list/SKILL.md +0 -273
  91. package/agent-tools/skills/gamut-review/SKILL.md +0 -254
  92. package/agent-tools/skills/gamut-style-utilities/SKILL.md +0 -107
  93. package/agent-tools/skills/gamut-system-props/SKILL.md +0 -203
  94. package/agent-tools/skills/gamut-testing/SKILL.md +0 -221
  95. package/agent-tools/skills/gamut-theming/SKILL.md +0 -115
  96. package/agent-tools/skills/gamut-typography/SKILL.md +0 -98
  97. package/bin/commands/plugin/install.mjs +0 -212
  98. package/bin/commands/plugin/list.mjs +0 -73
  99. package/bin/commands/plugin/remove.mjs +0 -108
  100. package/bin/commands/plugin/update.mjs +0 -59
  101. package/bin/gamut.mjs +0 -96
  102. package/bin/lib/claude.mjs +0 -52
  103. package/bin/lib/cursor.mjs +0 -40
  104. package/bin/lib/design.mjs +0 -71
  105. package/bin/lib/io.mjs +0 -14
  106. package/bin/lib/resolve-plugin-dir.mjs +0 -38
  107. package/bin/lib/run-command.mjs +0 -22
@@ -1,643 +0,0 @@
1
- ---
2
- version: alpha
3
- name: Codecademy Design System
4
- description: Design tokens for codecademy.com
5
- colors:
6
- # palette — raw swatches; set once on :root and then always reference by token name, never use hex values directly in code
7
- hyper-500: '#3A10E5'
8
- hyper-400: '#5533FF'
9
- navy-900: '#0A0D1C'
10
- navy-800: '#10162F'
11
- navy-700: '#31374C'
12
- navy-600: '#4C5063'
13
- navy-500: '#686C7C'
14
- navy-300: '#BCBEC5'
15
- navy-200: '#E2E3E6'
16
- navy-100: '#F5F6F7'
17
- yellow-500: '#FFD300'
18
- yellow-400: '#CCA900'
19
- yellow-0: '#FFFAE5'
20
- yellow-900: '#211B00'
21
- green-700: '#008A27'
22
- green-400: '#AEE938'
23
- green-0: '#F5FFE3'
24
- green-900: '#151C07'
25
- red-600: '#BE1809'
26
- red-500: '#E91C11'
27
- red-400: '#DC5879'
28
- red-300: '#E85D7F'
29
- red-0: '#FBF1F0'
30
- red-900: '#280503'
31
- beige: '#FFF0E5'
32
- white: '#ffffff'
33
- black: '#000000'
34
- # semantic aliases (light mode) — use these in code, not palette swatches or hex values
35
- text: '{colors.navy-800}'
36
- text-accent: '{colors.navy-900}'
37
- text-secondary: '{colors.navy-600}'
38
- text-disabled: '{colors.navy-500}'
39
- background: '{colors.white}'
40
- background-primary: '{colors.beige}'
41
- background-contrast: '{colors.white}'
42
- background-selected: '{colors.navy-100}'
43
- background-hover: '{colors.navy-200}'
44
- background-disabled: '{colors.navy-200}'
45
- background-success: '{colors.green-0}'
46
- background-warning: '{colors.yellow-0}'
47
- background-error: '{colors.red-0}'
48
- primary: '{colors.hyper-500}'
49
- primary-hover: '{colors.hyper-400}'
50
- primary-inverse: '{colors.yellow-500}'
51
- secondary: '{colors.navy-800}'
52
- secondary-hover: '{colors.navy-700}'
53
- danger: '{colors.red-500}'
54
- danger-hover: '{colors.red-600}'
55
- feedback-error: '{colors.red-600}'
56
- feedback-success: '{colors.green-700}'
57
- feedback-warning: '{colors.yellow-500}'
58
- border-primary: '{colors.navy-800}'
59
- border-secondary: '{colors.navy-600}'
60
- border-tertiary: '{colors.navy-300}'
61
- border-disabled: '{colors.navy-500}'
62
- shadow-primary: '{colors.navy-800}'
63
- shadow-secondary: '{colors.navy-600}'
64
- typography:
65
- base:
66
- fontFamily: '"Apercu", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
67
- fontSize: '1rem'
68
- fontWeight: '400'
69
- lineHeight: '1.5'
70
- accent:
71
- fontFamily: '"Suisse", "Apercu", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
72
- fontSize: '0.875rem'
73
- fontWeight: '400'
74
- lineHeight: '1.5'
75
- title:
76
- fontFamily: '"Apercu", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
77
- fontSize: '2.125rem'
78
- fontWeight: '700'
79
- lineHeight: '1.2'
80
- hankenGrotesk:
81
- fontFamily: '"Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
82
- monospace:
83
- fontFamily: 'Monaco, Menlo, "Ubuntu Mono", "Droid Sans Mono", Consolas, monospace'
84
- rounded:
85
- none: '0px'
86
- sm: '2px'
87
- md: '4px'
88
- lg: '8px'
89
- xl: '16px'
90
- full: '999px'
91
- spacing:
92
- '0': '0'
93
- '4': '0.25rem'
94
- '8': '0.5rem'
95
- '12': '0.75rem'
96
- '16': '1rem'
97
- '24': '1.5rem'
98
- '32': '2rem'
99
- '40': '2.5rem'
100
- '48': '3rem'
101
- '64': '4rem'
102
- '96': '6rem'
103
- components:
104
- FillButton:
105
- backgroundColor: '{colors.primary}'
106
- textColor: '{colors.white}'
107
- rounded: '{rounded.md}'
108
- FillButton-hover:
109
- backgroundColor: '{colors.primary-hover}'
110
- textColor: '{colors.white}'
111
- FillButton-danger:
112
- backgroundColor: '{colors.danger}'
113
- textColor: '{colors.white}'
114
- rounded: '{rounded.md}'
115
- FillButton-danger-hover:
116
- backgroundColor: '{colors.danger-hover}'
117
- textColor: '{colors.white}'
118
- StrokeButton:
119
- backgroundColor: 'transparent'
120
- textColor: '{colors.secondary}'
121
- rounded: '{rounded.md}'
122
- CTAButton:
123
- backgroundColor: '{colors.primary}'
124
- textColor: '{colors.white}'
125
- rounded: '{rounded.md}'
126
- CTAButton-inverse:
127
- backgroundColor: '{colors.primary-inverse}'
128
- textColor: '{colors.secondary}'
129
- rounded: '{rounded.md}'
130
- TextButton:
131
- backgroundColor: 'transparent'
132
- textColor: '{colors.primary}'
133
- TextButton-hover:
134
- textColor: '{colors.primary-hover}'
135
- Card:
136
- backgroundColor: '{colors.background}'
137
- rounded: '{rounded.none}'
138
- Card-interactive:
139
- rounded: '{rounded.md}'
140
- Card-elevated:
141
- backgroundColor: '{colors.background-primary}'
142
- rounded: '{rounded.lg}'
143
- Card-beige:
144
- backgroundColor: '{colors.beige}'
145
- rounded: '{rounded.lg}'
146
- Input:
147
- backgroundColor: '{colors.background}'
148
- textColor: '{colors.text}'
149
- rounded: '{rounded.md}'
150
- Checkbox:
151
- backgroundColor: '{colors.primary}'
152
- rounded: '{rounded.sm}'
153
- Checkbox-hover:
154
- backgroundColor: '{colors.primary-hover}'
155
- Headline:
156
- textColor: '{colors.text-accent}'
157
- typography: '{typography.title}'
158
- Tag-success:
159
- backgroundColor: '{colors.feedback-success}'
160
- textColor: '{colors.white}'
161
- rounded: '{rounded.sm}'
162
- Tag-warning:
163
- backgroundColor: '{colors.feedback-warning}'
164
- textColor: '{colors.text}'
165
- rounded: '{rounded.sm}'
166
- Alert-error:
167
- backgroundColor: '{colors.background-error}'
168
- textColor: '{colors.feedback-error}'
169
- Alert-success:
170
- backgroundColor: '{colors.background-success}'
171
- textColor: '{colors.text}'
172
- Alert-warning:
173
- backgroundColor: '{colors.background-warning}'
174
- textColor: '{colors.text}'
175
- ---
176
-
177
- # Codecademy
178
-
179
- This file defines the visual design tokens for codecademy.com, implemented using the Gamut design system (`@codecademy/gamut`, `@codecademy/gamut-styles`). Gamut ships 52 components with Figma ↔ code mappings via Figma Code Connect.
180
-
181
- **Figma file**: https://www.figma.com/design/ReGfRNillGABAj5SlITalN/📐-Gamut
182
- **Storybook**: https://gamut.codecademy.com
183
-
184
- ---
185
-
186
- ## Visual Theme & Atmosphere
187
-
188
- Codecademy communicates **logic with personality** — structured and trustworthy enough for a learning platform, with creative moments that feel engaging and human. The design voice is: _"we are ruled by logic, but are creative and a bit unexpected as well."_
189
-
190
- **Density**: Medium. Information-dense layouts use careful whitespace and strong typographic hierarchy to stay readable. Avoid cramped or overly airy layouts.
191
-
192
- **Design philosophy**:
193
-
194
- - Components are color mode–aware by default — never hardcode hex values for adaptive UI
195
- - Every component works across all themes without modification
196
- - Mobile-first responsive design built on a 12-column grid
197
- - Accessibility is guaranteed by design: semantic color tokens meet contrast requirements per mode automatically
198
-
199
- ---
200
-
201
- ## Themes
202
-
203
- Codecademy products use one of four Gamut themes, all sharing the same core visual identity. Token aliases resolve to the right values per theme automatically — components require no modification.
204
-
205
- | Theme | Use case | Base font | Dark mode |
206
- | ------------- | ------------------------------- | -------------- | -------------- |
207
- | **Core** | Codecademy (default) | Apercu | ✓ light + dark |
208
- | **Admin** | Codecademy admin tools | Apercu | ✓ light + dark |
209
- | **Platform** | Codecademy learning environment | Apercu | ✓ light + dark |
210
- | **LX Studio** | LX Studio application | Hanken Grotesk | light only |
211
-
212
- The active theme is set at the app root via `<GamutProvider>`. When designing, know which theme your screen targets — it affects primary colors, font families, and available color weights.
213
-
214
- **Font licensing**: Apercu is licensed for codecademy.com only. LX Studio uses Hanken Grotesk.
215
-
216
- For Percipio projects, use `DESIGN.Percipio.md` from the same package instead.
217
-
218
- ### LX Studio theme overrides
219
-
220
- LX Studio extends Core with these differences:
221
-
222
- **Font**: All families → `"Hanken Grotesk"` (no Apercu, no Suisse).
223
-
224
- **Border radii** (all values shift up one step):
225
-
226
- | Token | Core | LX Studio |
227
- | ----- | ---- | --------- |
228
- | `sm` | 2px | 4px |
229
- | `md` | 4px | 8px |
230
- | `lg` | 8px | 12px |
231
-
232
- **Semantic color overrides (light mode)**:
233
-
234
- | Token | Core value | LX Studio value |
235
- | -------------------- | ------------------- | ------------------------------- |
236
- | `primary` | hyper-500 `#3A10E5` | `#5628FE` (lxStudioPurple) |
237
- | `primary-hover` | hyper-400 `#5533FF` | `#7955FC` (lxStudioPurpleHover) |
238
- | `feedback-success` | green-700 `#008A27` | `#06844F` (lxStudioSuccess) |
239
- | `background-primary` | beige `#FFF0E5` | `#FAFBFC` (lxStudioBgPrimary) |
240
- | `shadow-primary` | navy-800 | navy-200 |
241
- | `border-primary` | navy-800 | navy-400 |
242
- | `border-disabled` | navy-500 | navy-300 |
243
-
244
- ---
245
-
246
- ## Semantic Color Aliases
247
-
248
- Use these token names when specifying colors in designs. They resolve to the correct raw value for the active theme and color mode automatically. **Never hardcode hex values** for anything that needs to adapt across modes.
249
-
250
- ### Text
251
-
252
- | Token | Light | Dark | Use for |
253
- | ---------------- | -------------------------- | --------------- | --------------------------- |
254
- | `text` | navy-800 `#10162F` at 100% | white `#ffffff` | Default body and UI text |
255
- | `text-accent` | navy-900 `#0A0D1C` | beige `#FFF0E5` | Stronger emphasis text |
256
- | `text-secondary` | navy-800 at 75% | white at 65% | Supporting / secondary copy |
257
- | `text-disabled` | navy-800 at 63% | white at 50% | Disabled state labels |
258
-
259
- ### Background
260
-
261
- | Token | Light | Dark | Use for |
262
- | --------------------- | ------------------ | -------------------- | --------------------------------- |
263
- | `background` | white `#ffffff` | navy-800 `#10162F` | Default page/component background |
264
- | `background-primary` | beige `#FFF0E5` | navy-900 `#0A0D1C` | Slightly elevated surfaces |
265
- | `background-contrast` | white | black `#000000` | Maximum contrast surface |
266
- | `background-selected` | navy-800 at 4% | white at 4% | Selected row / item |
267
- | `background-hover` | navy-800 at 12% | white at 9% | Hover state overlay |
268
- | `background-disabled` | navy-800 at 12% | white at 9% | Disabled surface |
269
- | `background-success` | green-0 `#F5FFE3` | green-900 `#151C07` | Success state container |
270
- | `background-warning` | yellow-0 `#FFFAE5` | yellow-900 `#211B00` | Warning state container |
271
- | `background-error` | red-0 `#FBF1F0` | red-900 `#280503` | Error state container |
272
-
273
- ### Interactive
274
-
275
- | Token | Light | Dark | Use for |
276
- | ----------------- | -------------------- | -------------------- | ------------------------------------ |
277
- | `primary` | hyper-500 `#3A10E5` | yellow-500 `#FFD300` | Primary CTA, links, focus rings |
278
- | `primary-hover` | hyper-400 `#5533FF` | yellow-400 `#CCA900` | Hover state of primary interactive |
279
- | `primary-inverse` | yellow-500 `#FFD300` | hyper-500 `#3A10E5` | Primary on a colored background |
280
- | `secondary` | navy-800 `#10162F` | white `#ffffff` | Secondary CTA, ghost buttons |
281
- | `secondary-hover` | navy-800 at 86% | white at 80% | Hover state of secondary interactive |
282
- | `danger` | red-500 `#E91C11` | red-300 `#E85D7F` | Destructive actions, error states |
283
- | `danger-hover` | red-600 `#BE1809` | red-400 `#DC5879` | Hover on danger interactive |
284
-
285
- ### Border
286
-
287
- | Token | Light | Dark | Use for |
288
- | ------------------ | ------------------ | --------------- | -------------------------- |
289
- | `border-primary` | navy-800 `#10162F` | white `#ffffff` | Strong borders, dividers |
290
- | `border-secondary` | navy-800 at 75% | white at 65% | Medium-weight borders |
291
- | `border-tertiary` | navy-800 at 28% | white at 20% | Subtle borders, separators |
292
- | `border-disabled` | navy-800 at 63% | white at 50% | Disabled input borders |
293
-
294
- ### Feedback
295
-
296
- | Token | Light | Dark | Use for |
297
- | ------------------ | ------------------- | ------------------- | -------------------------------- |
298
- | `feedback-error` | red-600 `#BE1809` | red-300 `#E85D7F` | Error messages, validation |
299
- | `feedback-success` | green-700 `#008A27` | green-400 `#AEE938` | Success messages, confirmations |
300
- | `feedback-warning` | yellow `#FFD300` | yellow-0 `#FFFAE5` | Warning messages, caution states |
301
-
302
- ### Shadow
303
-
304
- | Token | Light | Dark |
305
- | ------------------ | --------------- | ------------ |
306
- | `shadow-primary` | navy-800 | white |
307
- | `shadow-secondary` | navy-800 at 75% | white at 65% |
308
-
309
- ---
310
-
311
- ## Raw Color Palette
312
-
313
- All colors available as static tokens regardless of color mode. Use these only when a color should be **fixed** and not adapt to dark mode.
314
-
315
- ### Core Palette
316
-
317
- | Name | Weights available | Notes |
318
- | --------------- | ---------------------------- | --------------------------------------------------------------------------------- |
319
- | `navy` | 100–900 | 100–700 are rgba transparencies of `#10162F`; 800 = `#10162F`; 900 = `#0A0D1C` |
320
- | `white` | 100–700 | rgba transparencies of `#ffffff` (no solid white weight — use `white` for `#fff`) |
321
- | `blue` | 0, 100, 300, 400, 500, 800 | 500 = `#1557FF` |
322
- | `hyper` | 400, 500 | 500 = `#3A10E5` (purple-blue), 400 = `#5533FF` |
323
- | `green` | 0, 100, 400, 700, 900 | 700 = `#008A27` |
324
- | `yellow` | 0, 400, 500, 900 | 500 = `#FFD300` |
325
- | `red` | 0, 300, 400, 500, 600, 900 | 500 = `#E91C11` |
326
- | `gray` | 100, 200, 300, 600, 800, 900 | |
327
- | `pink` | 0, 400 | 400 = `#F966FF` |
328
- | `orange` | 100, 500 | 500 = `#FF8C00` |
329
- | `beige` | 100 (alias: `beige`) | `#FFF0E5` |
330
- | `black` | — | `#000000` |
331
- | `white` (solid) | — | `#ffffff` |
332
-
333
- **Named aliases** (shorthand for common weights):
334
- `beige`, `blue`, `green`, `hyper`, `lightBlue`, `lightGreen`, `navy`, `orange`, `paleBlue`, `paleGreen`, `palePink`, `paleRed`, `paleYellow`, `pink`, `red`, `yellow`, `black`, `white`
335
-
336
- ### Platform-only additions
337
-
338
- `lightBeige` (`#FFFBF8`), `gold` (`#8A7300`), `teal` (`#006D82`), `purple` (`#B3CCFF`)
339
-
340
- ### LX Studio additions
341
-
342
- `lxStudioPurple` (`#5628FE`), `lxStudioPurpleHover` (`#7955FC`), `lxStudioSuccess` (`#06844F`)
343
-
344
- ---
345
-
346
- ## Typography
347
-
348
- ### Typefaces
349
-
350
- | Token | Core / Admin / Platform | LX Studio | Use for |
351
- | ----------- | -------------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------ |
352
- | `base` | Apercu Pro (CSS: `Apercu`) | Hanken Grotesk | All default UI text, headlines, body copy |
353
- | `accent` | Suisse Intl Mono (CSS: `Suisse`); falls back to `Apercu` | Hanken Grotesk | Code, captions, labels, lists, technical context |
354
- | `monospace` | Monaco, Menlo, Ubuntu Mono, Droid Sans Mono, Consolas | Monaco, Menlo, Ubuntu Mono, Droid Sans Mono, Consolas | Code editor contexts |
355
- | `system` | System UI fonts | System UI fonts | Performance-critical surfaces |
356
-
357
- **Apercu is licensed for codecademy.com only.** LX Studio uses Hanken Grotesk for both `base` and `accent`.
358
-
359
- ### Rules
360
-
361
- - **Apercu Bold** for headlines, sub-headlines, CTAs, and buttons.
362
- - **Apercu Regular** for body text, UI labels, and menu items.
363
- - **Apercu Italic** to emphasize text within a Regular paragraph — not Bold.
364
- - **Suisse** sparingly: code snippets, enumerated items, quotations, captions. Reads 10–15% large for its point size — size down relative to Apercu (14px Suisse ≈ 16px Apercu visually).
365
- - Text is **left-aligned** by default. Center-align only for short marketing headlines. Never right-align.
366
- - Do not adjust letter-spacing.
367
-
368
- ### Font size scale
369
-
370
- | Token key | Size | Common use |
371
- | --------- | ---- | ---------------------------- |
372
- | `64` | 64px | Hero / display |
373
- | `44` | 44px | Page titles |
374
- | `34` | 34px | Section titles |
375
- | `26` | 26px | Sub-section titles |
376
- | `22` | 22px | Card titles, large UI labels |
377
- | `20` | 20px | Secondary titles |
378
- | `18` | 18px | Large body, intro text |
379
- | `16` | 16px | Default body text |
380
- | `14` | 14px | Small body, captions, labels |
381
-
382
- ### Font weight scale
383
-
384
- | Token | Value | Use |
385
- | ------- | ----- | ------------------------ |
386
- | `base` | 400 | Body text, UI labels |
387
- | `title` | 700 | Headlines, CTAs, buttons |
388
-
389
- ### Line height scale
390
-
391
- | Token | Value | Use |
392
- | ------------- | ----- | ------------------------------------------------ |
393
- | `base` | 1.5 | Body text (150% — aim for 150–175% of font size) |
394
- | `spacedTitle` | 1.3 | Sub-headlines and medium titles |
395
- | `title` | 1.2 | Large headlines (aim for 100–110% of font size) |
396
-
397
- ### Line length
398
-
399
- Target 45–85 characters per line; 66 characters is ideal for web body text. Max 50 characters for multi-column layouts.
400
-
401
- ---
402
-
403
- ## Spacing Scale
404
-
405
- All spacing is multiples of 4px, placed on an 8px grid.
406
-
407
- | Token | Value |
408
- | ----- | ----- |
409
- | `0` | 0 |
410
- | `4` | 4px |
411
- | `8` | 8px |
412
- | `12` | 12px |
413
- | `16` | 16px |
414
- | `24` | 24px |
415
- | `32` | 32px |
416
- | `40` | 40px |
417
- | `48` | 48px |
418
- | `64` | 64px |
419
- | `96` | 96px |
420
-
421
- ---
422
-
423
- ## Depth & Elevation
424
-
425
- Gamut uses border-based and shadow-based depth cues rather than a rigid z-elevation tier system.
426
-
427
- ### Shadow tokens
428
-
429
- Shadow props accept standard CSS `box-shadow` syntax. Always use `shadow-primary` / `shadow-secondary` color tokens so shadows remain visible in both light and dark modes.
430
-
431
- ```
432
- box-shadow: 0 4px 0 <shadow-primary> → Card "outline" shadow
433
- box-shadow: 0 0 4px rgba(0,0,0,.15) → Subtle ambient shadow
434
- ```
435
-
436
- ### Card shadow variants
437
-
438
- | Variant | Effect | Use for |
439
- | ---------------- | ------------------------------------------------------ | ------------------------------ |
440
- | `none` (default) | No shadow | Static / non-interactive cards |
441
- | `outline` | Solid shadow on bottom + left/right using border color | Standard clickable cards |
442
- | `patternLeft` | Decorative checker pattern on bottom + left | Stylized content cards |
443
- | `patternRight` | Decorative checker pattern on bottom + right | Stylized content cards |
444
-
445
- Interactive cards (`isInteractive` prop) gain a shadow on hover and `borderRadius: md`. Cards with a pattern drop the pattern on hover.
446
-
447
- ### Z-index
448
-
449
- | Token | Value | Use |
450
- | --------- | ----- | ------------------ |
451
- | `headerZ` | 15 | Global page header |
452
-
453
- ---
454
-
455
- ## Border Radius Scale
456
-
457
- | Token | Value | Use |
458
- | ------ | ----- | ------------------------------------------ |
459
- | `none` | 0px | Square / non-interactive elements |
460
- | `sm` | 2px | Subtle rounding, tags |
461
- | `md` | 4px | Default buttons, inputs, interactive cards |
462
- | `lg` | 8px | Cards, panels |
463
- | `xl` | 16px | Large cards, modals |
464
- | `full` | 999px | Pills, avatars, circular elements |
465
-
466
- ---
467
-
468
- ## Responsive Behavior
469
-
470
- Mobile-first. Apply styles from the named breakpoint and up.
471
-
472
- ### Breakpoints & screen sizes
473
-
474
- | Token | Min-width | Screen dimensions | Max content | Fold height |
475
- | -------- | --------- | ----------------- | ----------- | ----------- |
476
- | _(base)_ | 0 | 320×480 | 288px | 440px |
477
- | `xs` | 480px | 480×900 | 448px | 440px |
478
- | `sm` | 768px | 768×1024 | 704px | 680px |
479
- | `md` | 1024px | 1024×768 | 896px | 680px |
480
- | `lg` | 1200px | 1200×900 | 1072px | 680px |
481
- | `xl` | 1440px | 1440×900 | 1248px | 680px |
482
-
483
- Container query variants (`c_xs` through `c_xl`) mirror these values but trigger on component container size, not viewport.
484
-
485
- ### Grid
486
-
487
- 12-column grid at all breakpoints. The designer specifies how many columns a section spans per breakpoint.
488
-
489
- | Usage | Recommended values |
490
- | --------------------- | ------------------------------------------------ |
491
- | Horizontal margins | 64px (lg+), 48px (md), 32px (sm/xs), 16px (base) |
492
- | Column gaps (gutters) | 32px (lg+), 24px (md), 16px (sm/xs), 8px (base) |
493
- | Row gaps | 32px (lg+), 24px (md), 16px (sm/xs), 8px (base) |
494
-
495
- ### Touch targets
496
-
497
- Minimum interactive touch target: **44×44px** on mobile breakpoints.
498
-
499
- ### Collapsing strategies
500
-
501
- - Begin design work at 1440px (XL), then adapt to smaller sizes.
502
- - Wider multi-column layouts collapse to fewer columns — do not simply stretch or squish.
503
- - Elements not in an explicit lockup (e.g., catalog cards) should align on one axis (usually left) rather than fill column widths.
504
- - Avoid dense or small components in the base (mobile) breakpoint.
505
-
506
- ---
507
-
508
- ## Component Library
509
-
510
- Components are organized into three tiers:
511
-
512
- ### Atoms — foundational, single-purpose
513
-
514
- Badge, Button (FillButton, StrokeButton, CTAButton, TextButton, IconButton), ButtonBase, Card, Checkbox, CodeBlock, ColorMode, Drawer, FlexBox, FormGroup, GridBox, HiddenText, Icon, Input, Label, Loader, Radio, Select, Spinner, Tag, TextArea, Toggle, Tooltip
515
-
516
- ### Molecules — composed of atoms, handle a discrete task
517
-
518
- Alert, Anchor, Breadcrumbs, Coachmark, Disclosure, GridForm, Markdown, Menu, Modal, Pagination, Popover, ProgressBar, Table, Tabs, Toast, Toaster, Video
519
-
520
- ### Organisms — page-level compositions
521
-
522
- ContentContainer, GridContainer, Layout, LayoutGrid
523
-
524
- ### Key component patterns
525
-
526
- #### Buttons
527
-
528
- | Variant | Component | Use for |
529
- | ----------------- | -------------- | ----------------------------------- |
530
- | Primary action | `FillButton` | Solid fill, high-emphasis CTA |
531
- | Secondary action | `StrokeButton` | Outlined, secondary CTA |
532
- | Marketing CTA | `CTAButton` | High-visibility promotional actions |
533
- | Tertiary / inline | `TextButton` | Low-emphasis, inline text actions |
534
- | Icon-only | `IconButton` | Compact actions with icon only |
535
-
536
- All button variants support sizes: `small`, `normal` (default), `large`. They accept an `icon` prop (leading or trailing) and a `disabled` prop. Passing `href` renders the button as an `<a>` tag.
537
-
538
- **States**: default → hover (`primary-hover` / `secondary-hover`) → active → disabled (`text-disabled` + `background-disabled`).
539
-
540
- #### Cards
541
-
542
- Cards support:
543
-
544
- - **Background variants**: `default` (ColorMode-responsive), `white`, `yellow`, `beige` (light contexts), `navy`, `hyper` (dark contexts)
545
- - **Shadow variants**: `none` (default), `outline`, `patternLeft`, `patternRight`
546
- - **Interaction**: wrap in `<Anchor>` and add `isInteractive` for hover shadow + `borderRadius: md`
547
- - **Border radius**: defaults to `none` (non-interactive); override with the `borderRadius` prop as needed
548
-
549
- #### Color-aware components
550
-
551
- - **`<ColorMode mode="light|dark|system">`** — wraps a subtree in an explicit color mode.
552
- - **`<Background bg="<color>">`** — applies a background color and automatically switches the color mode inside to maintain accessible contrast. Prefer this over setting a raw `bg` prop on any content-bearing surface.
553
-
554
- ---
555
-
556
- ## Global Elements
557
-
558
- | Token | Value | Use |
559
- | -------------- | -------------------------------------- | ------------------------------- |
560
- | `headerHeight` | 4rem (64px) base, 5rem (80px) at `md`+ | Global page header height |
561
- | `headerZ` | 15 | Z-index for global page headers |
562
-
563
- ---
564
-
565
- ## Do's and Don'ts
566
-
567
- ### Colors
568
-
569
- - **Do** use semantic color aliases (`primary`, `text`, `background`, etc.) for any UI that must adapt to color mode or theme.
570
- - **Do** use `<Background bg="...">` when setting a section background — it adjusts the inner color mode for contrast automatically.
571
- - **Don't** hardcode hex values for anything adaptive.
572
- - **Don't** use navy or white semi-transparent swatches where they may overlap unpredictably.
573
-
574
- ### Typography
575
-
576
- - **Do** use `title` weight (700) for headlines, CTAs, and buttons.
577
- - **Do** keep body text at 150–175% line height for readability.
578
- - **Do** use Suisse sparingly — as an accent for code, captions, and lists only.
579
- - **Don't** use Apercu Bold to emphasize text _within_ a paragraph — use Italic instead.
580
- - **Don't** adjust letter-spacing.
581
- - **Don't** right-align text in normal circumstances.
582
- - **Don't** center-align body paragraphs with long line lengths.
583
-
584
- ### Layout & Spacing
585
-
586
- - **Do** use multiples of 8px for block-element spacing (4px only for inline / typographic relationships).
587
- - **Do** begin design work at 1440px (XL), then adapt down to each breakpoint.
588
- - **Do** align elements to the 12-column grid.
589
- - **Don't** stretch elements to fill wider space — maintain proper line lengths and component widths.
590
-
591
- ### Components
592
-
593
- - **Do** use `FillButton` for primary actions and `StrokeButton` for secondary actions.
594
- - **Do** add `isInteractive` to any `Card` that is wrapped in an `<Anchor>`.
595
- - **Don't** use `CTAButton` for standard UI actions — reserve it for marketing/high-visibility promotions.
596
- - **Don't** use `<Background>` without an actual color value — it's not a neutral wrapper.
597
-
598
- ---
599
-
600
- ## Agent Prompt Guide
601
-
602
- Quick color/token reference for generating or specifying UI:
603
-
604
- | Scenario | Tokens |
605
- | ---------------------- | ----------------------------------------------------------------------------------------------------- |
606
- | Primary button (light) | `bg: primary (#3A10E5)`, `color: white`, `hover: primary-hover (#5533FF)` |
607
- | Primary button (dark) | `bg: primary (#FFD300)`, `color: navy-800`, `hover: primary-hover (#CCA900)` |
608
- | Body text | `color: text`, `font: base (Apercu Pro)`, `size: 16px`, `weight: 400`, `lineHeight: base (1.5)` |
609
- | Headline | `color: text-accent`, `font: base`, `size: 34–64px`, `weight: title (700)`, `lineHeight: title (1.2)` |
610
- | Caption / label | `color: text-secondary`, `font: accent (Suisse Int'l Mono)`, `size: 14px` |
611
- | Card default | `bg: background`, `borderRadius: none` — add `isInteractive` for hover shadow + `borderRadius: md` |
612
- | Error state | `color: feedback-error`, `bg: background-error`, `border: danger` |
613
- | Success state | `color: feedback-success`, `bg: background-success` |
614
- | Disabled state | `color: text-disabled`, `bg: background-disabled`, `border: border-disabled` |
615
-
616
- ### Component token cheatsheet
617
-
618
- ```
619
- FillButton → bg: primary, color: white, hover: primary-hover
620
- StrokeButton → bg: transparent, border: secondary, hover: secondary-hover
621
- CTAButton → high-visibility; use primary-inverse on colored surfaces
622
- Card (light) → variant: "default" | "white" | "yellow" | "beige"
623
- Card (dark) → variant: "navy" | "hyper"
624
- Alert (error) → uses feedback-error + background-error
625
- Alert (success) → uses feedback-success + background-success
626
- Alert (warning) → uses feedback-warning + background-warning
627
- ColorMode → <ColorMode mode="light|dark|system">
628
- Background → <Background bg="hyper"> — auto-flips color mode for contrast
629
- ```
630
-
631
- ---
632
-
633
- ## Figma ↔ Code Mapping
634
-
635
- 52 components have Code Connect entries in `packages/code-connect/`. These appear as live code snippets in Figma's inspect panel when you select a component.
636
-
637
- Figma layer names use emojis as visual shorthand (e.g. `✏️ label`, `👁 leading icon`, `↳ trailing icon`). These map to named props in the React components.
638
-
639
- To publish updated code snippets after changing a component:
640
-
641
- ```
642
- npx figma connect publish --token <your-figma-token>
643
- ```