@codecademy/gamut 68.7.1-alpha.f618c1.0 → 68.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/agent-tools/DESIGN.Codecademy.md +90 -120
  2. package/agent-tools/DESIGN.LXStudio.md +127 -132
  3. package/agent-tools/DESIGN.Percipio.md +129 -134
  4. package/agent-tools/DESIGN.md +12 -1
  5. package/bin/lib/claude.mjs +5 -14
  6. package/bin/lib/cursor.mjs +1 -4
  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 +22 -23
  12. package/dist/AccordionButtonDeprecated/styles.module.scss +8 -6
  13. package/dist/Alert/elements.d.ts +2 -2
  14. package/dist/Anchor/index.d.ts +9 -19
  15. package/dist/Anchor/index.js +6 -9
  16. package/dist/BarChart/BarRow/elements.d.ts +45 -47
  17. package/dist/BarChart/utils/hooks.d.ts +2 -2
  18. package/dist/BarChart/utils/hooks.js +1 -3
  19. package/dist/Box/GridBox.d.ts +0 -1
  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 +4 -9
  33. package/dist/ButtonBase/ButtonBase.js +4 -11
  34. package/dist/Card/elements.d.ts +103 -109
  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 +3 -4
  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 +12 -18
  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 +1 -2
  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 +42 -44
  56. package/dist/Menu/MenuItem.js +6 -10
  57. package/dist/Menu/elements.d.ts +2 -2
  58. package/dist/Modals/Dialog.js +2 -6
  59. package/dist/Modals/Modal.js +2 -5
  60. package/dist/Modals/elements.d.ts +1 -1
  61. package/dist/Pagination/AnimatedPaginationButtons.d.ts +29 -31
  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 +29 -31
  65. package/dist/Pagination/utils.js +11 -14
  66. package/dist/Popover/Popover.js +6 -6
  67. package/dist/Popover/types.d.ts +3 -4
  68. package/dist/PopoverContainer/PopoverContainer.js +9 -9
  69. package/dist/PopoverContainer/hooks.d.ts +4 -16
  70. package/dist/PopoverContainer/hooks.js +27 -50
  71. package/dist/PopoverContainer/types.d.ts +1 -2
  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 +8 -14
  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 +6 -12
  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/Typography/styles/_variables.scss +54 -0
  83. package/dist/Video/styles/vds_base_theme.scss +3 -1
  84. package/dist/utils/react.js +2 -4
  85. package/package.json +10 -10
  86. package/dist/utils/nullish.d.ts +0 -10
  87. package/dist/utils/nullish.js +0 -11
@@ -5,12 +5,12 @@ description: Design tokens for the Skillsoft Percipio platform.
5
5
  colors:
6
6
  # palette — raw swatches; set once on :root and then always reference by token name, never use hex values directly in code
7
7
  percipioTextPrimary: '#222325'
8
- percipioTextSecondary: '#595A5C'
8
+ percipioTextSecondary: 'rgba(34, 35, 37, 0.75)'
9
9
  percipioTextDisabled: '#AFB6C2'
10
- percipioActionPrimary: '#0073C4'
10
+ sapphire: '#1C50BB'
11
11
  percipioActionPrimaryHover: '#141C36'
12
12
  percipioActionSecondary: '#6A6E75'
13
- percipioActionSecondaryHover: '#7F8288'
13
+ percipioActionSecondaryHover: 'rgba(106, 110, 117, 0.86)'
14
14
  percipioActionDangerHover: '#A52020'
15
15
  percipioDanger: '#B83C3C'
16
16
  percipioFeedbackSuccess: '#1B8057'
@@ -20,10 +20,10 @@ colors:
20
20
  percipioBgWarning: '#FFF7E0'
21
21
  percipioBgError: '#FFF1F5'
22
22
  navy-800: '#10162F'
23
- navy-400: '#8F919D'
24
- navy-300: '#BCBEC5'
25
- navy-200: '#E2E3E6'
26
- navy-100: '#F5F6F7'
23
+ navy-400: 'rgba(16, 22, 47, 0.47)'
24
+ navy-300: 'rgba(16, 22, 47, 0.28)'
25
+ navy-200: 'rgba(16, 22, 47, 0.12)'
26
+ navy-100: 'rgba(16, 22, 47, 0.04)'
27
27
  white: '#ffffff'
28
28
  # semantic aliases — use these in code, not palette swatches or hex values
29
29
  text: '{colors.percipioTextPrimary}'
@@ -38,7 +38,7 @@ colors:
38
38
  background-success: '{colors.percipioBgSuccess}'
39
39
  background-warning: '{colors.percipioBgWarning}'
40
40
  background-error: '{colors.percipioBgError}'
41
- primary: '{colors.percipioActionPrimary}'
41
+ primary: '{colors.sapphire}'
42
42
  primary-hover: '{colors.percipioActionPrimaryHover}'
