@codecademy/gamut 68.7.1-alpha.89ca82.0 → 68.7.1-alpha.f618c1.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 (87) hide show
  1. package/agent-tools/DESIGN.Codecademy.md +85 -84
  2. package/agent-tools/DESIGN.LXStudio.md +106 -104
  3. package/agent-tools/DESIGN.Percipio.md +104 -104
  4. package/agent-tools/DESIGN.md +1 -7
  5. package/bin/lib/claude.mjs +14 -5
  6. package/bin/lib/cursor.mjs +4 -1
  7. package/dist/AccordionButtonDeprecated/ButtonDeprecated/index.d.ts +2 -2
  8. package/dist/AccordionButtonDeprecated/ButtonDeprecated/index.js +1 -1
  9. package/dist/AccordionButtonDeprecated/ButtonDeprecated/styles/index.module.scss +5 -5
  10. package/dist/AccordionButtonDeprecated/ButtonDeprecated/styles/mixins.scss +5 -5
  11. package/dist/AccordionButtonDeprecated/ButtonDeprecated/styles/variables.scss +23 -22
  12. package/dist/AccordionButtonDeprecated/styles.module.scss +6 -8
  13. package/dist/Alert/elements.d.ts +2 -2
  14. package/dist/Anchor/index.d.ts +19 -9
  15. package/dist/Anchor/index.js +9 -6
  16. package/dist/BarChart/BarRow/elements.d.ts +47 -45
  17. package/dist/BarChart/utils/hooks.d.ts +2 -2
  18. package/dist/BarChart/utils/hooks.js +3 -1
  19. package/dist/Box/GridBox.d.ts +1 -0
  20. package/dist/Box/GridBox.js +1 -1
  21. package/dist/Box/props.d.ts +1 -1
  22. package/dist/Breadcrumbs/index.d.ts +5 -5
  23. package/dist/Breadcrumbs/index.js +2 -2
  24. package/dist/Button/CTAButton.d.ts +2 -2
  25. package/dist/Button/FillButton.d.ts +4 -4
  26. package/dist/Button/IconButton.d.ts +4 -4
  27. package/dist/Button/StrokeButton.d.ts +4 -4
  28. package/dist/Button/TextButton.d.ts +4 -4
  29. package/dist/Button/shared/InlineIconButton.d.ts +2 -2
  30. package/dist/Button/shared/styles.d.ts +3 -3
  31. package/dist/Button/shared/types.d.ts +1 -1
  32. package/dist/ButtonBase/ButtonBase.d.ts +9 -4
  33. package/dist/ButtonBase/ButtonBase.js +11 -4
  34. package/dist/Card/elements.d.ts +109 -103
  35. package/dist/Card/styles.d.ts +8 -8
  36. package/dist/Coachmark/index.d.ts +1 -1
  37. package/dist/ConnectedForm/ConnectedForm.d.ts +1 -1
  38. package/dist/ConnectedForm/ConnectedFormGroup.js +4 -3
  39. package/dist/ConnectedForm/utils.d.ts +1 -1
  40. package/dist/ConnectedForm/utils.js +1 -1
  41. package/dist/DatePicker/DatePickerInput/index.d.ts +1 -1
  42. package/dist/Disclosure/elements.d.ts +18 -12
  43. package/dist/FeatureShimmer/index.js +1 -1
  44. package/dist/Form/SelectDropdown/SelectDropdown.js +1 -1
  45. package/dist/Form/SelectDropdown/elements/containers.js +1 -1
  46. package/dist/Form/SelectDropdown/elements/controls.js +2 -2
  47. package/dist/Form/SelectDropdown/elements/multi-value.js +2 -2
  48. package/dist/Form/SelectDropdown/types/internal.d.ts +2 -2
  49. package/dist/Form/SelectDropdown/utils.js +2 -1
  50. package/dist/Form/elements/Form.d.ts +15 -15
  51. package/dist/Form/elements/FormGroup.d.ts +1 -1
  52. package/dist/Form/styles/Checkbox-styles.d.ts +1 -1
  53. package/dist/GridForm/GridFormButtons/index.d.ts +4 -4
  54. package/dist/List/ListProvider.d.ts +1 -1
  55. package/dist/List/elements.d.ts +44 -42
  56. package/dist/Menu/MenuItem.js +10 -6
  57. package/dist/Menu/elements.d.ts +2 -2
  58. package/dist/Modals/Dialog.js +6 -2
  59. package/dist/Modals/Modal.js +5 -2
  60. package/dist/Modals/elements.d.ts +1 -1
  61. package/dist/Pagination/AnimatedPaginationButtons.d.ts +31 -29
  62. package/dist/Pagination/EllipsisButton.d.ts +2 -2
  63. package/dist/Pagination/PaginationButton.d.ts +6 -6
  64. package/dist/Pagination/utils.d.ts +31 -29
  65. package/dist/Pagination/utils.js +14 -11
  66. package/dist/Popover/Popover.js +6 -6
  67. package/dist/Popover/types.d.ts +4 -3
  68. package/dist/PopoverContainer/PopoverContainer.js +9 -9
  69. package/dist/PopoverContainer/hooks.d.ts +16 -4
  70. package/dist/PopoverContainer/hooks.js +50 -27
  71. package/dist/PopoverContainer/types.d.ts +2 -1
  72. package/dist/Tabs/TabButton.d.ts +2 -2
  73. package/dist/Tabs/TabNavLink.d.ts +2 -2
  74. package/dist/Tag/elements.d.ts +14 -8
  75. package/dist/Tag/index.js +1 -1
  76. package/dist/Tip/InfoTip/InfoTipButton.d.ts +4 -4
  77. package/dist/Tip/PreviewTip/elements.d.ts +12 -6
  78. package/dist/Tip/__tests__/helpers.d.ts +1 -1
  79. package/dist/Tip/shared/FloatingTip.js +2 -2
  80. package/dist/Tip/shared/types.d.ts +2 -2
  81. package/dist/Tip/shared/utils.js +1 -1
  82. package/dist/Video/styles/vds_base_theme.scss +1 -3
  83. package/dist/utils/nullish.d.ts +10 -0
  84. package/dist/utils/nullish.js +11 -0
  85. package/dist/utils/react.js +4 -2
  86. package/package.json +10 -10
  87. package/dist/Typography/styles/_variables.scss +0 -54
