@codecademy/gamut 68.6.1-alpha.e6c390.0 → 68.6.1-alpha.f6b2ce.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 (47) hide show
  1. package/agent-tools/.cursor-plugin/plugin.json +1 -1
  2. package/agent-tools/DESIGN.Codecademy.md +239 -191
  3. package/agent-tools/DESIGN.LXStudio.md +236 -184
  4. package/agent-tools/DESIGN.Percipio.md +232 -182
  5. package/agent-tools/DESIGN.md +1 -1
  6. package/agent-tools/commands/gamut-review.md +176 -87
  7. package/agent-tools/guidelines/components/animations.md +74 -0
  8. package/agent-tools/guidelines/components/buttons.md +74 -23
  9. package/agent-tools/guidelines/components/card.md +19 -0
  10. package/agent-tools/guidelines/components/coachmark.md +21 -0
  11. package/agent-tools/guidelines/components/data-table.md +79 -0
  12. package/agent-tools/guidelines/components/forms.md +106 -0
  13. package/agent-tools/guidelines/components/loading-states.md +17 -0
  14. package/agent-tools/guidelines/components/menu.md +58 -0
  15. package/agent-tools/guidelines/components/overview.md +97 -17
  16. package/agent-tools/guidelines/components/radial-progress.md +13 -0
  17. package/agent-tools/guidelines/components/select.md +23 -0
  18. package/agent-tools/guidelines/components/tooltips.md +22 -0
  19. package/agent-tools/guidelines/components/video.md +29 -0
  20. package/agent-tools/guidelines/foundations/color.md +140 -58
  21. package/agent-tools/guidelines/foundations/modes.md +39 -17
  22. package/agent-tools/guidelines/foundations/spacing.md +78 -37
  23. package/agent-tools/guidelines/foundations/typography.md +69 -37
  24. package/agent-tools/guidelines/overview-icons.md +19 -0
  25. package/agent-tools/guidelines/overview-illustrations.md +7 -0
  26. package/agent-tools/guidelines/overview-patterns.md +7 -0
  27. package/agent-tools/guidelines/overview.md +69 -23
  28. package/agent-tools/guidelines/setup.md +59 -18
  29. package/agent-tools/rules/accessibility.mdc +22 -13
  30. package/agent-tools/skills/gamut-accessibility/SKILL.md +97 -112
  31. package/agent-tools/skills/gamut-color-mode/SKILL.md +79 -29
  32. package/agent-tools/skills/gamut-components/SKILL.md +46 -0
  33. package/agent-tools/skills/gamut-forms/SKILL.md +101 -0
  34. package/agent-tools/skills/gamut-style-utilities/SKILL.md +111 -0
  35. package/agent-tools/skills/gamut-system-props/SKILL.md +70 -26
  36. package/agent-tools/skills/gamut-testing/SKILL.md +106 -62
  37. package/agent-tools/skills/gamut-theming/SKILL.md +34 -86
  38. package/agent-tools/skills/gamut-typography/SKILL.md +36 -80
  39. package/bin/commands/plugin/install.mjs +96 -56
  40. package/bin/commands/plugin/list.mjs +11 -43
  41. package/bin/commands/plugin/remove.mjs +30 -38
  42. package/bin/commands/plugin/update.mjs +15 -5
  43. package/bin/gamut.mjs +17 -13
  44. package/bin/lib/design.mjs +71 -0
  45. package/bin/lib/io.mjs +14 -0
  46. package/package.json +6 -6
  47. package/bin/lib/figma.mjs +0 -49
@@ -1,86 +1,168 @@
1
1
  # Color
2
2
 
3
- Use **semantic aliases** for all UI that adapts to color mode or theme. Use raw palette tokens only when a color must stay fixed regardless of mode.
3
+ Use semantic aliases for UI that should respond to color mode (light/dark) and theme (Core, Admin, Platform, Percipio, LX Studio). The same semantic token names (`text`, `primary`, `background`, …) exist across themes; resolved palette values and hex differ by `GamutProvider` theme and active ColorMode. Never assume Codecademy Core hex when advising another product.
4
4
 