43
43
  primary-inverse: '{colors.white}'
44
44
  secondary: '{colors.percipioActionSecondary}'
@@ -56,17 +56,17 @@ colors:
56
56
  shadow-secondary: '{colors.navy-400}'
57
57
  typography:
58
58
  base:
59
- fontFamily: '"Roboto", sans-serif'
59
+ fontFamily: '"Skillsoft Text", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
60
60
  fontSize: '1rem'
61
61
  fontWeight: '400'
62
62
  lineHeight: '1.5'
63
63
  accent:
64
- fontFamily: '"Roboto", sans-serif'
64
+ fontFamily: '"Skillsoft Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
65
65
  fontSize: '0.875rem'
66
66
  fontWeight: '400'
67
67
  lineHeight: '1.5'
68
68
  title:
69
- fontFamily: '"Roboto", sans-serif'
69
+ fontFamily: '"Skillsoft Text", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
70
70
  fontSize: '2.125rem'
71
71
  fontWeight: '500'
72
72
  lineHeight: '1.2'
@@ -118,21 +118,23 @@ This file defines the visual design tokens for the Skillsoft Percipio platform,
118
118
 
119
119
  **Storybook**: https://gamut.codecademy.com
120
120
 
121
+ > **Other Gamut themes:** This document covers **Percipio** only. For Codecademy (Core/Admin/Platform) or LX Studio, install that product's `DESIGN.md` instead: `gamut plugin install cursor --theme core` or `--theme lxstudio`.
122
+
121
123
  ---
122
124
 
123
125
  ## Visual Theme & Atmosphere
124
126
 
125
- Percipio communicates **professional clarity** — clean, trustworthy, and enterprise-ready. The design voice is more neutral and corporate than Codecademy: less playful, more functional. Primary blue drives interactive affordances; neutral grays define text and structure.
127
+ Percipio communicates **professional clarity** — clean, trustworthy, and enterprise-ready. The design voice is neutral and corporate: functional, with clear hierarchy. Brand blue drives interactive affordances; neutral grays define text and structure.
126
128
 
127
- **Density**: Medium. Consistent with Codecademy layouts but with softer shadows and a lighter overall feel due to the muted neutral palette.
129
+ **Density**: Medium. Information-dense layouts with softer shadows and a muted neutral palette.
128
130
 
129
131
  **Design philosophy**:
130
132
 
131
133
  - Light mode only — no dark mode support
132
- - Primary blue (`percipioActionPrimary`) replaces Codecademy's `hyper-500` for all interactive elements
133
- - Text is near-black dark gray rather than navy
134
- - Shadows are soft and minimal (navy at low opacity) rather than hard borders
135
- - Title font weight is 500 (medium) rather than 700 (bold) Percipio headlines are less heavy
134
+ - Brand blue (`sapphire` / `primary`) for buttons, links, and focus rings
135
+ - Text uses dedicated Percipio palette tokens (`percipioTextPrimary`, etc.)
136
+ - Shadows are soft and minimal (`shadow-primary` `navy-200`)
137
+ - Title font weight is **500** via `fontWeight="title"` use semantic weight, not literal `700`
136
138
 
137
139
  ---
138
140
 
@@ -140,9 +142,9 @@ Percipio communicates **professional clarity** — clean, trustworthy, and enter
140
142
 
141
143
  Percipio uses a single Gamut theme — light mode only.
142
144
 
143
- | Theme | Use case | Base font | Dark mode |
144
- | ------------ | --------------------------- | --------- | ---------- |
145
- | **Percipio** | Skillsoft Percipio platform | Roboto | light only |
145
+ | Theme | Use case | Base font | Dark mode |
146
+ | ------------ | --------------------------- | --------------------- | ---------- |
147
+ | **Percipio** | Skillsoft Percipio platform | Skillsoft Text / Sans | light only |
146
148
 
147
149
  The active theme is set at the app root via `<GamutProvider theme={percipioTheme}>`.
148
150
 
@@ -154,65 +156,65 @@ Use these token names when specifying colors. Percipio is light mode only — th
154
156
 
155
157
  ### Text
156
158
 
157
- | Token | Value | Use for |
158
- | ---------------- | --------- | ------------------------------------------------ |
159
- | `text` | `#222325` | Default body and UI text |
160
- | `text-accent` | `#222325` | Emphasis text (same value as `text` in Percipio) |
161
- | `text-secondary` | `#595A5C` | Supporting / secondary copy |
162
- | `text-disabled` | `#AFB6C2` | Disabled state labels |
159
+ | Token | Resolves to | Use for |
160
+ | ---------------- | ----------------------- | ------------------------------------------------ |
161
+ | `text` | `percipioTextPrimary` | Default body and UI text |
162
+ | `text-accent` | `percipioTextPrimary` | Emphasis text (same value as `text` in Percipio) |
163
+ | `text-secondary` | `percipioTextSecondary` | Supporting / secondary copy |
164
+ | `text-disabled` | `percipioTextDisabled` | Disabled state labels |
163
165
 