@@ -8,13 +8,12 @@ colors:
8
8
  hyper-400: '#5533FF'
9
9
  navy-900: '#0A0D1C'
10
10
  navy-800: '#10162F'
11
- navy-700: 'rgba(16, 22, 47, 0.86)'
12
- navy-600: 'rgba(16, 22, 47, 0.75)'
13
- navy-500: 'rgba(16, 22, 47, 0.63)'
14
- navy-400: 'rgba(16, 22, 47, 0.47)'
15
- navy-300: 'rgba(16, 22, 47, 0.28)'
16
- navy-200: 'rgba(16, 22, 47, 0.12)'
17
- navy-100: 'rgba(16, 22, 47, 0.04)'
11
+ navy-700: '#31374C'
12
+ navy-600: '#4C5063'
13
+ navy-500: '#686C7C'
14
+ navy-300: '#BCBEC5'
15
+ navy-200: '#E2E3E6'
16
+ navy-100: '#F5F6F7'
18
17
  yellow-500: '#FFD300'
19
18
  yellow-400: '#CCA900'
20
19
  yellow-0: '#FFFAE5'
@@ -78,6 +77,8 @@ typography:
78
77
  fontSize: '2.125rem'
79
78
  fontWeight: '700'
80
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'
81
82
  monospace:
82
83
  fontFamily: 'Monaco, Menlo, "Ubuntu Mono", "Droid Sans Mono", Consolas, monospace'
83
84
  rounded:
@@ -201,24 +202,24 @@ Codecademy communicates **logic with personality** — structured and trustworth
201
202
 
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.
203
204
 
204
- | Theme | Use case | Base font | Dark mode |
205
- | ------------- | ------------------------------- | --------------------- | -------------- |
206
- | **Core** | Codecademy (default) | Apercu | ✓ light + dark |
207
- | **Admin** | Codecademy admin tools | Apercu | ✓ light + dark |
208
- | **Platform** | Codecademy learning environment | Apercu | ✓ light + dark |
209
- | **LX Studio** | LX Studio application | Skillsoft Text / Sans | light only |
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 |
210
211
 
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.
212
213
 
213
- **Font licensing**: Apercu is licensed for codecademy.com only. LX Studio and Percipio use Skillsoft Text and Skillsoft Sans.
214
+ **Font licensing**: Apercu is licensed for codecademy.com only. LX Studio uses Hanken Grotesk.
214
215
 
215
- For Percipio projects, use `DESIGN.Percipio.md` from the same package instead. For LX Studio, use `DESIGN.LXStudio.md`.
216
+ For Percipio projects, use `DESIGN.Percipio.md` from the same package instead.
216
217
 
217
218
  ### LX Studio theme overrides
218
219
 
219
220
  LX Studio extends Core with these differences:
220
221
 
221
- **Font**: `base`Skillsoft Text; `accent` → Skillsoft Sans (no Apercu, no Suisse). Title weight is **500**, not Core's 700.
222
+ **Font**: All families `"Hanken Grotesk"` (no Apercu, no Suisse).
222
223
 
223
224
  **Border radii** (all values shift up one step):
224
225
 
@@ -230,15 +231,15 @@ LX Studio extends Core with these differences:
230
231
 
231
232
  **Semantic color overrides (light mode)**:
232
233
 
233
- | Token | Core value | LX Studio value |
234
- | -------------------- | ----------- | ------------------- |
235
- | `primary` | `hyper-500` | `sapphire` |
236
- | `primary-hover` | `hyper-400` | `navy-800` |
237
- | `feedback-success` | `green-700` | `lxStudioSuccess` |
238
- | `background-primary` | `beige` | `lxStudioBgPrimary` |
239
- | `shadow-primary` | navy-800 | navy-200 |
240
- | `border-primary` | navy-800 | navy-400 |
241
- | `border-disabled` | navy-500 | navy-300 |
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 |
242
243
 