5
- ## Semantic aliases
5
+ Prefer `css` / `variant` / `states` from `@codecademy/gamut-styles` with semantic names (see Storybook [Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page)).
6
+
7
+ Related: [`setup.md`](../setup.md) (which theme to import) · [`gamut-theming` skill](../../skills/gamut-theming/SKILL.md) · [`gamut-style-utilities` skill](../../skills/gamut-style-utilities/SKILL.md) · [`gamut-color-mode` skill](../../skills/gamut-color-mode/SKILL.md) · [`modes.md`](modes.md) (`<ColorMode>`, `<Background>`)
8
+
9
+ Percipio, LX Studio, Admin, and Platform override subsets of semantic mappings while keeping the shared alias API — see theme sources below before hardcoding palette names or hex.
10
+
11
+ ## Semantic aliases (theme-stable names)
12
+
13
+ These tokens describe roles. Actual colors come from the active theme + ColorMode.
14
+
15
+ ### Text
16
+
17
+ | Token | Use for | Notes |
18
+ | ---------------- | --------------------------- | -------------------------- |
19
+ | `text` | Default body and UI text | |
20
+ | `text-accent` | Stronger emphasis text | |
21
+ | `text-secondary` | Supporting / secondary copy | Often opacity on base text |
22
+ | `text-disabled` | Disabled state labels | |
23
+
24
+ ### Background
25
+
26
+ | Token | Use for | Notes |
27
+ | --------------------- | --------------------------------- | ------------------------- |
28
+ | `background` | Default page/component background | |
29
+ | `background-primary` | Slightly elevated surfaces | |
30
+ | `background-contrast` | Maximum contrast surface | |
31
+ | `background-selected` | Selected row / item | Often low-opacity overlay |
32
+ | `background-hover` | Hover state overlay | |
33
+ | `background-disabled` | Disabled surface | |
34
+ | `background-success` | Success state container | |
35
+ | `background-warning` | Warning state container | |
36
+ | `background-error` | Error state container | |
37
+
38
+ ### Interactive
39
+
40
+ | Token | Use for | Notes |
41
+ | ----------------- | ----------------------------------------- | ---------------------------- |
42
+ | `primary` | Primary CTA, links, focus accents | Pairs with `primary-hover` |
43
+ | `primary-hover` | Hover on primary interactive | |
44
+ | `primary-inverse` | Accent on top of primary-colored surfaces | |
45
+ | `secondary` | Secondary CTA, ghost buttons | Pairs with `secondary-hover` |
46
+ | `secondary-hover` | Hover on secondary interactive | |
47
+ | `danger` | Destructive actions, error emphasis | Pairs with `danger-hover` |
48
+ | `danger-hover` | Hover on danger interactive | |
49
+
50
+ ### Border
51
+
52
+ | Token | Use for | Notes |
53
+ | ------------------ | -------------------------- | ----- |
54
+ | `border-primary` | Strong borders, dividers | |
55
+ | `border-secondary` | Medium-weight borders | |
56
+ | `border-tertiary` | Subtle borders, separators | |
57
+ | `border-disabled` | Disabled input borders | |
58
+
59
+ ### Feedback
60
+
61
+ | Token | Use for | Notes |
62
+ | ------------------ | -------------------------- | ----- |
63
+ | `feedback-error` | Error messages, validation | |
64
+ | `feedback-success` | Success messages | |
65
+ | `feedback-warning` | Warning messages | |
66
+
67
+ ## Where resolved colors are documented
68
+
69
+ Use these instead of memorizing hex:
70
+
71
+ - Storybook [ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page) — how aliases map per light/dark for reference layouts.
72
+ - Storybook Foundations → Theme — per-product tables and guidance:
73
+ - [Core Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-core-theme--docs)
74
+ - [Admin Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-admin-theme--docs)
75
+ - [Platform Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-platform-theme--docs)
76
+ - [Percipio Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-percipio-theme--docs)
77
+ - [LX Studio Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-lx-studio-theme--docs)
78
+ - [Creating Themes](https://gamut.codecademy.com/?path=/docs-foundations-theme-creating-themes--docs) — authoring new themes in `gamut-styles`
79
+ - Product design YAML (root `DESIGN.md` from agent-tools): [`DESIGN.Codecademy.md`](../../DESIGN.Codecademy.md), [`DESIGN.Percipio.md`](../../DESIGN.Percipio.md), [`DESIGN.LXStudio.md`](../../DESIGN.LXStudio.md) — semantic ↔ palette for that product.
80
+ - Source: theme definitions in [`packages/gamut-styles/src/themes`](https://github.com/Codecademy/gamut/tree/main/packages/gamut-styles/src/themes), palette scales in [`packages/gamut-styles/src/variables`](https://github.com/Codecademy/gamut/tree/main/packages/gamut-styles/src/variables).
81
+
82
+ ## Codecademy Core — illustrative light/dark hex only
83
+
84
+ The tables below are not valid for Percipio, LX Studio, or other themes. They are a quick mental model for Codecademy Core defaults only.
6
85
 
7
86
  ### Text
8
87
 
9
- | Token | Light | Dark | Use for |
10
- |---|---|---|---|
11
- | `text` | `#10162F` | `#ffffff` | Default body and UI text |
12
- | `text-accent` | `#0A0D1C` | `#FFF0E5` | Stronger emphasis text |
13
- | `text-secondary` | navy-800 75% | white 65% | Supporting / secondary copy |
14
- | `text-disabled` | navy-800 63% | white 50% | Disabled state labels |
88
+ | Token | Light | Dark |
89
+ | ---------------- | ------------ | --------- |
90
+ | `text` | `#10162F` | `#ffffff` |
91
+ | `text-accent` | `#0A0D1C` | `#FFF0E5` |
92
+ | `text-secondary` | navy-800 75% | white 65% |
93
+ | `text-disabled` | navy-800 63% | white 50% |
15
94
 
16
95
  ### Background
17
96
 
18
- | Token | Light | Dark | Use for |
19
- |---|---|---|---|
20
- | `background` | `#ffffff` | `#10162F` | Default page/component background |
21
- | `background-primary` | `#FFF0E5` | `#0A0D1C` | Slightly elevated surfaces |
22
- | `background-contrast` | white | black | Maximum contrast surface |
23
- | `background-selected` | navy-800 4% | white 4% | Selected row / item |
24
- | `background-hover` | navy-800 12% | white 9% | Hover state overlay |
25
- | `background-disabled` | navy-800 12% | white 9% | Disabled surface |
26
- | `background-success` | `#F5FFE3` | `#151C07` | Success state container |
27
- | `background-warning` | `#FFFAE5` | `#211B00` | Warning state container |
28
- | `background-error` | `#FBF1F0` | `#280503` | Error state container |
97
+ | Token | Light | Dark |
98
+ | --------------------- | ------------ | --------- |
99
+ | `background` | `#ffffff` | `#10162F` |
100
+ | `background-primary` | `#FFF0E5` | `#0A0D1C` |
101
+ | `background-contrast` | white | black |
102
+ | `background-selected` | navy-800 4% | white 4% |
103
+ | `background-hover` | navy-800 12% | white 9% |
104
+ | `background-disabled` | navy-800 12% | white 9% |
105
+ | `background-success` | `#F5FFE3` | `#151C07` |
106
+ | `background-warning` | `#FFFAE5` | `#211B00` |
107
+ | `background-error` | `#FBF1F0` | `#280503` |
29
108
 
30
109
  ### Interactive
31
110
 
32
- | Token | Light | Dark | Use for |
33
- |---|---|---|---|
34
- | `primary` | `#3A10E5` | `#FFD300` | Primary CTA, links, focus rings |
35
- | `primary-hover` | `#5533FF` | `#CCA900` | Hover on primary interactive |
36
- | `primary-inverse` | `#FFD300` | `#3A10E5` | Primary on a colored background |
37
- | `secondary` | `#10162F` | `#ffffff` | Secondary CTA, ghost buttons |
38
- | `secondary-hover` | navy-800 86% | white 80% | Hover on secondary interactive |
39
- | `interface` | `#3A10E5` | `#FFD300` | Checkboxes, toggles, sliders |
40
- | `interface-hover` | `#5533FF` | `#CCA900` | Hover on interface elements |
41
- | `danger` | `#E91C11` | `#E85D7F` | Destructive actions, error states |
42
- | `danger-hover` | `#BE1809` | `#DC5879` | Hover on danger interactive |
111
+ | Token | Light | Dark |
112
+ | ----------------- | ------------ | --------- |
113
+ | `primary` | `#3A10E5` | `#FFD300` |
114
+ | `primary-hover` | `#5533FF` | `#CCA900` |
115
+ | `primary-inverse` | `#FFD300` | `#3A10E5` |
116
+ | `secondary` | `#10162F` | `#ffffff` |
117
+ | `secondary-hover` | navy-800 86% | white 80% |
118
+ | `danger` | `#E91C11` | `#E85D7F` |
119
+ | `danger-hover` | `#BE1809` | `#DC5879` |
43
120
 
44
121
  ### Border
45
122
 
46
- | Token | Light | Dark | Use for |
47
- |---|---|---|---|
48
- | `border-primary` | `#10162F` | `#ffffff` | Strong borders, dividers |
49
- | `border-secondary` | navy-800 75% | white 65% | Medium-weight borders |
50
- | `border-tertiary` | navy-800 28% | white 20% | Subtle borders, separators |
51
- | `border-disabled` | navy-800 63% | white 50% | Disabled input borders |
123
+ | Token | Light | Dark |
124
+ | ------------------ | ------------ | --------- |
125
+ | `border-primary` | `#10162F` | `#ffffff` |
126
+ | `border-secondary` | navy-800 75% | white 65% |
127
+ | `border-tertiary` | navy-800 28% | white 20% |
128
+ | `border-disabled` | navy-800 63% | white 50% |
52
129
 
53
130
  ### Feedback
54
131
 
55
- | Token | Light | Dark | Use for |
56
- |---|---|---|---|
57
- | `feedback-error` | `#BE1809` | `#E85D7F` | Error messages, validation |
58
- | `feedback-success` | `#008A27` | `#AEE938` | Success messages |
59
- | `feedback-warning` | `#FFD300` | `#FFFAE5` | Warning messages |
132
+ | Token | Light | Dark |
133
+ | ------------------ | --------- | --------- |
134
+ | `feedback-error` | `#BE1809` | `#E85D7F` |
135
+ | `feedback-success` | `#008A27` | `#AEE938` |
136
+ | `feedback-warning` | `#FFD300` | `#FFFAE5` |
137
+
138
+ ## Raw palette (Core-centric reference)
60
139
 
61
- ## Raw palette
140
+ Raw tokens name fixed swatches (surfaces, illustration, `<Background bg="…">` on Codecademy). Palette keys and hex vary by theme — Percipio and others add or remap scales (`percipioPalette`, etc.). Confirm allowed keys in the active theme or `DESIGN.md` before using a raw token in a non-Core app.
62
141
 
63
- Use raw tokens only when color must be **fixed** (not adaptive).
142
+ For Codecademy Core defaults:
64
143
 
65
- | Name | Weights | Key values |
66
- |---|---|---|
67
- | `navy` | 100–900 | 800 = `#10162F`, 900 = `#0A0D1C` |
68
- | `hyper` | 400, 500 | 500 = `#3A10E5`, 400 = `#5533FF` |
69
- | `yellow` | 0, 400, 500, 900 | 500 = `#FFD300` |
70
- | `red` | 0, 300, 400, 500, 600, 900 | 500 = `#E91C11` |
71
- | `green` | 0, 100, 400, 700, 900 | 700 = `#008A27` |
72
- | `blue` | 0, 100, 300, 400, 500, 800 | 500 = `#1557FF` |
73
- | `beige` | — | `#FFF0E5` |
74
- | `pink` | 0, 400 | 400 = `#F966FF` |
75
- | `orange` | 100, 500 | 500 = `#FF8C00` |
144
+ | Name | Weights | Key values (illustrative) |
145
+ | -------- | -------------------------- | -------------------------------- |
146
+ | `navy` | 100–900 | 800 = `#10162F`, 900 = `#0A0D1C` |
147
+ | `hyper` | 400, 500 | 500 = `#3A10E5`, 400 = `#5533FF` |
148
+ | `yellow` | 0, 400, 500, 900 | 500 = `#FFD300` |
149
+ | `red` | 0, 300, 400, 500, 600, 900 | 500 = `#E91C11` |
150
+ | `green` | 0, 100, 400, 700, 900 | 700 = `#008A27` |
151
+ | `blue` | 0, 100, 300, 400, 500, 800 | 500 = `#1557FF` |
152
+ | `beige` | — | `#FFF0E5` |
153
+ | `pink` | 0, 400 | 400 = `#F966FF` |
154
+ | `orange` | 100, 500 | 500 = `#FF8C00` |
76
155
 
77
- Named shorthand aliases: `beige`, `blue`, `green`, `hyper`, `navy`, `orange`, `pink`, `red`, `yellow`, `black`, `white`
156
+ Named shorthand aliases commonly used on Core surfaces: `beige`, `blue`, `green`, `hyper`, `navy`, `orange`, `pink`, `red`, `yellow`, `black`, `white`
78
157
 
79
158
  ## Decision guide
80
159
 
81
160
  ```
161
+ Which product theme is GamutProvider using?
162
+ └─ Unknown → check setup.md / DESIGN.md / Storybook theme page before assuming hex or palette name
163
+
82
164
  Coloring UI text or backgrounds?
83
- └─ Needs to adapt to light/dark or theme? → use semantic alias (text, background, primary, …)
84
- └─ Must be fixed regardless of mode? → use raw token (navy-800, yellow-500, )
85
- └─ Setting a section background with content inside? → use <Background bg="…"> (see modes.md)
165
+ └─ Must adapt to light/dark OR theme? → semantic alias (text, background, primary, …)
166
+ └─ Must stay fixed regardless of mode? → raw palette token (confirm key exists in that theme)
167
+ └─ Section background with content inside? → <Background bg="…"> (see modes.md)
86
168
  ```
@@ -1,24 +1,43 @@
1
1
  # Color Modes
2
2
 
3
- Gamut uses **semantic color aliases** so components adapt to light/dark mode without configuration. See [color.md](color.md) for the full alias reference.
3
+ Gamut uses semantic color aliases so components adapt to light/dark mode without configuration. See [color.md](color.md) for the full alias reference and decision guide.
4
4
 
5
- ## `<ColorMode>`
5
+ Product tokens: Semantic mappings vary by theme. Confirm aliases and palette keys against root `DESIGN.md` and the active theme Storybook page — do not assume Codecademy Core values in Percipio, LX Studio, or other products.
6
+
7
+ Deep reference: [`skills/gamut-color-mode/SKILL.md`](../../skills/gamut-color-mode/SKILL.md) · Storybook [ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page)
8
+
9
+ ## When to use the color mode system
10
+
11
+ For any dark or light region — sidebars, footers, hero bands, callouts, panels, whole-app dark mode — use `ColorMode` or `Background` from `@codecademy/gamut-styles`. Do not handle these with custom CSS, hardcoded `rgba`, or manual color swaps.
12
+
13
+ | Component | Use when |
14
+ | ------------ | ----------------------------------------------------------------------------------------------- |
15
+ | `ColorMode` | You know the mode (`light`, `dark`, or `system` for OS preference). |
16
+ | `Background` | Background color is a palette token and Gamut should pick the best contrast mode automatically. |
6
17
 
7
- Wraps a subtree in an explicit color mode. Nest to create scoped mode regions.
18
+ ## Rules
19
+
20
+ 1. Never override Gamut colors with custom CSS when a `ColorMode` or `Background` wrapper achieves the same result via tokens.
21
+ 2. Prefer `ColorMode` over `Background` when the intended mode is known (e.g. sidebar always dark). Use `Background` when the surface color is fixed and mode should adapt.
22
+ 3. `ColorMode` has no `as` prop — nest semantic elements inside (`<nav>`, `<aside>`, `<footer>`).
23
+ 4. System props work on `ColorMode` — `p`, `m`, `width`, `position`, etc. without extra wrappers.
24
+ 5. `mode="system"` follows OS `prefers-color-scheme`. For in-app theme toggles, pass `mode="light"` or `mode="dark"` from your own state.
25
+
26
+ ## `<ColorMode>`
8
27
 
9
28
  ```tsx
10
29
  import { ColorMode } from '@codecademy/gamut-styles';
11
30
 
12
- <ColorMode mode="light">{children}</ColorMode> // force light
13
- <ColorMode mode="dark">{children}</ColorMode> // force dark
14
- <ColorMode mode="system">{children}</ColorMode> // follows OS preference
31
+ <ColorMode mode="light">{children}</ColorMode>
32
+ <ColorMode mode="dark">{children}</ColorMode>
33
+ <ColorMode mode="system">{children}</ColorMode>
15
34
  ```
16
35
 
17
- **Props**: `mode="light" | "dark" | "system"`
36
+ Props: `mode="light" | "dark" | "system"`
18
37
 
19
38
  ## `<Background>`
20
39
 
21
- Use `<Background>` — not a raw `bg` propwhenever setting a colored background on a section that contains text or interactive elements. It automatically switches the color mode inside to maintain accessible contrast.
40
+ Use `<Background>` — not a raw `bg` on layout for colored sections with text or interactive children. Pass a palette token to `bg` (e.g. `hyper`, `navy`), not a semantic alias.
22
41
 
23
42
  ```tsx
24
43
  import { Background } from '@codecademy/gamut-styles';
@@ -30,18 +49,21 @@ Nesting is supported — each `<Background>` creates its own accessible color co
30
49
 
31
50
  ## Hooks
32
51
 
33
- | Hook | Returns | Use |
34
- | ---------------------- | ------------------------------------------------------- | ------------------------------------------------- |
35
- | `useCurrentMode()` | `"light" \| "dark"` | Active mode key only |
36
- | `useColorModes()` | `[modeKey, currentModeColors, allModes, getColorValue]` | Full mode data + resolver for semantic color keys |
37
- | `usePrefersDarkMode()` | `boolean` | OS `prefers-color-scheme: dark` only |
52
+ | Hook | Returns | Use |
53
+ | ---------------------- | ------------------------------------- | ---------------------------------------------------------- |
54
+ | `useCurrentMode()` | `"light" \| "dark"` | Active mode key only |
55
+ | `useColorModes()` | mode key, colors, all modes, resolver | Full mode data + `getColorValue` |
56
+ | `usePrefersDarkMode()` | `boolean` | OS dark preference (prefer `mode="system"` on `ColorMode`) |
38
57
 
39
58
  Import from `@codecademy/gamut-styles`.
40
59
 
41
- **Storybook:** [Foundations / ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page) · [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page)
60
+ ## Example (Core theme)
61
+
62
+ Core light/dark semantic mappings are documented in Storybook [ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page). Other themes remap the same alias names to different palette values — verify in `DESIGN.md` and the product theme story before hardcoding palette fallbacks.
63
+ Storybook: [Foundations / ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page) · [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page)
42
64
 
43
65
  ## Common mistakes
44
66
 
45
- - Do not use raw color tokens (`navy-400`, `white`) for text/backgrounds that must be accessible across modes — use semantic aliases.
46
- - Do not use a raw `bg` prop on colored sections containing content — use `<Background>` so contrast is guaranteed.
47
- - Do not manually toggle modes from `usePrefersDarkMode()` use `<ColorMode mode="system">` instead.
67
+ - Do not use raw palette tokens (`navy-400`, `white`) for text/backgrounds that must adapt across modes — use semantic aliases.
68
+ - Do not use a raw `bg` prop on colored sections with content — use `<Background>`.
69
+ - Do not wire `usePrefersDarkMode()` into `ColorMode` when `mode="system"` suffices.
@@ -1,62 +1,103 @@
1
1
  # Spacing, Border Radius & Layout
2
2
 
3
+ Token values match [`packages/gamut-styles/src/variables`](https://github.com/Codecademy/gamut/tree/main/packages/gamut-styles/src/variables) (`spacing.ts`, `borderRadii.ts`, `responsive.ts`). Breakpoints and max-content widths align with Storybook [Foundations / Layout](https://gamut.codecademy.com/?path=/docs-foundations-layout--docs).
4
+
5
+ In code — use system props for spacing: Gamut layout primitives (`Box`, `FlexBox`, `GridBox`, …) expose margin, padding, and gap props backed by `system.space` from `@codecademy/gamut-styles`. Pass spacing scale numbers (`4`, `8`, `16`, …), not raw pixel strings. For custom `styled` components, compose `system.space` (see [`gamut-system-props` skill](../../skills/gamut-system-props/SKILL.md)). [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) shows responsive `Box` examples.
6
+
7
+ Responsive behavior: All those props accept mobile-first object (`{ _: 8, md: 24 }`) or array syntax per [Responsive properties](https://gamut.codecademy.com/?path=/docs-foundations-system-responsive-properties--page). Container queries use keys `c_base`, `c_xs`, … `c_xl`; the parent must set a container (e.g. `containerType="inline-size"` on `FlexBox`). Prefer a media-query fallback when mixing `c_*` with viewport breakpoints.
8
+
9
+ Two different “grids”:
10
+
11
+ - Design / page grid (this doc’s “Grid” section, 12 columns, margins/gutters) — product layout guidelines; implement with [`LayoutGrid`](https://gamut.codecademy.com/?path=/docs-layouts-layoutgrid-layoutgrid--docs) and responsive `columnGap` / `rowGap` where appropriate.
12
+ - CSS Grid system props — `system.grid` on styled components or `GridBox` for local regions; not the same as full-page `LayoutGrid`. See [System props / Grid](https://gamut.codecademy.com/?path=/docs-foundations-system-props-grid--page). `LayoutGrid` is for flexible full-page sections; use `FlexBox` / `GridBox` / `Box` for smaller areas ([LayoutGrid usage](https://gamut.codecademy.com/?path=/docs-layouts-layoutgrid-layoutgrid--docs)).
13
+
14
+ Designer vs code names: Figma / Layout docs often label artboards XL, LG, MD, SM, XS, Base. In code, viewport breakpoints are `xl`, `lg`, `md`, `sm`, `xs` (min-widths below); `_` is the base (no min-width query). The “Max content width” column maps to those design sizes, not the `xs` token name alone.
15
+
3
16
  ## Spacing scale
4
17
 
5
18
  All spacing is multiples of 4px on an 8px grid.
6
19
 
7
20
  | Token | Value |
8
- |---|---|
9
- | `0` | 0 |
10
- | `4` | 4px |
11
- | `8` | 8px |
12
- | `12` | 12px |
13
- | `16` | 16px |
14
- | `24` | 24px |
15
- | `32` | 32px |
16
- | `40` | 40px |
17
- | `48` | 48px |
18
- | `64` | 64px |
19
- | `96` | 96px |
21
+ | ----- | ----- |
22
+ | `0` | 0 |
23
+ | `4` | 4px |
24
+ | `8` | 8px |
25
+ | `12` | 12px |
26
+ | `16` | 16px |
27
+ | `24` | 24px |
28
+ | `32` | 32px |
29
+ | `40` | 40px |
30
+ | `48` | 48px |
31
+ | `64` | 64px |
32
+ | `96` | 96px |
20
33
 
21
34
  Use multiples of 8px for block-element spacing. Use 4px only for inline or typographic relationships.
22
35
 
23
36
  ## Border radius
24
37
 
25
- | Token | Value | Use |
26
- |---|---|---|
27
- | `none` | 0px | Square / non-interactive elements |
28
- | `sm` | 2px | Subtle rounding, tags |
29
- | `md` | 4px | Buttons, inputs, interactive cards |
30
- | `lg` | 8px | Cards, panels |
31
- | `xl` | 16px | Large cards, modals |
32
- | `full` | 999px | Pills, avatars, circular elements |
38
+ | Token | Value | Use |
39
+ | ------ | ----- | ---------------------------------- |
40
+ | `none` | 0px | Square / non-interactive elements |
41
+ | `sm` | 2px | Subtle rounding, tags |
42
+ | `md` | 4px | Buttons, inputs, interactive cards |
43
+ | `lg` | 8px | Cards, panels |
44
+ | `xl` | 16px | Large cards, modals |
45
+ | `full` | 999px | Pills, avatars, circular elements |
33
46
 
34
47
  ## Breakpoints
35
48
 
36
49
  Mobile-first. Styles apply from the named breakpoint and up.
37
50
 
38
- | Token | Min-width | Max content width |
39
- |---|---|---|
40
- | _(base)_ | 0 | 288px |
41
- | `xs` | 480px | 448px |
42
- | `sm` | 768px | 704px |
43
- | `md` | 1024px | 896px |
44
- | `lg` | 1200px | 1072px |
45
- | `xl` | 1440px | 1248px |
51
+ | Token | Min-width | Max content width |
52
+ | -------- | --------- | ----------------- |
53
+ | _(base)_ | 0 | 288px |
54
+ | `xs` | 480px | 448px |
55
+ | `sm` | 768px | 704px |
56
+ | `md` | 1024px | 896px |
57
+ | `lg` | 1200px | 1072px |
58
+ | `xl` | 1440px | 1248px |
59
+
60
+ The grid table below collapses xl+lg, md, sm+xs, and base to four implementation tiers; max-content widths still follow the six design sizes in Layout.
61
+
62
+ ## Container query breakpoints
63
+
64
+ Container keys (`c_*`) use the same min-width numbers as viewport breakpoints, but they apply to the width of a CSS containment context (usually a parent), not the browser viewport. Use them when a component must adapt inside sidebars, split layouts, or embeds. Full detail: [Responsive properties — Container Queries](https://gamut.codecademy.com/?path=/docs-foundations-system-responsive-properties--page).
65
+
66
+ | Key | Min container width | Typical use |
67
+ | -------- | ------------------- | ----------------------------------------------------------------------- |
68
+ | `c_base` | 1px | Always matches once a container exists; base style inside the container |
69
+ | `c_xs` | 480px | Matches viewport `xs` threshold, but on container width |
70
+ | `c_sm` | 768px | |
71
+ | `c_md` | 1024px | |
72
+ | `c_lg` | 1200px | |
73
+ | `c_xl` | 1440px | |
74
+
75
+ Requirements
76
+
77
+ - A descendant of an element that establishes a container — e.g. parent `<FlexBox containerType="inline-size">` (or other `container-type`). Without that, `c_*` rules never match.
78
+ - Prefer a viewport fallback alongside `c_*` (e.g. `display={{ _: 'block', sm: 'flex', c_md: 'grid' }}`) for browsers or trees without container support.
79
+
80
+ Object vs array
81
+
82
+ - Object: `p={{ _: 8, c_md: 24 }}` — readable for a few container-only overrides.
83
+ - Array: after the six viewport slots (`_` through `xl`), indices 6–11 are `c_base`, `c_xs`, `c_sm`, `c_md`, `c_lg`, `c_xl` respectively. Use when you need the full ordered chain.
84
+
85
+ When to use which
46
86
 
47
- Container query variants (`c_xs`–`c_xl`) mirror these values but trigger on component width.
87
+ - Viewport keys (`_`, `xs`, … `xl`) page-level layout, full-bleed sections, global nav.
88
+ - Container keys (`c_base`, … `c_xl`) — reusable widgets whose width is driven by layout, not the device alone.
48
89
 
49
- ## Grid
90
+ ## Page layout grid (12 columns)
50
91
 
51
- 12-column grid at all breakpoints.
92
+ 12-column grid at all breakpoints. Tier columns group breakpoints with identical margin/gutter/row-gap numbers from [Layout](https://gamut.codecademy.com/?path=/docs-foundations-layout--docs).
52
93
 
53
- | Property | xl/lg | md | sm/xs | base |
54
- |---|---|---|---|---|
55
- | Horizontal margins | 64px | 48px | 32px | 16px |
56
- | Column gutters | 32px | 24px | 16px | 8px |
57
- | Row gaps | 32px | 24px | 16px | 8px |
94
+ | Property | xl/lg | md | sm/xs | base |
95
+ | ------------------ | ----- | ---- | ----- | ---- |
96
+ | Horizontal margins | 64px | 48px | 32px | 16px |
97
+ | Column gutters | 32px | 24px | 16px | 8px |
98
+ | Row gaps | 32px | 24px | 16px | 8px |
58
99
 
59
- Minimum touch target on mobile: **44×44px**.
100
+ Minimum touch target on mobile: 44×44px — see `gamut-accessibility` skill for hit-target guidance.
60
101
 
61
102
  ## Responsive rules
62
103
 
@@ -1,50 +1,82 @@
1
1
  # Typography
2
2
 
3
- ## Typefaces
3
+ Use theme typography tokens (`fontFamily`, `fontSize`, `fontWeight`, `lineHeight`) — never hardcoded font-family strings or magic px for product UI. Prefer `<Text>` from `@codecademy/gamut`, or `system.typography` / `css()` from `@codecademy/gamut-styles` ([`gamut-system-props` skill](../../skills/gamut-system-props/SKILL.md)).
4
4
 
5
- | Token | Codecademy font | Non-Codecademy | Use for |
6
- |---|---|---|---|
7
- | `base` | Apercu Pro | Hanken Grotesk | All UI text, headlines, body copy |
8
- | `accent` | Suisse Intl Mono | Hanken Grotesk | Code, captions, labels, technical context |
9
- | `monospace` | Monaco / Menlo / Consolas | Monaco / Menlo / Consolas | Code editor contexts |
5
+ Source of truth for scales and stacks: [`packages/gamut-styles/src/variables/typography.ts`](https://github.com/Codecademy/gamut/blob/main/packages/gamut-styles/src/variables/typography.ts) and theme builders under [`packages/gamut-styles/src/themes`](https://github.com/Codecademy/gamut/tree/main/packages/gamut-styles/src/themes).
10
6
 
11
- Percipio overrides all families to Roboto. Apercu is licensed for codecademy.com only.
7
+ Storybook: [Typography / Text](https://gamut.codecademy.com/?path=/docs-typography-text--docs) · [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) (system props) · Foundations / Theme: [Core](https://gamut.codecademy.com/?path=/docs-foundations-theme-core-theme--docs), [Percipio](https://gamut.codecademy.com/?path=/docs-foundations-theme-percipio-theme--docs), [LX Studio](https://gamut.codecademy.com/?path=/docs-foundations-theme-lx-studio-theme--docs)
8
+
9
+ ## Themes × font families
10
+
11
+ Semantic keys (`base`, `accent`, `monospace`, `system`) are stable; resolved stacks depend on `GamutProvider` theme ([`setup.md`](../setup.md)).
12
+
13
+ | Theme | `fontFamily.base` | `fontFamily.accent` | `fontFamily.monospace` | `fontFamily.system` |
14
+ | --------------------- | ------------------------------------ | ------------------------------------- | -------------------------------------- | ------------------------------ |
15
+ | Core, Admin, Platform | Apercu stack (`fontBase`) | Suisse + Apercu stack (`fontAccent`) | Monaco / Menlo stack (`fontMonospace`) | System UI stack (`fontSystem`) |
16
+ | Percipio | Skillsoft Text (`fontPercipioBase`) | Skillsoft Sans (`fontPercipioAccent`) | Roboto Mono | Roboto (`system`) |
17
+ | LX Studio | Same as Percipio (`base` / `accent`) | Same | Same stack as Core (`fontMonospace`) | Same as Core (`fontSystem`) |
18
+
19
+ Admin and Platform extend Core for colors / modes only — typography matches Core.
20
+
21
+ Licensing: Apercu is licensed for Codecademy surfaces only; Skillsoft products use Percipio/LX stacks above.
12
22
 
13
23
  ## Font size scale
14
24
 
15
- | Token | Size | Common use |
16
- |---|---|---|
17
- | `64` | 64px | Hero / display |
18
- | `44` | 44px | Page titles |
19
- | `34` | 34px | Section titles |
20
- | `26` | 26px | Sub-section titles |
21
- | `22` | 22px | Card titles, large UI labels |
22
- | `20` | 20px | Secondary titles |
23
- | `18` | 18px | Large body, intro text |
24
- | `16` | 16px | Default body text |
25
- | `14` | 14px | Small body, captions, labels |
26
-
27
- ## Font weight
28
-
29
- | Token | Value | Use |
30
- |---|---|---|
31
- | `base` | 400 | Body text, UI labels |
32
- | `title` | 700 | Headlines, CTAs, buttons |
25
+ Values are `rem`-backed keys on `theme.fontSize` (aliases shown as px for readability).
26
+
27
+ | Token | Size | Common use |
28
+ | ----- | ---- | ---------------------------- |
29
+ | `64` | 64px | Hero / display |
30
+ | `44` | 44px | Page titles |
31
+ | `34` | 34px | Section titles |
32
+ | `26` | 26px | Sub-section titles |
33
+ | `22` | 22px | Card titles, large UI labels |
34
+ | `20` | 20px | Secondary titles |
35
+ | `18` | 18px | Large body, intro text |
36
+ | `16` | 16px | Default body text |
37
+ | `14` | 14px | Small body, captions, labels |
33
38
 
34
39
  ## Line height
35
40
 
36
- | Token | Value | Use |
37
- |---|---|---|
38
- | `base` | 1.5 | Body text |
39
- | `spacedTitle` | 1.3 | Sub-headlines, medium titles |
40
- | `title` | 1.2 | Large headlines |
41
+ | Token | Value | Use |
42
+ | ------------- | ----- | ---------------------------- |
43
+ | `base` | 1.5 | Body text |
44
+ | `spacedTitle` | 1.3 | Sub-headlines, medium titles |
45
+ | `title` | 1.2 | Large headlines |
46
+
47
+ ## Font weight (semantic)
48
+
49
+ Use semantic keys on components — do not assume a numeric bold everywhere.
50
+
51
+ | Token | Core / Admin / Platform | Percipio / LX Studio |
52
+ | ------- | ----------------------- | ----------------------------- |
53
+ | `base` | 400 | 400 |
54
+ | `title` | 700 | 500 (`fontWeightMediumTitle`) |
55
+
56
+ Headlines, CTAs, and buttons should use `fontWeight="title"` so Percipio/LX get 500, Core gets 700. Literal `700` breaks Skillsoft branding on those themes.
57
+
58
+ Numeric `400` and `700` keys also exist on the theme for rare explicit needs.
59
+
60
+ ## Codecademy (Core / Admin / Platform) — voice & layout
61
+
62
+ These UX rules target Apercu + Suisse products; do not blindly apply to Percipio/LX without brand guidance.
63
+
64
+ - `fontFamily="base"` (Apercu): default UI and marketing type. Emphasis inside body copy: Italic, not Bold for intra-paragraph stress.
65
+ - `fontFamily="accent"` (Suisse stack): technical accent — code snippets, captions, labels with engineering flavor, figures. Use sparingly; glyph box reads larger — step down ~10–15% vs equivalent `base` size; give comfortable line-height.
66
+ - Alignment: left-align by default; center only short marketing headlines; avoid right-align except tabs / numerics.
67
+ - Letter-spacing: do not tweak tracking unless design specifies.
68
+ - Line length: ~45–85 characters per line (~66 ideal for single-column body); constrain container width, not arbitrary CSS letter-spacing.
69
+
70
+ ## Line length (all products)
41
71
 
42
- Target 45–85 characters per line (66 ideal for web body text).
72
+ | Context | Target |
73
+ | ------------------ | ------------------- |
74
+ | Single-column body | ~66 chars (max ~85) |
75
+ | Multi-column | ≤50 chars per line |
76
+ | Minimum | ~45 chars |
43
77
 
44
- ## Rules
78
+ ## Related skills
45
79
 
46
- - Use `title` weight (700) for headlines, CTAs, and buttons.
47
- - Use Apercu Italic to emphasize within a Regular paragraph not Bold.
48
- - Use `accent` (Suisse) sparingly: code snippets, captions, enumerated items. Suisse reads ~10–15% large size it down relative to Apercu equivalents.
49
- - Left-align text by default. Center-align only for short marketing headlines. Never right-align.
50
- - Do not adjust letter-spacing.
80
+ - [`gamut-typography`](../../skills/gamut-typography/SKILL.md) deeper editorial patterns for agents.
81
+ - [`gamut-style-utilities`](../../skills/gamut-style-utilities/SKILL.md) `css()` / `variant` / `states` and tokenized typography in styled components.
82
+ - [`gamut-theming`](../../skills/gamut-theming/SKILL.md) — which theme / `GamutProvider` / `theme.d.ts`.
@@ -0,0 +1,19 @@
1
+ # Icons
2
+
3
+ Icons must come from `@codecademy/gamut-icons`. Do not import or generate icons from other sources. If a needed icon is unavailable, pick a verified alternative from the library or flag for confirmation — do not substitute non-system assets.
4
+
5
+ ## Identifying the correct icon
6
+
7
+ Do not rely on Figma layer names (`data-name`). Layer names are often stale after icon swaps.
8
+
9
+ Determine the correct icon by:
10
+
11
+ 1. Reading the design image — visually identify the shape (three vertical dots → kebab menu, 3×3 grid → app switcher, etc.).
12
+ 2. Using contextual clues — tooltip text, element purpose, surrounding UI patterns.
13
+ 3. Cross-referencing exports — search `@codecademy/gamut-icons` for icons matching visual and semantic intent.
14
+ 4. Treating layer names as hints only — if a layer name conflicts with visual/contextual evidence, trust the evidence.
15
+ 5. When uncertain, flag for confirmation rather than guessing.
16
+
17
+ Before using any icon, confirm it exists in `@codecademy/gamut-icons` (`packages/gamut-icons/src` or package exports).
18
+
19
+ Storybook: [Foundations / Icons](https://gamut.codecademy.com/?path=/docs-foundations-icons--page)
@@ -0,0 +1,7 @@
1
+ # Illustrations
2
+
3
+ Illustrations must come from `@codecademy/gamut-illustrations`. Do not generate or import illustrations from other sources.
4
+
5
+ If the correct illustration is unavailable, flag for confirmation rather than substituting a non-system asset.
6
+
7
+ Storybook: [Illustrations](https://gamut.codecademy.com/?path=/docs-illustrations--page) · `packages/gamut-illustrations/src` exports.
@@ -0,0 +1,7 @@
1
+ # Patterns
2
+
3
+ Patterns must come from `@codecademy/gamut-patterns`. Match Figma component names to pattern exports when possible.
4
+
5
+ If the correct pattern is unavailable, flag for confirmation rather than substituting a non-system asset.
6
+
7
+ Storybook: browse pattern stories under the Gamut styleguide, or inspect `packages/gamut-patterns/src` exports.