164
166
  ### Background
165
167
 
166
- | Token | Value | Use for |
167
- | --------------------- | -------------------- | --------------------------------- |
168
- | `background` | `#ffffff` | Default page/component background |
169
- | `background-primary` | `#FAFBFC` | Slightly elevated surfaces |
170
- | `background-selected` | `#F5F6F7` (navy-100) | Selected row / item |
171
- | `background-hover` | `#E2E3E6` (navy-200) | Hover state overlay |
172
- | `background-disabled` | `#E2E3E6` (navy-200) | Disabled surface |
173
- | `background-success` | `#EEF7F3` | Success state container |
174
- | `background-warning` | `#FFF7E0` | Warning state container |
175
- | `background-error` | `#FFF1F5` | Error state container |
168
+ | Token | Resolves to | Use for |
169
+ | --------------------- | ------------------- | --------------------------------- |
170
+ | `background` | `white` | Default page/component background |
171
+ | `background-primary` | `percipioBgPrimary` | Slightly elevated surfaces |
172
+ | `background-selected` | `navy-100` | Selected row / item |
173
+ | `background-hover` | `navy-200` | Hover state overlay |
174
+ | `background-disabled` | `navy-200` | Disabled surface |
175
+ | `background-success` | `percipioBgSuccess` | Success state container |
176
+ | `background-warning` | `percipioBgWarning` | Warning state container |
177
+ | `background-error` | `percipioBgError` | Error state container |
176
178
 
177
179
  ### Interactive
178
180
 
179
- | Token | Value | Use for |
180
- | ----------------- | --------- | ------------------------------------ |
181
- | `primary` | `#0073C4` | Primary CTA, links, focus rings |
182
- | `primary-hover` | `#141C36` | Hover state of primary interactive |
183
- | `primary-inverse` | `#ffffff` | Primary on a colored background |
184
- | `secondary` | `#6A6E75` | Secondary CTA, ghost buttons |
185
- | `secondary-hover` | `#7F8288` | Hover state of secondary interactive |
186
- | `danger` | `#B83C3C` | Destructive actions, error states |
187
- | `danger-hover` | `#A52020` | Hover on danger interactive |
181
+ | Token | Resolves to | Use for |
182
+ | ----------------- | ------------------------------ | ------------------------------------ |
183
+ | `primary` | `sapphire` | Primary CTA, links, focus rings |
184
+ | `primary-hover` | `percipioActionPrimaryHover` | Hover state of primary interactive |
185
+ | `primary-inverse` | `white` | Primary on a colored background |
186
+ | `secondary` | `percipioActionSecondary` | Secondary CTA, ghost buttons |
187
+ | `secondary-hover` | `percipioActionSecondaryHover` | Hover state of secondary interactive |
188
+ | `danger` | `percipioDanger` | Destructive actions, error states |
189
+ | `danger-hover` | `percipioActionDangerHover` | Hover on danger interactive |
188
190
 
189
191
  ### Border
190
192
 
191
193
  Percipio's border weights use a non-standard order: `primary` is mid-weight, `secondary` is very light, `tertiary` is the strongest (solid navy). Use them for their semantic intent, not their numeric rank.
192
194
 
193
- | Token | Value | Use for |
194
- | ------------------ | -------------------- | ----------------------------------- |
195
- | `border-primary` | `#8F919D` (navy-400) | Standard input and card borders |
196
- | `border-secondary` | `#E2E3E6` (navy-200) | Subtle dividers, section separators |
197
- | `border-tertiary` | `#10162F` (navy-800) | Strong structural borders |
198
- | `border-disabled` | `#BCBEC5` (navy-300) | Disabled input borders |
195
+ | Token | Resolves to | Use for |
196
+ | ------------------ | ----------- | ----------------------------------- |
197
+ | `border-primary` | `navy-400` | Standard input and card borders |
198
+ | `border-secondary` | `navy-200` | Subtle dividers, section separators |
199
+ | `border-tertiary` | `navy-800` | Strong structural borders |
200
+ | `border-disabled` | `navy-300` | Disabled input borders |
199
201
 
200
202
  ### Feedback
201
203
 
202
- | Token | Value | Use for |
203
- | ------------------ | --------- | -------------------------------- |
204
- | `feedback-error` | `#B83C3C` | Error messages, validation |
205
- | `feedback-success` | `#1B8057` | Success messages, confirmations |
206
- | `feedback-warning` | `#EF5B0D` | Warning messages, caution states |
204
+ | Token | Resolves to | Use for |
205
+ | ------------------ | ------------------------- | -------------------------------- |
206
+ | `feedback-error` | `percipioDanger` | Error messages, validation |
207
+ | `feedback-success` | `percipioFeedbackSuccess` | Success messages, confirmations |
208
+ | `feedback-warning` | `percipioFeedbackWarning` | Warning messages, caution states |
207
209
 