243
244
  ---
244
245
 
@@ -248,55 +249,55 @@ Use these token names when specifying colors in designs. They resolve to the cor
248
249
 
249
250
  ### Text
250
251
 
251
- | Token | Light | Dark | Use for |
252
- | ---------------- | --------------- | ------------ | --------------------------- |
253
- | `text` | `navy-800` | `white` | Default body and UI text |
254
- | `text-accent` | `navy-900` | `beige` | Stronger emphasis text |
255
- | `text-secondary` | navy-800 at 75% | white at 65% | Supporting / secondary copy |
256
- | `text-disabled` | navy-800 at 63% | white at 50% | Disabled state labels |
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 |
257
258
 
258
259
  ### Background
259
260
 
260
- | Token | Light | Dark | Use for |
261
- | --------------------- | --------------- | ------------ | --------------------------------- |
262
- | `background` | `white` | `navy-800` | Default page/component background |
263
- | `background-primary` | `beige` | `navy-900` | Slightly elevated surfaces |
264
- | `background-contrast` | `white` | `black` | Maximum contrast surface |
265
- | `background-selected` | navy-800 at 4% | white at 4% | Selected row / item |
266
- | `background-hover` | navy-800 at 12% | white at 9% | Hover state overlay |
267
- | `background-disabled` | navy-800 at 12% | white at 9% | Disabled surface |
268
- | `background-success` | `green-0` | `green-900` | Success state container |
269
- | `background-warning` | `yellow-0` | `yellow-900` | Warning state container |
270
- | `background-error` | `red-0` | `red-900` | Error state container |
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 |
271
272
 
272
273
  ### Interactive
273
274
 
274
- | Token | Light | Dark | Use for |
275
- | ----------------- | --------------- | ------------ | ------------------------------------ |
276
- | `primary` | `hyper-500` | `yellow-500` | Primary CTA, links, focus rings |
277
- | `primary-hover` | `hyper-400` | `yellow-400` | Hover state of primary interactive |
278
- | `primary-inverse` | `yellow-500` | `hyper-500` | Primary on a colored background |
279
- | `secondary` | `navy-800` | `white` | Secondary CTA, ghost buttons |
280
- | `secondary-hover` | navy-800 at 86% | white at 80% | Hover state of secondary interactive |
281
- | `danger` | `red-500` | `red-300` | Destructive actions, error states |
282
- | `danger-hover` | `red-600` | `red-400` | Hover on danger interactive |
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 |
283
284
 
284
285
  ### Border
285
286
 
286
- | Token | Light | Dark | Use for |
287
- | ------------------ | --------------- | ------------ | -------------------------- |
288
- | `border-primary` | `navy-800` | `white` | Strong borders, dividers |
289
- | `border-secondary` | navy-800 at 75% | white at 65% | Medium-weight borders |
290
- | `border-tertiary` | navy-800 at 28% | white at 20% | Subtle borders, separators |
291
- | `border-disabled` | navy-800 at 63% | white at 50% | Disabled input borders |
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 |
292
293
 
293
294
  ### Feedback
294
295
 
295
- | Token | Light | Dark | Use for |
296
- | ------------------ | ----------- | ----------- | -------------------------------- |
297
- | `feedback-error` | `red-600` | `red-300` | Error messages, validation |
298
- | `feedback-success` | `green-700` | `green-400` | Success messages, confirmations |
299
- | `feedback-warning` | `yellow` | `yellow-0` | Warning messages, caution states |
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 |
300
301
 
301
302
  ### Shadow
302
303
 
@@ -313,32 +314,32 @@ All colors available as static tokens regardless of color mode. Use these only w
313
314
 
314
315
  ### Core Palette
315
316
 
316
- | Name | Weights available | Notes |
317
- | --------------- | ---------------------------- | -------------------------------------------------------------------------- |
318
- | `navy` | 100–900 | 100–700 are rgba transparencies of `navy-800`; 800 and 900 are solid |
319
- | `white` | 100–700 | rgba transparencies of `white` (no solid white weight — use `white` token) |
320
- | `blue` | 0, 100, 300, 400, 500, 800 | named alias `blue` maps to `blue-500` |
321
- | `hyper` | 400, 500 | named alias `hyper` maps to `hyper-500` |
322
- | `green` | 0, 100, 400, 700, 900 | named alias `green` maps to `green-700` |
323
- | `yellow` | 0, 400, 500, 900 | named alias `yellow` maps to `yellow-500` |
324
- | `red` | 0, 300, 400, 500, 600, 900 | named alias `red` maps to `red-500` |
325
- | `gray` | 100, 200, 300, 600, 800, 900 | |
326
- | `pink` | 0, 400 | named alias `pink` maps to `pink-400` |
327
- | `orange` | 100, 500 | named alias `orange` maps to `orange-500` |
328
- | `beige` | 100 (alias: `beige`) | solid `beige` token |
329
- | `black` | — | `black` token |
330
- | `white` (solid) | — | `white` token |
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` |
331
332
 
332
333
  **Named aliases** (shorthand for common weights):
333
334
  `beige`, `blue`, `green`, `hyper`, `lightBlue`, `lightGreen`, `navy`, `orange`, `paleBlue`, `paleGreen`, `palePink`, `paleRed`, `paleYellow`, `pink`, `red`, `yellow`, `black`, `white`
334
335
 
335
336
  ### Platform-only additions
336
337
 
337
- `lightBeige`, `gold`, `teal`, `purple` (Platform theme palette)
338
+ `lightBeige` (`#FFFBF8`), `gold` (`#8A7300`), `teal` (`#006D82`), `purple` (`#B3CCFF`)
338
339
 