208
210
  ### Shadow
209
211
 
210
- | Token | Value |
211
- | ------------------ | -------------------- |
212
- | `shadow-primary` | `#E2E3E6` (navy-200) |
213
- | `shadow-secondary` | `#8F919D` (navy-400) |
212
+ | Token | Resolves to |
213
+ | ------------------ | ----------- |
214
+ | `shadow-primary` | `navy-200` |
215
+ | `shadow-secondary` | `navy-400` |
214
216
 
215
- Percipio shadows are softer than Codecademy's — use `shadow-primary` for standard elevated surfaces.
217
+ Use `shadow-primary` for standard elevated surfaces.
216
218
 
217
219
  ---
218
220
 
@@ -220,23 +222,23 @@ Percipio shadows are softer than Codecademy's — use `shadow-primary` for stand
220
222
 
221
223
  Percipio introduces its own named semantic colors. These are the source values behind the aliases above. Use the semantic aliases in designs, not the raw named colors.
222
224
 
223
- | Named color | Value | Mapped to |
224
- | ------------------------------ | --------- | -------------------------- |
225
- | `percipioTextPrimary` | `#222325` | `text`, `text-accent` |
226
- | `percipioTextSecondary` | `#595A5C` | `text-secondary` |
227
- | `percipioTextDisabled` | `#AFB6C2` | `text-disabled` |
228
- | `percipioActionPrimary` | `#0073C4` | `primary` |
229
- | `percipioActionPrimaryHover` | `#141C36` | `primary-hover` |
230
- | `percipioActionSecondary` | `#6A6E75` | `secondary` |
231
- | `percipioActionSecondaryHover` | `#7F8288` | `secondary-hover` |
232
- | `percipioActionDangerHover` | `#A52020` | `danger-hover` |
233
- | `percipioDanger` | `#B83C3C` | `danger`, `feedback-error` |
234
- | `percipioFeedbackSuccess` | `#1B8057` | `feedback-success` |
235
- | `percipioFeedbackWarning` | `#EF5B0D` | `feedback-warning` |
236
- | `percipioBgPrimary` | `#FAFBFC` | `background-primary` |
237
- | `percipioBgSuccess` | `#EEF7F3` | `background-success` |
238
- | `percipioBgWarning` | `#FFF7E0` | `background-warning` |
239
- | `percipioBgError` | `#FFF1F5` | `background-error` |
225
+ | Palette token | Semantic alias(es) |
226
+ | ------------------------------ | -------------------------- |
227
+ | `percipioTextPrimary` | `text`, `text-accent` |
228
+ | `percipioTextSecondary` | `text-secondary` |
229
+ | `percipioTextDisabled` | `text-disabled` |
230
+ | `sapphire` | `primary` |
231
+ | `percipioActionPrimaryHover` | `primary-hover` |
232
+ | `percipioActionSecondary` | `secondary` |
233
+ | `percipioActionSecondaryHover` | `secondary-hover` |
234
+ | `percipioActionDangerHover` | `danger-hover` |
235
+ | `percipioDanger` | `danger`, `feedback-error` |
236
+ | `percipioFeedbackSuccess` | `feedback-success` |
237
+ | `percipioFeedbackWarning` | `feedback-warning` |
238
+ | `percipioBgPrimary` | `background-primary` |
239
+ | `percipioBgSuccess` | `background-success` |
240
+ | `percipioBgWarning` | `background-warning` |
241
+ | `percipioBgError` | `background-error` |
240
242
 
241
243
  The full core swatch palette (navy, blue, green, yellow, red, etc.) is also available, but the semantic aliases above are how Percipio maps them. Raw swatches should only be used for fixed colors that must not adapt (illustrations, data viz, etc.).
242
244
 
@@ -246,34 +248,32 @@ The full core swatch palette (navy, blue, green, yellow, red, etc.) is also avai
246
248
 
247
249
  ### Typefaces
248
250
 
249
- All font families in Percipio use **Roboto**. There is no separate accent or display typeface.
251
+ Percipio uses **Skillsoft Text** for body and headlines and **Skillsoft Sans** for accent UI. Roboto Mono is used for code; the `system` slot still uses Roboto.
250
252
 