339
340
  ### LX Studio additions
340
341
 
341
- `sapphire`, `lxStudioSuccess`, `lxStudioBgPrimary` (LX Studio theme palette)
342
+ `lxStudioPurple` (`#5628FE`), `lxStudioPurpleHover` (`#7955FC`), `lxStudioSuccess` (`#06844F`)
342
343
 
343
344
  ---
344
345
 
@@ -348,12 +349,12 @@ All colors available as static tokens regardless of color mode. Use these only w
348
349
 
349
350
  | Token | Core / Admin / Platform | LX Studio | Use for |
350
351
  | ----------- | -------------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------ |
351
- | `base` | Apercu Pro (CSS: `Apercu`) | Skillsoft Text | All default UI text, headlines, body copy |
352
- | `accent` | Suisse Intl Mono (CSS: `Suisse`); falls back to `Apercu` | Skillsoft Sans | Code, captions, labels, lists, technical context |
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 |
353
354
  | `monospace` | Monaco, Menlo, Ubuntu Mono, Droid Sans Mono, Consolas | Monaco, Menlo, Ubuntu Mono, Droid Sans Mono, Consolas | Code editor contexts |
354
355
  | `system` | System UI fonts | System UI fonts | Performance-critical surfaces |
355
356
 
356
- **Apercu is licensed for codecademy.com only.** LX Studio uses Skillsoft Text (`base`) and Skillsoft Sans (`accent`) with title weight 500.
357
+ **Apercu is licensed for codecademy.com only.** LX Studio uses Hanken Grotesk for both `base` and `accent`.
357
358
 
358
359
  ### Rules
359
360
 
@@ -602,8 +603,8 @@ Quick color/token reference for generating or specifying UI:
602
603
 
603
604
  | Scenario | Tokens |
604
605
  | ---------------------- | ----------------------------------------------------------------------------------------------------- |