251
- | Token | Font | Use for |
252
- | ----------- | -------------------------- | ------------------------------------------- |
253
- | `base` | `"Roboto", sans-serif` | All default UI text, headlines, body copy |
254
- | `accent` | `"Roboto", sans-serif` | Labels, captions (same as base in Percipio) |
255
- | `monospace` | `"Roboto Mono", monospace` | Code editor contexts |
256
- | `system` | `"Roboto", sans-serif` | Performance-critical surfaces |
253
+ | Token | Font | Use for |
254
+ | ----------- | ------------------------------ | ----------------------------------------- |
255
+ | `base` | `"Skillsoft Text", sans-serif` | All default UI text, headlines, body copy |
256
+ | `accent` | `"Skillsoft Sans", sans-serif` | Labels, captions, accent UI |
257
+ | `monospace` | `"Roboto Mono", monospace` | Code editor contexts |
258
+ | `system` | `"Roboto", sans-serif` | Performance-critical surfaces |
257
259
 
258
260
  ### Rules
259
261
 
260
- - **Roboto Medium (500)** for headlines, sub-headlines, CTAs, and buttons — not Bold (700).
261
- - **Roboto Regular (400)** for body text, UI labels, and menu items.
262
+ - **Skillsoft Text Medium (500)** for headlines, sub-headlines, CTAs, and buttons — use `fontWeight="title"`, not literal `700`.
263
+ - **Skillsoft Text Regular (400)** for body text, UI labels, and menu items.
262
264
  - Text is **left-aligned** by default. Center-align only for short marketing headlines. Never right-align.
263
265
  - Do not adjust letter-spacing.
264
266
 
265
267
  ### Font weight scale
266
268
 