605
- | Primary button (light) | `bg: primary`, `color: white`, `hover: primary-hover` |
606
- | Primary button (dark) | `bg: primary`, `color: text`, `hover: primary-hover` |
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)` |
607
608
  | Body text | `color: text`, `font: base (Apercu Pro)`, `size: 16px`, `weight: 400`, `lineHeight: base (1.5)` |
608
609
  | Headline | `color: text-accent`, `font: base`, `size: 34–64px`, `weight: title (700)`, `lineHeight: title (1.2)` |
609
610
  | Caption / label | `color: text-secondary`, `font: accent (Suisse Int'l Mono)`, `size: 14px` |
@@ -4,7 +4,8 @@ name: LX Studio Design System
4
4
  description: Design tokens for the Skillsoft LX Studio authoring platform.
5
5
  colors:
6
6
  # LX Studio additions — custom brand tokens
7
- sapphire: '#1C50BB'
7
+ lxStudioPurple: '#5628FE'
8
+ lxStudioPurpleHover: '#7955FC'
8
9
  lxStudioSuccess: '#06844F'
9
10
  lxStudioBgPrimary: '#FAFBFC'
10
11
  # core palette — referenced by semantic aliases below
@@ -12,13 +13,13 @@ colors:
12
13
  hyper-400: '#5533FF'
13
14
  navy-900: '#0A0D1C'
14
15
  navy-800: '#10162F'
15
- navy-700: 'rgba(16, 22, 47, 0.86)'
16
- navy-600: 'rgba(16, 22, 47, 0.75)'
17
- navy-500: 'rgba(16, 22, 47, 0.63)'
18
- navy-400: 'rgba(16, 22, 47, 0.47)'
19
- navy-300: 'rgba(16, 22, 47, 0.28)'
20
- navy-200: 'rgba(16, 22, 47, 0.12)'
21
- navy-100: 'rgba(16, 22, 47, 0.04)'
16
+ navy-700: '#31374C'
17
+ navy-600: '#4C5063'
18
+ navy-500: '#686C7C'
19
+ navy-400: '#8F919D'
20
+ navy-300: '#BCBEC5'
21
+ navy-200: '#E2E3E6'
22
+ navy-100: '#F5F6F7'
22
23
  yellow-500: '#FFD300'
23
24
  yellow-0: '#FFFAE5'
24
25
  green-700: '#008A27'
@@ -41,8 +42,8 @@ colors:
41
42
  background-success: '{colors.green-0}'
42
43
  background-warning: '{colors.yellow-0}'
43
44
  background-error: '{colors.red-0}'
44
- primary: '{colors.sapphire}'
45
- primary-hover: '{colors.navy-800}'
45
+ primary: '{colors.lxStudioPurple}'
46
+ primary-hover: '{colors.lxStudioPurpleHover}'
46
47
  primary-inverse: '{colors.yellow-500}'
47
48
  secondary: '{colors.navy-800}'
48
49
  secondary-hover: '{colors.navy-700}'
@@ -59,19 +60,19 @@ colors:
59
60
  shadow-secondary: '{colors.navy-600}'
60
61
  typography:
61
62
  base:
62
- fontFamily: '"Skillsoft Text", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
63
+ fontFamily: '"Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
63
64
  fontSize: '1rem'
64
65
  fontWeight: '400'
65
66
  lineHeight: '1.5'
66
67
  accent:
67
- fontFamily: '"Skillsoft Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
68
+ fontFamily: '"Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
68
69
  fontSize: '0.875rem'
69
70
  fontWeight: '400'
70
71
  lineHeight: '1.5'
71
72
  title:
72
- fontFamily: '"Skillsoft Text", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
73
+ fontFamily: '"Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
73
74
  fontSize: '2.125rem'
74
- fontWeight: '500'
75
+ fontWeight: '700'
75
76
  lineHeight: '1.2'
76
77
  monospace:
77
78
  fontFamily: 'Monaco, Menlo, "Ubuntu Mono", "Droid Sans Mono", Consolas, monospace'
@@ -140,9 +141,9 @@ LX Studio communicates **modern professional craft** — clean, precise, and too
140
141
 
141
142
  - Light mode only — no dark mode support
142
143
  - Larger border radii than Core give the UI a softer, more modern feel
143
- - Brand blue (`sapphire` / `primary`) drives CTAs, buttons, and links
144
+ - Brand purple (`lxStudioPurple`) via `primary` drives CTAs, buttons, links, checkboxes, and toggles
144
145
  - Shadows are soft (navy-200) rather than hard (navy-800 in Core light mode)
145
- - Skillsoft Text and Skillsoft Sans replace Apercu and Suisse across all font roles
146
+ - Hanken Grotesk replaces Apercu and Suisse across all font roles
146
147
 
147
148
  ---
148
149
 
@@ -150,9 +151,9 @@ LX Studio communicates **modern professional craft** — clean, precise, and too
150
151
 
151
152
  LX Studio uses a single Gamut theme — light mode only.
152
153
 
153
- | Theme | Use case | Base font | Dark mode |
154
- | ------------- | -------------------------------------- | --------------------- | ---------- |
155
- | **LX Studio** | Skillsoft LX Studio authoring platform | Skillsoft Text / Sans | light only |
154
+ | Theme | Use case | Base font | Dark mode |
155
+ | ------------- | -------------------------------------- | -------------- | ---------- |
156
+ | **LX Studio** | Skillsoft LX Studio authoring platform | Hanken Grotesk | light only |
156
157
 
157
158
  The active theme is set at the app root via `<GamutProvider theme={lxStudioTheme}>`.
158
159
 
@@ -164,64 +165,64 @@ Use these token names when specifying colors. LX Studio is light mode only — t
164
165
 
165
166
  ### Text
166
167
 
167
- | Token | Resolves to | Use for |
168
- | ---------------- | ----------- | --------------------------- |
169
- | `text` | `navy-800` | Default body and UI text |
170
- | `text-accent` | `navy-900` | Stronger emphasis text |
171
- | `text-secondary` | `navy-600` | Supporting / secondary copy |
172
- | `text-disabled` | `navy-500` | Disabled state labels |
168
+ | Token | Value | Use for |
169
+ | ---------------- | -------------------- | --------------------------- |
170
+ | `text` | `#10162F` (navy-800) | Default body and UI text |
171
+ | `text-accent` | `#0A0D1C` (navy-900) | Stronger emphasis text |
172
+ | `text-secondary` | `#4C5063` (navy-600) | Supporting / secondary copy |
173
+ | `text-disabled` | `#686C7C` (navy-500) | Disabled state labels |
173
174
 
174
175
  ### Background
175
176
 
176
- | Token | Resolves to | Use for |
177
- | --------------------- | ------------------- | --------------------------------- |
178
- | `background` | `white` | Default page/component background |
179
- | `background-primary` | `lxStudioBgPrimary` | Slightly elevated surfaces |
180
- | `background-contrast` | `white` | Maximum contrast surface |
181
- | `background-selected` | `navy-100` | Selected row / item |
182
- | `background-hover` | `navy-200` | Hover state overlay |
183
- | `background-disabled` | `navy-200` | Disabled surface |
184
- | `background-success` | `green-0` | Success state container |
185
- | `background-warning` | `yellow-0` | Warning state container |
186
- | `background-error` | `red-0` | Error state container |
177
+ | Token | Value | Use for |
178
+ | --------------------- | ----------------------------- | --------------------------------- |
179
+ | `background` | `#ffffff` | Default page/component background |
180
+ | `background-primary` | `#FAFBFC` (lxStudioBgPrimary) | Slightly elevated surfaces |
181
+ | `background-contrast` | `#ffffff` | Maximum contrast surface |
182
+ | `background-selected` | `#F5F6F7` (navy-100) | Selected row / item |
183
+ | `background-hover` | `#E2E3E6` (navy-200) | Hover state overlay |
184
+ | `background-disabled` | `#E2E3E6` (navy-200) | Disabled surface |
185
+ | `background-success` | `#F5FFE3` (green-0) | Success state container |
186
+ | `background-warning` | `#FFFAE5` (yellow-0) | Warning state container |
187
+ | `background-error` | `#FBF1F0` (red-0) | Error state container |
187
188
 
188
189
  ### Interactive
189
190
 
190
- | Token | Resolves to | Use for |
191
- | ----------------- | ------------ | ------------------------------------ |
192
- | `primary` | `sapphire` | Primary CTA, links, focus rings |
193
- | `primary-hover` | `navy-800` | Hover state of primary interactive |
194
- | `primary-inverse` | `yellow-500` | Primary on a colored background |
195
- | `secondary` | `navy-800` | Secondary CTA, ghost buttons |
196
- | `secondary-hover` | `navy-700` | Hover state of secondary interactive |
197
- | `danger` | `red-500` | Destructive actions, error states |
198
- | `danger-hover` | `red-600` | Hover on danger interactive |
191
+ | Token | Value | Use for |
192
+ | ----------------- | ------------------------------- | ------------------------------------ |
193
+ | `primary` | `#5628FE` (lxStudioPurple) | Primary CTA, links, focus rings |
194
+ | `primary-hover` | `#7955FC` (lxStudioPurpleHover) | Hover state of primary interactive |
195
+ | `primary-inverse` | `#FFD300` (yellow-500) | Primary on a colored background |
196
+ | `secondary` | `#10162F` (navy-800) | Secondary CTA, ghost buttons |
197
+ | `secondary-hover` | `#31374C` (navy-700) | Hover state of secondary interactive |
198
+ | `danger` | `#E91C11` (red-500) | Destructive actions, error states |
199
+ | `danger-hover` | `#BE1809` (red-600) | Hover on danger interactive |
199
200
 
200
201
  ### Border
201
202
 
202
- | Token | Resolves to | Use for |
203
- | ------------------ | ----------- | ------------------------------- |
204
- | `border-primary` | `navy-400` | Standard input and card borders |
205
- | `border-secondary` | `navy-600` | Medium-weight borders |
206
- | `border-tertiary` | `navy-800` | Strong structural borders |
207
- | `border-disabled` | `navy-300` | Disabled input borders |
203
+ | Token | Value | Use for |
204
+ | ------------------ | -------------------- | ------------------------------- |
205
+ | `border-primary` | `#8F919D` (navy-400) | Standard input and card borders |
206
+ | `border-secondary` | `#4C5063` (navy-600) | Medium-weight borders |
207
+ | `border-tertiary` | `#10162F` (navy-800) | Strong structural borders |
208
+ | `border-disabled` | `#BCBEC5` (navy-300) | Disabled input borders |
208
209
 
209
210
  LX Studio's `border-primary` is mid-gray (navy-400) rather than Core's near-black navy-800 — borders are softer and less prominent.
210
211
 
211
212
  ### Feedback
212
213
 
213
- | Token | Resolves to | Use for |
214
- | ------------------ | ----------------- | -------------------------------- |
215
- | `feedback-error` | `red-600` | Error messages, validation |
216
- | `feedback-success` | `lxStudioSuccess` | Success messages, confirmations |
217
- | `feedback-warning` | `yellow-500` | Warning messages, caution states |
214
+ | Token | Value | Use for |
215
+ | ------------------ | --------------------------- | -------------------------------- |
216
+ | `feedback-error` | `#BE1809` (red-600) | Error messages, validation |
217
+ | `feedback-success` | `#06844F` (lxStudioSuccess) | Success messages, confirmations |
218
+ | `feedback-warning` | `#FFD300` (yellow-500) | Warning messages, caution states |
218
219
 
219
220
  ### Shadow
220
221
 
221
- | Token | Resolves to |
222
- | ------------------ | ----------- |
223
- | `shadow-primary` | `navy-200` |
224
- | `shadow-secondary` | `navy-600` |
222
+ | Token | Value |
223
+ | ------------------ | -------------------- |
224
+ | `shadow-primary` | `#E2E3E6` (navy-200) |
225
+ | `shadow-secondary` | `#4C5063` (navy-600) |
225
226
 
226
227
  LX Studio shadows are soft — use `shadow-primary` for standard elevated surfaces. This matches Percipio's shadow weight, not Core's hard navy-800 shadow.
227
228
 
@@ -229,13 +230,14 @@ LX Studio shadows are soft — use `shadow-primary` for standard elevated surfac
229
230
 
230
231
  ## LX Studio Color Palette
231
232
 
232
- LX Studio adds named colors to the core palette. Use semantic aliases in code, not these raw names.
233
+ LX Studio adds four named colors to the core palette. Use semantic aliases in code, not these raw names.
233
234
 
234
- | Palette token | Semantic alias(es) |
235
- | ------------------- | -------------------- |
236
- | `sapphire` | `primary` |
237
- | `lxStudioSuccess` | `feedback-success` |
238
- | `lxStudioBgPrimary` | `background-primary` |
235
+ | Named color | Value | Mapped to |
236
+ | --------------------- | --------- | -------------------- |
237
+ | `lxStudioPurple` | `#5628FE` | `primary` |
238
+ | `lxStudioPurpleHover` | `#7955FC` | `primary-hover` |
239
+ | `lxStudioSuccess` | `#06844F` | `feedback-success` |
240
+ | `lxStudioBgPrimary` | `#FAFBFC` | `background-primary` |
239
241
 
240
242
  The full core swatch palette (navy, hyper, blue, green, yellow, red, etc.) is also available. Raw swatches should only be used for fixed colors that must not adapt (illustrations, data viz, etc.).
241
243
 
@@ -245,31 +247,31 @@ The full core swatch palette (navy, hyper, blue, green, yellow, red, etc.) is al
245
247
 
246
248
  ### Typefaces
247
249
 
248
- LX Studio uses **Skillsoft Text** for body and headlines and **Skillsoft Sans** for accent UI. There is no Apercu and no Suisse.
250
+ LX Studio uses **Hanken Grotesk** for all font roles. There is no Apercu and no Suisse.
249
251
 
250
- | Token | Font | Use for |
251
- | ----------- | ----------------------------------------------------- | ----------------------------------------- |
252
- | `base` | `"Skillsoft Text"`, sans-serif fallback | All default UI text, headlines, body copy |
253
- | `accent` | `"Skillsoft Sans"`, sans-serif fallback | Labels, captions, accent UI |
254
- | `monospace` | Monaco, Menlo, Ubuntu Mono, Droid Sans Mono, Consolas | Code editor contexts |
255
- | `system` | System UI fonts | Performance-critical surfaces |
252
+ | Token | Font | Use for |
253
+ | ----------- | ----------------------------------------------------- | --------------------------------------------------------------- |
254
+ | `base` | `"Hanken Grotesk"`, sans-serif fallback | All default UI text, headlines, body copy |
255
+ | `accent` | `"Hanken Grotesk"`, sans-serif fallback | Labels, captions, technical context (same as base in LX Studio) |
256
+ | `monospace` | Monaco, Menlo, Ubuntu Mono, Droid Sans Mono, Consolas | Code editor contexts |
257
+ | `system` | System UI fonts | Performance-critical surfaces |
256
258
 
257
- Skillsoft fonts are loaded via Gamut's asset provider (same stack as Percipio).
259
+ Hanken Grotesk is served from `https://www.codecademy.com/gamut/` in four variants: regular, italic, bold, bold-italic.
258
260
 
259
261
  ### Rules
260
262
 
261
- - **Skillsoft Text Medium (500)** for headlines, sub-headlines, CTAs, and buttons — use `fontWeight="title"`, not literal `700`.
262
- - **Skillsoft Text Regular (400)** for body text, UI labels, and menu items.
263
+ - **Hanken Grotesk Bold (700)** for headlines, sub-headlines, CTAs, and buttons.
264
+ - **Hanken Grotesk Regular (400)** for body text, UI labels, and menu items.
263
265
  - Text is **left-aligned** by default. Center-align only for short marketing headlines. Never right-align.
264
266
  - Do not adjust letter-spacing.
265
- - Skillsoft Sans is the accent face; Skillsoft Text is used for `base` and title styles.
267
+ - No separate accent typeface Hanken Grotesk is used uniformly for `base` and `accent`.
266
268
 
267
269
  ### Font weight scale
268
270
 
269
- | Token | Value | Use |
270
- | ------- | ------- | ---------------------------------------------------- |
271
- | `base` | 400 | Body text, UI labels |
272
- | `title` | **500** | Headlines, CTAs, buttons _(differs from Core's 700)_ |
271
+ | Token | Value | Use |
272
+ | ------- | ----- | ------------------------ |
273
+ | `base` | 400 | Body text, UI labels |
274
+ | `title` | 700 | Headlines, CTAs, buttons |
273
275
 
274
276
  ### Font size scale
275
277
 
@@ -369,9 +371,9 @@ Same component library as Codecademy — all atoms, molecules, and organisms app
369
371
 
370
372
  Key LX Studio-specific visual differences:
371
373
 
372
- - `FillButton` uses `primary` (`sapphire`) instead of Core `hyper-500`
373
- - `FillButton` hover uses `primary-hover` (`navy-800`) — darker on hover
374
- - `Checkbox` / `Toggle` use palette `hyper-500` (not `primary`)
374
+ - `FillButton` uses `#5628FE` (lxStudioPurple) instead of hyper-500
375
+ - `FillButton` hover shifts to `#7955FC` (lxStudioPurpleHover) — lighter, not darker, on hover
376
+ - `Checkbox` / `Toggle` use `hyper-500` (`#3A10E5`) — not the brand purple
375
377
  - All interactive elements have `borderRadius: md` (8px) instead of Core's 4px
376
378
  - `Card` shadows use navy-200 (soft) rather than navy-800 (hard)
377
379
  - No `Card-beige` variant — LX Studio `background-primary` is off-white, not beige
@@ -383,15 +385,15 @@ Key LX Studio-specific visual differences:
383
385
  ### Colors
384
386
 
385
387
  - **Do** use semantic color aliases (`primary`, `text`, `background`, etc.) — never hardcode hex values.
386
- - **Do** use `primary` (resolves to palette `sapphire`) for buttons and links.
388
+ - **Do** use `lxStudioPurple` (`#5628FE`) via `primary` for buttons and links.
387
389
  - **Don't** attempt dark mode — LX Studio is light only.
388
390
  - **Don't** use the Percipio or Codecademy primary blue/hyper colors directly; go through semantic aliases.
389
391
 
390
392
  ### Typography
391
393
 
392
- - **Do** use `fontWeight="title"` (500) for headlines, CTAs, and buttons.
394
+ - **Do** use Hanken Grotesk Bold (700) for headlines, CTAs, and buttons.
393
395
  - **Do** keep body text at 150–175% line height for readability.
394
- - **Don't** use Apercu, Suisse, or Hanken Grotesk LX Studio uses Skillsoft Text and Skillsoft Sans.
396
+ - **Don't** use Apercu or Suissethose fonts are not available in LX Studio.
395
397
  - **Don't** right-align or center-align body paragraphs.
396
398
  - **Don't** adjust letter-spacing.
397
399
 
@@ -408,27 +410,27 @@ Key LX Studio-specific visual differences:
408
410
 
409
411
  Quick color/token reference for generating or specifying LX Studio UI:
410
412
 
411
- | Scenario | Tokens |
412
- | ---------------- | -------------------------------------------------------------------------------------------------- |
413
- | Primary button | `bg: primary`, `color: white`, `hover: primary-hover`, `borderRadius: md` |
414
- | Body text | `color: text`, `font: base`, `size: 16`, `weight: 400`, `lineHeight: base` |
415
- | Headline | `color: text-accent`, `font: base`, `size: 34–64`, `weight: title`, `lineHeight: title` |
416
- | Secondary text | `color: text-secondary` |
417
- | Disabled text | `color: text-disabled` |
418
- | Elevated surface | `bg: background-primary` |
419
- | Card default | `bg: background`, `borderRadius: none` — add `isInteractive` for hover shadow + `borderRadius: md` |
420
- | Error state | `color: feedback-error`, `bg: background-error`, `borderColor: danger` |
421
- | Success state | `color: feedback-success`, `bg: background-success` |
422
- | Warning state | `color: feedback-warning`, `bg: background-warning` |
423
- | Disabled state | `color: text-disabled`, `bg: background-disabled`, `borderColor: border-disabled` |
413
+ | Scenario | Tokens |
414
+ | ---------------- | ------------------------------------------------------------------------------------------------------------------ |
415
+ | Primary button | `bg: primary (#5628FE)`, `color: white`, `hover: primary-hover (#7955FC)`, `borderRadius: md (8px)` |
416
+ | Body text | `color: text (#10162F)`, `font: Hanken Grotesk`, `size: 16px`, `weight: 400`, `lineHeight: base (1.5)` |
417
+ | Headline | `color: text-accent (#0A0D1C)`, `font: Hanken Grotesk`, `size: 34–64px`, `weight: 700`, `lineHeight: title (1.2)` |
418
+ | Secondary text | `color: text-secondary (#4C5063)` |
419
+ | Disabled text | `color: text-disabled (#686C7C)` |
420
+ | Elevated surface | `bg: background-primary (#FAFBFC)` |
421
+ | Card default | `bg: background (#ffffff)`, `borderRadius: none` — add `isInteractive` for hover shadow + `borderRadius: md (8px)` |
422
+ | Error state | `color: feedback-error (#BE1809)`, `bg: background-error (#FBF1F0)`, `border: danger` |
423
+ | Success state | `color: feedback-success (#06844F)`, `bg: background-success (#F5FFE3)` |
424
+ | Warning state | `color: feedback-warning (#FFD300)`, `bg: background-warning (#FFFAE5)` |
425
+ | Disabled state | `color: text-disabled (#686C7C)`, `bg: background-disabled (#E2E3E6, navy-200)`, `border: border-disabled` |
424
426
 
425
427
  ### Component token cheatsheet
426
428
 
427
429
  ```
428
- FillButton → bg: primary, color: white, hover: primary-hover, borderRadius: md
429
- StrokeButton → bg: transparent, borderColor: secondary
430
- Checkbox/Toggle → palette hyper-500, hover hyper-400, borderRadius: sm
431
- Card → bg: background, shadow: shadow-primary (navy-200, soft), radius: none
430
+ FillButton → bg: primary (#5628FE), color: white, hover: primary-hover (#7955FC), radius: 8px
431
+ StrokeButton → bg: transparent, border: secondary (#10162F)
432
+ Checkbox/Toggle → primary (#5628FE), hover: primary-hover (#7955FC), radius: 4px
433
+ Card → bg: background, shadow: shadow-primary (#E2E3E6, navy-200, soft), radius: none
432
434
  Alert (error) → uses feedback-error + background-error
433
435
  Alert (success) → uses feedback-success + background-success
434
436
  Alert (warning) → uses feedback-warning + background-warning