267
- Percipio overrides the title weight from Core's 700 to 500 (medium). This gives Percipio a lighter, less heavy headline style.
268
-
269
- | Token | Value | Use |
270
- | ------- | ------- | ---------------------------------------------------------- |
271
- | `base` | 400 | Body text, UI labels |
272
- | `title` | **500** | Headlines, CTAs, buttons _(differs from Codecademy's 700)_ |
269
+ | Token | Value | Use |
270
+ | ------- | ------- | ------------------------ |
271
+ | `base` | 400 | Body text, UI labels |
272
+ | `title` | **500** | Headlines, CTAs, buttons |
273
273
 
274
274
  ### Font size scale
275
275
 
276
- Shared with Core all sizes are identical.
276
+ Standard Gamut font size scale:
277
277
 
278
278
  | Token key | Size | Common use |
279
279
  | --------- | ---- | ---------------------------- |
@@ -289,7 +289,7 @@ Shared with Core — all sizes are identical.
289
289
 
290
290
  ### Line height scale
291
291
 
292
- Shared with Core.
292
+ Standard Gamut line height scale:
293
293
 
294
294
  | Token | Value | Use |
295
295
  | ------------- | ----- | ------------------------------- |
@@ -305,7 +305,7 @@ Target 45–85 characters per line; 66 characters is ideal. Max 50 for multi-col
305
305
 
306
306
  ## Spacing Scale
307
307
 
308
- Identical to Core. All spacing is multiples of 4px on an 8px grid.
308
+ All spacing is multiples of 4px on an 8px grid.
309
309
 
310
310
  | Token | Value |
311
311
  | ----- | ----- |
@@ -325,22 +325,20 @@ Identical to Core. All spacing is multiples of 4px on an 8px grid.
325
325
 
326
326
  ## Border Radius Scale
327
327
 
328
- Identical to Core.
329
-
330
- | Token | Value | Use |
331
- | ------ | ----- | ------------------------------------------ |
332
- | `none` | 0px | Square / non-interactive elements |
333
- | `sm` | 2px | Subtle rounding, tags |
334
- | `md` | 4px | Default buttons, inputs, interactive cards |
335
- | `lg` | 8px | Cards, panels |
336
- | `xl` | 16px | Large cards, modals |
337
- | `full` | 999px | Pills, avatars, circular elements |
328
+ | Token | Value | Use |
329
+ | ------ | ----- | ------------------------ |
330
+ | `none` | 0px | Non-interactive elements |
331
+ | `sm` | 2px | Overlays |
332
+ | `md` | 4px | Interactive elements |
333
+ | `lg` | 8px | Non-interactive elements |
334
+ | `xl` | 16px | Non-interactive elements |
335
+ | `full` | 999px | Toggles, badges |
338
336
 
339
337
  ---
340
338
 
341
339
  ## Responsive Behavior
342
340
 
343
- Identical to Core. Mobile-first, apply styles from the named breakpoint up.
341
+ Mobile-first; apply styles from the named breakpoint up.
344
342
 
345
343
  | Token | Min-width | Max content |
346
344
  | -------- | --------- | ----------- |
@@ -365,15 +363,13 @@ Minimum interactive touch target: **44×44px** on mobile breakpoints.
365
363
 
366
364
  ## Component Library
367
365
 
368
- Same component library as Codecademy — all atoms, molecules, and organisms apply. Token values resolve differently per theme automatically.
366
+ Gamut atoms, molecules, and organisms all apply. Use semantic tokens below for Percipio-specific styling.
369
367
 
370
- Key Percipio-specific visual differences:
368
+ Key patterns:
371
369
 
372
- - `FillButton` uses `#0073C4` (blue) instead of hyper-purple
373
- - `FillButton` hover shifts to near-black `#141C36` rather than a lighter purple
374
- - `Checkbox` / `Toggle` use the same blue `#0073C4`
375
- - `Card` has softer shadows (navy-200 vs navy-800 in Codecademy light mode)
376
- - Card shadow patterns (`patternLeft`, `patternRight`) are available but rarely used in Percipio UIs
370
+ - `FillButton` `bg: primary`, `hover: primary-hover`
371
+ - `Checkbox` / `Toggle` `primary`, `hover: primary-hover`
372
+ - `Card` — `shadow-primary` (`navy-200`); `patternLeft` / `patternRight` are available but rarely used
377
373
 
378
374
  ---
379
375
 
@@ -382,15 +378,14 @@ Key Percipio-specific visual differences:
382
378
  ### Colors
383
379
 
384
380
  - **Do** use semantic color aliases (`primary`, `text`, `background`, etc.) — never hardcode hex values.
385
- - **Do** use `#0073C4` blue as the only primary interactive color.
386
- - **Don't** use Codecademy's hyper-purple or yellow in Percipio contexts.
381
+ - **Do** use `primary` (resolves to palette `sapphire`) as the brand interactive color.
387
382
  - **Don't** attempt dark mode — Percipio is light only.
388
383
 
389
384
  ### Typography
390
385
 
391
386
  - **Do** use title weight (500) for headlines, CTAs, and buttons — not 700.
392
387
  - **Do** keep body text at 150–175% line height for readability.
393
- - **Don't** use a separate accent typeface Roboto is used uniformly for base and accent.
388
+ - **Don't** use fonts outside the Percipio theme stack (Skillsoft Text, Skillsoft Sans, Roboto Mono for code).
394
389
  - **Don't** right-align or center-align body paragraphs.
395
390
  - **Don't** adjust letter-spacing.
396
391
 
@@ -406,27 +401,27 @@ Key Percipio-specific visual differences:
406
401
 
407
402
  Quick color/token reference for generating or specifying Percipio UI:
408
403
 
409
- | Scenario | Tokens |
410
- | ---------------- | ------------------------------------------------------------------------------------------------------------ |
411
- | Primary button | `bg: primary (#0073C4)`, `color: white`, `hover: primary-hover (#141C36)` |
412
- | Body text | `color: text (#222325)`, `font: Roboto`, `size: 16px`, `weight: 400`, `lineHeight: base (1.5)` |
413
- | Headline | `color: text (#222325)`, `font: Roboto`, `size: 34–64px`, `weight: title (500)`, `lineHeight: title (1.2)` |
414
- | Secondary text | `color: text-secondary (#595A5C)` |
415
- | Disabled text | `color: text-disabled (#AFB6C2)` |
416
- | Elevated surface | `bg: background-primary (#FAFBFC)` |
417
- | Card default | `bg: background (#ffffff)`, `borderRadius: none` — add `isInteractive` for hover shadow + `borderRadius: md` |
418
- | Error state | `color: feedback-error (#B83C3C)`, `bg: background-error (#FFF1F5)`, `border: danger` |
419
- | Success state | `color: feedback-success (#1B8057)`, `bg: background-success (#EEF7F3)` |
420
- | Warning state | `color: feedback-warning (#EF5B0D)`, `bg: background-warning (#FFF7E0)` |
421
- | Disabled state | `color: text-disabled (#AFB6C2)`, `bg: background-disabled (#E2E3E6, navy-200)`, `border: border-disabled` |
404
+ | Scenario | Tokens |
405
+ | ---------------- | -------------------------------------------------------------------------------------------------- |
406
+ | Primary button | `bg: primary`, `color: primary-inverse`, `hover: primary-hover` |
407
+ | Body text | `color: text`, `font: base`, `size: 16`, `weight: 400`, `lineHeight: base` |
408
+ | Headline | `color: text`, `font: base`, `size: 34–64`, `weight: title`, `lineHeight: title` |
409
+ | Secondary text | `color: text-secondary` |
410
+ | Disabled text | `color: text-disabled` |
411
+ | Elevated surface | `bg: background-primary` |
412
+ | Card default | `bg: background`, `borderRadius: none` — add `isInteractive` for hover shadow + `borderRadius: md` |
413
+ | Error state | `color: feedback-error`, `bg: background-error`, `borderColor: danger` |
414
+ | Success state | `color: feedback-success`, `bg: background-success` |
415
+ | Warning state | `color: feedback-warning`, `bg: background-warning` |
416
+ | Disabled state | `color: text-disabled`, `bg: background-disabled`, `borderColor: border-disabled` |
422
417
 
423
418
  ### Component token cheatsheet
424
419
 
425
420
  ```
426
- FillButton → bg: primary (#0073C4), color: white, hover: primary-hover (#141C36)
427
- StrokeButton → bg: transparent, border: secondary (#6A6E75)
428
- Checkbox/Toggle → primary (#0073C4), hover: primary-hover (#141C36)
429
- Card → bg: background, shadow: shadow-primary (#E2E3E6, navy-200, soft)
421
+ FillButton → bg: primary, color: primary-inverse, hover: primary-hover
422
+ StrokeButton → bg: transparent, borderColor: secondary, hover: secondary-hover
423
+ Checkbox/Toggle → bg: primary, hover: primary-hover
424
+ Card → bg: background, shadow: shadow-primary (navy-200, soft)
430
425
  Alert (error) → uses feedback-error + background-error
431
426
  Alert (success) → uses feedback-success + background-success
432
427
  Alert (warning) → uses feedback-warning + background-warning
@@ -1 +1,12 @@
1
- DEPRECATED. Use the appropriate DESIGN.\*.md from https://github.com/Codecademy/gamut/pull/3329 instead.
1
+ Product-specific design context lives in this directory. **Use one `DESIGN.md` per app — matched to the Gamut theme that app uses.**
2
+
3
+ | Source file | Install with `--theme` |
4
+ | ---------------------- | --------------------------------------------------------- |
5
+ | `DESIGN.Codecademy.md` | `core`, `admin`, `platform` (aliases: `codecademy`, `cc`) |
6
+ | `DESIGN.Percipio.md` | `percipio` |
7
+ | `DESIGN.LXStudio.md` | `lxstudio` (alias: `lx-studio`) |
8
+
9
+ ```sh
10
+ gamut plugin install cursor --theme <name>
11
+ # refresh: gamut plugin update cursor --theme <name> --force
12
+ ```
@@ -15,7 +15,7 @@ export async function claudePluginSpec(sourceRoot) {
15
15
  } catch {
16
16
  throw new Error(
17
17
  `Missing ${mp}.\n` +
18
- `A .claude-plugin/marketplace.json is required for Claude Code installation.`
18
+ `A .claude-plugin/marketplace.json is required for Claude Code installation.`,
19
19
  );
20
20
  }
21
21
 
@@ -26,20 +26,14 @@ export async function claudePluginSpec(sourceRoot) {
26
26
  const { name: marketplaceName, plugins } = json;
27
27
 
28
28
  if (!marketplaceName || !Array.isArray(plugins) || plugins.length === 0) {
29
- throw new Error(
30
- `Invalid marketplace.json — needs "name" and "plugins[]": ${mp}`
31
- );
29
+ throw new Error(`Invalid marketplace.json — needs "name" and "plugins[]": ${mp}`);
32
30
  }
33
31
 
34
32
  const entry =
35
- plugins.find(
36
- (p) => p.source === './' || p.source === '.' || p.source == null
37
- ) ?? plugins[0];
33
+ plugins.find((p) => p.source === './' || p.source === '.' || p.source == null) ?? plugins[0];
38
34
 
39
35
  if (!entry?.name) {
40
- throw new Error(
41
- `No plugin name found in marketplace.json plugins[]: ${mp}`
42
- );
36
+ throw new Error(`No plugin name found in marketplace.json plugins[]: ${mp}`);
43
37
  }
44
38
 
45
39
  return `${entry.name}@${marketplaceName}`;
@@ -53,9 +47,6 @@ export async function claudePluginSpec(sourceRoot) {
53
47
  */
54
48
  export function marketplaceName(spec) {
55
49
  const name = spec.split('@')[1];
56
- if (!name)
57
- throw new Error(
58
- `Could not parse marketplace name from plugin spec: ${spec}`
59
- );
50
+ if (!name) throw new Error(`Could not parse marketplace name from plugin spec: ${spec}`);
60
51
  return name;
61
52
  }
@@ -4,10 +4,7 @@ import { join } from 'node:path';
4
4
 
5
5
  /** @returns {string} */
6
6
  export function cursorPluginsRoot() {
7
- return (
8
- process.env.CURSOR_PLUGINS_LOCAL ??
9
- join(homedir(), '.cursor', 'plugins', 'local')
10
- );
7
+ return process.env.CURSOR_PLUGINS_LOCAL ?? join(homedir(), '.cursor', 'plugins', 'local');
11
8
  }
12
9
 
13
10
  /**
@@ -7,8 +7,8 @@ export declare const buttonPresetThemes: {
7
7
  readonly lantern: "darkmint";
8
8
  readonly royalblue: "brand-purple";
9
9
  };
10
- declare const _themes: readonly ["hyper", "navy", "red", "white", "brand-red", "brand-yellow", "brand-purple", "brand-dark-blue", "brand-blue", "mint", "darkmint", "grey", "greyblue"];
11
- export type ButtonDeprecatedThemes = keyof typeof buttonPresetThemes | (typeof _themes)[number];
10
+ declare const themes: readonly ["hyper", "navy", "red", "white", "brand-red", "brand-yellow", "brand-purple", "brand-dark-blue", "brand-blue", "mint", "darkmint", "grey", "greyblue"];
11
+ export type ButtonDeprecatedThemes = keyof typeof buttonPresetThemes | (typeof themes)[number];
12
12
  export type ButtonDeprecatedProps = ButtonDeprecatedBaseProps & {
13
13
  /**
14
14
  * Whether button should behave like a block element or inline.
@@ -16,7 +16,7 @@ export const buttonPresetThemes = {
16
16
  lantern: 'darkmint',
17
17
  royalblue: 'brand-purple'
18
18
  };
19
- const _themes = ['hyper', 'navy', 'red', 'white', 'brand-red', 'brand-yellow', 'brand-purple', 'brand-dark-blue', 'brand-blue', 'mint', 'darkmint', 'grey', 'greyblue'];
19
+ const themes = ['hyper', 'navy', 'red', 'white', 'brand-red', 'brand-yellow', 'brand-purple', 'brand-dark-blue', 'brand-blue', 'mint', 'darkmint', 'grey', 'greyblue'];
20
20
  const propKeys = ['theme', 'size', 'outline', 'underline', 'link', 'caps', 'go', 'children', 'block', 'className', 'round', 'square', 'flat', 'fitText', 'onClick'];
21
21
  const isPreset = theme => {
22
22
  return hasIn(buttonPresetThemes, theme);
@@ -1,6 +1,7 @@
1
1
  @use "sass:color";
2
2
  @use "variables";
3
3
  @use "mixins";
4
+ @use "~@codecademy/gamut-styles/utils" as *;
4
5
  //
5
6
  // Base styles
6
7
  //
@@ -10,8 +11,7 @@
10
11
  display: inline-flex;
11
12
  justify-content: center;
12
13
  font-weight: variables.$btn-font-weight;
13
- -webkit-font-smoothing: antialiased;
14
- -moz-osx-font-smoothing: grayscale;
14
+ @include font-smoothing;
15
15
  border: 1px solid transparent;
16
16
  border-radius: variables.$btn-border-radius;
17
17
  user-select: none;
@@ -33,11 +33,11 @@ fieldset[disabled] a.btn {
33
33
 
34
34
  @each $name, $color in variables.$btn-swatches {
35
35
  @if $name == "brand-yellow" {
36
- @include mixins.button-variants($name, variables.$color-black, $color);
36
+ @include mixins.button-variants($name, $color-black, $color);
37
37
  } @else if color.channel(color.to-space($color, hsl), "lightness") > 68 {
38
- @include mixins.button-variants($name, variables.$color-black, $color);
38
+ @include mixins.button-variants($name, $color-black, $color);
39
39
  } @else {
40
- @include mixins.button-variants($name, variables.$color-white, $color);
40
+ @include mixins.button-variants($name, $color-white, $color);
41
41
  }
42
42
  }
43
43
 
@@ -1,4 +1,5 @@
1
1
  @use "sass:color";
2
+ @use "~@codecademy/gamut-styles/utils" as *;
2
3
  @use "variables";
3
4
 
4
5
  // Button variants
@@ -7,7 +8,7 @@
7
8
  // and disabled options for all buttons
8
9
 
9
10
  @mixin button-variant($color, $background, $border: transparent) {
10
- $active-background: color.mix(variables.$color-black, $background);
11
+ $active-background: color.mix($color-black, $background);
11
12
 
12
13
  @if $border == transparent {
13
14
  $active-border: transparent;
@@ -23,7 +24,7 @@
23
24
  }
24
25
 
25
26
  &:focus-visible {
26
- box-shadow: 0 0 0 2px variables.$color-white, 0 0 0 4px $background;
27
+ box-shadow: 0 0 0 2px $color-white, 0 0 0 4px $background;
27
28
  }
28
29
 
29
30
  &:focus-visible,
@@ -59,7 +60,7 @@
59
60
  }
60
61
 
61
62
  &:focus-visible {
62
- box-shadow: 0 0 0 2px variables.$color-white, 0 0 0 4px $color;
63
+ box-shadow: 0 0 0 2px $color-white, 0 0 0 4px $color;
63
64
  }
64
65
 
65
66
  &:disabled {
@@ -97,8 +98,7 @@
97
98
  }
98
99
  .link-#{$name} {
99
100
  font-weight: bold;
100
- -webkit-font-smoothing: antialiased;
101
- -moz-osx-font-smoothing: grayscale;
101
+ @include font-smoothing;
102
102
  color: $background;
103
103
  text-decoration: underline;
104
104