@codecademy/gamut 68.6.1-alpha.c211a2.0 → 68.6.1-alpha.df4bce.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 (36) hide show
  1. package/agent-tools/.claude-plugin/marketplace.json +16 -0
  2. package/agent-tools/.claude-plugin/plugin.json +7 -0
  3. package/agent-tools/.cursor-plugin/plugin.json +7 -0
  4. package/agent-tools/DESIGN.Codecademy.md +643 -0
  5. package/agent-tools/DESIGN.LXStudio.md +444 -0
  6. package/agent-tools/DESIGN.Percipio.md +435 -0
  7. package/agent-tools/DESIGN.md +1 -0
  8. package/agent-tools/agents/.gitkeep +0 -0
  9. package/agent-tools/commands/gamut-review.md +231 -0
  10. package/agent-tools/guidelines/components/buttons.md +91 -0
  11. package/agent-tools/guidelines/components/overview.md +52 -0
  12. package/agent-tools/guidelines/foundations/color.md +172 -0
  13. package/agent-tools/guidelines/foundations/modes.md +47 -0
  14. package/agent-tools/guidelines/foundations/spacing.md +107 -0
  15. package/agent-tools/guidelines/foundations/typography.md +83 -0
  16. package/agent-tools/guidelines/overview.md +40 -0
  17. package/agent-tools/guidelines/setup.md +81 -0
  18. package/agent-tools/rules/accessibility.mdc +78 -0
  19. package/agent-tools/skills/gamut-accessibility/SKILL.md +214 -0
  20. package/agent-tools/skills/gamut-color-mode/SKILL.md +138 -0
  21. package/agent-tools/skills/gamut-forms/SKILL.md +84 -0
  22. package/agent-tools/skills/gamut-system-props/SKILL.md +203 -0
  23. package/agent-tools/skills/gamut-testing/SKILL.md +221 -0
  24. package/agent-tools/skills/gamut-theming/SKILL.md +113 -0
  25. package/agent-tools/skills/gamut-typography/SKILL.md +75 -0
  26. package/bin/commands/plugin/install.mjs +173 -0
  27. package/bin/commands/plugin/list.mjs +105 -0
  28. package/bin/commands/plugin/remove.mjs +116 -0
  29. package/bin/commands/plugin/update.mjs +49 -0
  30. package/bin/gamut.mjs +92 -0
  31. package/bin/lib/claude.mjs +52 -0
  32. package/bin/lib/cursor.mjs +40 -0
  33. package/bin/lib/figma.mjs +49 -0
  34. package/bin/lib/resolve-plugin-dir.mjs +38 -0
  35. package/bin/lib/run-command.mjs +22 -0
  36. package/package.json +11 -8
@@ -0,0 +1,91 @@
1
+ # Buttons
2
+
3
+ Agent reference: which **button component** and which **`variant`** to use. Colors are wired inside each atom — consumers do **not** pass `color`, `bg`, hex, or semantic token names on stock buttons.
4
+
5
+ **Related docs:** [overview.md](../overview.md) (reading order) · [foundations/color.md](../foundations/color.md) and `gamut-color-mode` skill — semantic tokens for **custom** styled controls only, not stock button atoms · [foundations/modes.md](../foundations/modes.md) — ColorMode / `<Background>` when placing buttons on colored surfaces
6
+
7
+ **Storybook (UX source of truth):**
8
+
9
+ - [Atoms / Buttons / Button](https://gamut.codecademy.com/?path=/docs-atoms-buttons-button--docs) — variants, light/dark examples
10
+ - [FillButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-fillbutton--docs) · [StrokeButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-strokebutton--docs) · [TextButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-textbutton--docs) · [IconButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-iconbutton--docs) · [CTAButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-ctabutton--docs)
11
+ - [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) — semantic tokens for custom `css` / `variant` / `states`, not prebuilt atoms
12
+ - [UX Writing / Component guidelines / Buttons](https://gamut.codecademy.com/?path=/docs-ux-writing-component-guidelines-buttons--docs) — label copy
13
+
14
+ ## Component selection
15
+
16
+ | Component | Use for | Default `variant` |
17
+ | -------------- | --------------------------------------------- | ------------------------------------------------ |
18
+ | `FillButton` | Primary / high-emphasis actions | `primary` |
19
+ | `StrokeButton` | Secondary / outlined actions | `primary` (often pass `secondary` per Storybook) |
20
+ | `TextButton` | Low-emphasis, inline actions | `primary` |
21
+ | `IconButton` | Icon-only; requires `tip` and accessible name | `secondary` |
22
+ | `CTAButton` | Marketing / high-visibility CTA only | `primary` (only option) |
23
+
24
+ ## `variant` prop
25
+
26
+ Shared by `FillButton`, `StrokeButton`, `TextButton`, and `IconButton`. `CTAButton` only supports `primary`.
27
+
28
+ | `variant` | Typical use |
29
+ | ----------- | ------------------------------ |
30
+ | `primary` | Submit, main CTA |
31
+ | `secondary` | Close, cancel, low priority |
32
+ | `danger` | Destructive actions |
33
+ | `interface` | Controls styled like UI chrome |
34
+
35
+ ```tsx
36
+ <FillButton variant="primary">Submit</FillButton>
37
+ <StrokeButton variant="secondary">Cancel</StrokeButton>
38
+ <IconButton icon={SearchIcon} tip="Search" variant="secondary" />
39
+ <CTAButton>Try Pro for free</CTAButton>
40
+ ```
41
+
42
+ ## Sizes
43
+
44
+ `small` | `normal` (default) | `large`
45
+
46
+ ## Key props
47
+
48
+ | Prop | Type | Effect |
49
+ | -------------- | ----------------------------------------------------- | ------------------------------------------------ |
50
+ | `variant` | `"primary" \| "secondary" \| "danger" \| "interface"` | Color emphasis (see table above) |
51
+ | `size` | `"small" \| "normal" \| "large"` | Padding and font size |
52
+ | `icon` | Icon component | Leading or trailing icon (Fill, Stroke, Text) |
53
+ | `iconPosition` | `"left" \| "right"` | Defaults to left |
54
+ | `disabled` | boolean | Disabled state styling |
55
+ | `href` | string | Renders as `<a>` tag |
56
+ | `tip` | string | Required on `IconButton` (tooltip + hover label) |
57
+
58
+ ## States
59
+
60
+ Hover, active, and disabled colors are handled by the component. Do not override state colors with `color` / `bg` props.
61
+
62
+ ## Accessibility — `disabled` vs `aria-disabled`
63
+
64
+ | Situation | Use | Why |
65
+ | ------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
66
+ | Button should not be activatable (default) | `disabled` prop | Renders native `disabled` on `<button>`; removed from tab order; correct for most forms and actions |
67
+ | Disabled button **with a tooltip** that must stay readable on focus | `aria-disabled` only — **do not** also pass `disabled` | Native `disabled` blocks keyboard focus, so the tooltip cannot be reached. Gamut disabled **styles** also match `[aria-disabled='true']`. See [ToolTip — With a disabled Button](https://gamut.codecademy.com/?path=/docs-molecules-tips-tooltip--docs) |
68
+
69
+ ```tsx
70
+ // Default — not interactive
71
+ <FillButton disabled>Submit</FillButton>
72
+
73
+ // Disabled but focusable (e.g. wrapped in ToolTip explaining why)
74
+ <ToolTip id="why-disabled" info="Complete the lesson first">
75
+ <FillButton aria-describedby="why-disabled" aria-disabled>
76
+ Submit
77
+ </FillButton>
78
+ </ToolTip>
79
+ ```
80
+
81
+ - **`href` + `disabled`:** `ButtonBase` (internal) drops `href` and renders a `<button disabled>` — link-style buttons cannot stay anchors while disabled.
82
+ - **`IconButton`:** provide an accessible name via `tip` (used as `aria-label` when `aria-label` is omitted). See ToolTip / IconButton Storybook pages.
83
+ - **`ButtonBase` is not exported** from `@codecademy/gamut` (only the `ButtonBaseElements` type is). Prefer stock atoms; custom button styling belongs in Gamut itself or via `css` / `variant` from `gamut-styles`, not by importing `ButtonBase`.
84
+
85
+ ## Rules
86
+
87
+ - Use `FillButton` for primary actions and `StrokeButton` for secondary — do not use both at equal weight on the same screen.
88
+ - Reserve `CTAButton` for marketing / high-visibility promotions; do not use it for standard UI actions.
89
+ - Avoid placing buttons in the wrong color-mode context (e.g. light-mode buttons on a navy band without `<Background>`). See [modes.md](../foundations/modes.md).
90
+ - Every interactive `Card` wrapped in `<Anchor>` should have `isInteractive` — not a button inside.
91
+ - Do not set `color`, `bg`, or hex on stock button components. For custom styled controls, follow [color.md](../foundations/color.md) and `gamut-styles` utilities — do not import internal `ButtonBase`.
@@ -0,0 +1,52 @@
1
+ # Components
2
+
3
+ 52 components have Figma ↔ code mappings via Figma Code Connect (`packages/code-connect/`). Live code snippets appear in Figma's inspect panel when you select a component.
4
+
5
+ ## Atoms — foundational, single-purpose
6
+
7
+ Badge, Button (FillButton, StrokeButton, CTAButton, TextButton, IconButton), ButtonBase, Card, Checkbox, CodeBlock, ColorMode, Drawer, FlexBox, FormGroup, GridBox, HiddenText, Icon, Input, Label, Loader, Radio, Select, Spinner, Tag, TextArea, Toggle, Tooltip
8
+
9
+ ## Molecules — composed of atoms
10
+
11
+ Alert, Anchor, Breadcrumbs, Coachmark, Disclosure, GridForm, Markdown, Menu, Modal, Pagination, Popover, ProgressBar, Table, Tabs, Toast, Toaster, Video
12
+
13
+ ## Organisms — page-level compositions
14
+
15
+ ContentContainer, GridContainer, Layout, LayoutGrid
16
+
17
+ ## Key patterns
18
+
19
+ ### Buttons
20
+
21
+ See [buttons.md](buttons.md) for full reference. Use `FillButton` for primary actions, `StrokeButton` for secondary.
22
+
23
+ ### Forms and accessibility
24
+
25
+ **`FormGroup`**, **`GridForm`**, **`ConnectedForm`**, tips, dialogs, composite widgets: **[`skills/gamut-forms/SKILL.md`](../../skills/gamut-forms/SKILL.md)** (forms) · **[`skills/gamut-accessibility/SKILL.md`](../../skills/gamut-accessibility/SKILL.md)** (overlays, composites, checklists) · Storybook [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page).
26
+
27
+ ### Cards
28
+
29
+ - **Background variants**: `default` (ColorMode-responsive), `white`, `yellow`, `beige`, `navy`, `hyper`
30
+ - **Shadow variants**: `none` (default), `outline`, `patternLeft`, `patternRight`
31
+ - Add `isInteractive` when wrapping in `<Anchor>` — enables hover shadow + `borderRadius: md`
32
+ - Default `borderRadius` is `none`; override with `borderRadius` prop
33
+
34
+ ### Color-aware components
35
+
36
+ - `<ColorMode mode="light|dark|system">` — scopes a subtree to an explicit color mode
37
+ - `<Background bg="<color>">` — applies background color + auto-switches inner color mode for contrast
38
+
39
+ ### Alerts
40
+
41
+ | Variant | Tokens |
42
+ | ------- | ----------------------------------------- |
43
+ | Error | `feedback-error` + `background-error` |
44
+ | Success | `feedback-success` + `background-success` |
45
+ | Warning | `feedback-warning` + `background-warning` |
46
+
47
+ ## Global tokens
48
+
49
+ | Token | Value | Use |
50
+ | -------------- | ----------------------- | ------------------------------ |
51
+ | `headerHeight` | 64px (base), 80px (md+) | Global page header height |
52
+ | `headerZ` | 15 | Z-index for global page header |
@@ -0,0 +1,172 @@
1
+ # Color
2
+
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
+
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-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
+ | `interface` | Checkboxes, toggles, sliders | Pairs with `interface-hover` |
48
+ | `interface-hover` | Hover on interface elements | |
49
+ | `danger` | Destructive actions, error emphasis | Pairs with `danger-hover` |
50
+ | `danger-hover` | Hover on danger interactive | |
51
+
52
+ ### Border
53
+
54
+ | Token | Use for | Notes |
55
+ | ------------------ | -------------------------- | ----- |
56
+ | `border-primary` | Strong borders, dividers | |
57
+ | `border-secondary` | Medium-weight borders | |
58
+ | `border-tertiary` | Subtle borders, separators | |
59
+ | `border-disabled` | Disabled input borders | |
60
+
61
+ ### Feedback
62
+
63
+ | Token | Use for | Notes |
64
+ | ------------------ | -------------------------- | ----- |
65
+ | `feedback-error` | Error messages, validation | |
66
+ | `feedback-success` | Success messages | |
67
+ | `feedback-warning` | Warning messages | |
68
+
69
+ ## Where resolved colors are documented
70
+
71
+ Use these instead of memorizing hex:
72
+
73
+ - **Storybook [ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page)** — how aliases map per light/dark for reference layouts.
74
+ - **Storybook Foundations → Theme** — per-product tables and guidance:
75
+ - [Core Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-core-theme--docs)
76
+ - [Admin Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-admin-theme--docs)
77
+ - [Platform Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-platform-theme--docs)
78
+ - [Percipio Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-percipio-theme--docs)
79
+ - [LX Studio Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-lx-studio-theme--docs)
80
+ - [Creating Themes](https://gamut.codecademy.com/?path=/docs-foundations-theme-creating-themes--docs) — authoring new themes in `gamut-styles`
81
+ - **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.
82
+ - **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).
83
+
84
+ ## Codecademy Core — illustrative light/dark hex only
85
+
86
+ The tables below are **not** valid for Percipio, LX Studio, or other themes. They are a quick mental model for Codecademy **Core** defaults only.
87
+
88
+ ### Text
89
+
90
+ | Token | Light | Dark |
91
+ | ---------------- | ------------ | --------- |
92
+ | `text` | `#10162F` | `#ffffff` |
93
+ | `text-accent` | `#0A0D1C` | `#FFF0E5` |
94
+ | `text-secondary` | navy-800 75% | white 65% |
95
+ | `text-disabled` | navy-800 63% | white 50% |
96
+
97
+ ### Background
98
+
99
+ | Token | Light | Dark |
100
+ | --------------------- | ------------ | --------- |
101
+ | `background` | `#ffffff` | `#10162F` |
102
+ | `background-primary` | `#FFF0E5` | `#0A0D1C` |
103
+ | `background-contrast` | white | black |
104
+ | `background-selected` | navy-800 4% | white 4% |
105
+ | `background-hover` | navy-800 12% | white 9% |
106
+ | `background-disabled` | navy-800 12% | white 9% |
107
+ | `background-success` | `#F5FFE3` | `#151C07` |
108
+ | `background-warning` | `#FFFAE5` | `#211B00` |
109
+ | `background-error` | `#FBF1F0` | `#280503` |
110
+
111
+ ### Interactive
112
+
113
+ | Token | Light | Dark |
114
+ | ----------------- | ------------ | --------- |
115
+ | `primary` | `#3A10E5` | `#FFD300` |
116
+ | `primary-hover` | `#5533FF` | `#CCA900` |
117
+ | `primary-inverse` | `#FFD300` | `#3A10E5` |
118
+ | `secondary` | `#10162F` | `#ffffff` |
119
+ | `secondary-hover` | navy-800 86% | white 80% |
120
+ | `interface` | `#3A10E5` | `#FFD300` |
121
+ | `interface-hover` | `#5533FF` | `#CCA900` |
122
+ | `danger` | `#E91C11` | `#E85D7F` |
123
+ | `danger-hover` | `#BE1809` | `#DC5879` |
124
+
125
+ ### Border
126
+
127
+ | Token | Light | Dark |
128
+ | ------------------ | ------------ | --------- |
129
+ | `border-primary` | `#10162F` | `#ffffff` |
130
+ | `border-secondary` | navy-800 75% | white 65% |
131
+ | `border-tertiary` | navy-800 28% | white 20% |
132
+ | `border-disabled` | navy-800 63% | white 50% |
133
+
134
+ ### Feedback
135
+
136
+ | Token | Light | Dark |
137
+ | ------------------ | --------- | --------- |
138
+ | `feedback-error` | `#BE1809` | `#E85D7F` |
139
+ | `feedback-success` | `#008A27` | `#AEE938` |
140
+ | `feedback-warning` | `#FFD300` | `#FFFAE5` |
141
+
142
+ ## Raw palette (Core-centric reference)
143
+
144
+ 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.
145
+
146
+ For Codecademy Core defaults:
147
+
148
+ | Name | Weights | Key values (illustrative) |
149
+ | -------- | -------------------------- | -------------------------------- |
150
+ | `navy` | 100–900 | 800 = `#10162F`, 900 = `#0A0D1C` |
151
+ | `hyper` | 400, 500 | 500 = `#3A10E5`, 400 = `#5533FF` |
152
+ | `yellow` | 0, 400, 500, 900 | 500 = `#FFD300` |
153
+ | `red` | 0, 300, 400, 500, 600, 900 | 500 = `#E91C11` |
154
+ | `green` | 0, 100, 400, 700, 900 | 700 = `#008A27` |
155
+ | `blue` | 0, 100, 300, 400, 500, 800 | 500 = `#1557FF` |
156
+ | `beige` | — | `#FFF0E5` |
157
+ | `pink` | 0, 400 | 400 = `#F966FF` |
158
+ | `orange` | 100, 500 | 500 = `#FF8C00` |
159
+
160
+ Named shorthand aliases commonly used on Core surfaces: `beige`, `blue`, `green`, `hyper`, `navy`, `orange`, `pink`, `red`, `yellow`, `black`, `white`
161
+
162
+ ## Decision guide
163
+
164
+ ```
165
+ Which product theme is GamutProvider using?
166
+ └─ Unknown → check setup.md / DESIGN.md / Storybook theme page before assuming hex or palette name
167
+
168
+ Coloring UI text or backgrounds?
169
+ └─ Must adapt to light/dark OR theme? → semantic alias (text, background, primary, …)
170
+ └─ Must stay fixed regardless of mode? → raw palette token (confirm key exists in that theme)
171
+ └─ Section background with content inside? → <Background bg="…"> (see modes.md)
172
+ ```
@@ -0,0 +1,47 @@
1
+ # Color Modes
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.
4
+
5
+ ## `<ColorMode>`
6
+
7
+ Wraps a subtree in an explicit color mode. Nest to create scoped mode regions.
8
+
9
+ ```tsx
10
+ import { ColorMode } from '@codecademy/gamut-styles';
11
+
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
15
+ ```
16
+
17
+ **Props**: `mode="light" | "dark" | "system"`
18
+
19
+ ## `<Background>`
20
+
21
+ Use `<Background>` — not a raw `bg` prop — whenever setting a colored background on a section that contains text or interactive elements. It automatically switches the color mode inside to maintain accessible contrast.
22
+
23
+ ```tsx
24
+ import { Background } from '@codecademy/gamut-styles';
25
+
26
+ <Background bg="hyper">{children}</Background>;
27
+ ```
28
+
29
+ Nesting is supported — each `<Background>` creates its own accessible color context.
30
+
31
+ ## Hooks
32
+
33
+ | Hook | Returns | Use |
34
+ | ---------------------- | --------------------------------- | ------------------------------------------------- |
35
+ | `useCurrentMode()` | `"light" \| "dark"` | Active mode key only |
36
+ | `useColorMode()` | `[modeKey, modeColors, allModes]` | Full mode data + resolver for semantic color keys |
37
+ | `usePrefersDarkMode()` | `boolean` | Read OS dark preference only |
38
+
39
+ Import from `@codecademy/gamut-styles`.
40
+
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)
42
+
43
+ ## Common mistakes
44
+
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.
@@ -0,0 +1,107 @@
1
+ # Spacing, Border Radius & Layout
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
+
16
+ ## Spacing scale
17
+
18
+ All spacing is multiples of 4px on an 8px grid.
19
+
20
+ | Token | Value |
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 |
33
+
34
+ Use multiples of 8px for block-element spacing. Use 4px only for inline or typographic relationships.
35
+
36
+ ## Border radius
37
+
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 |
46
+
47
+ ## Breakpoints
48
+
49
+ Mobile-first. Styles apply from the named breakpoint and up.
50
+
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**
86
+
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.
89
+
90
+ ## Page layout grid (12 columns)
91
+
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).
93
+
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 |
99
+
100
+ Minimum touch target on mobile: **44×44px** — see `gamut-accessibility` skill for hit-target guidance.
101
+
102
+ ## Responsive rules
103
+
104
+ - Begin design work at 1440px (XL), then adapt down.
105
+ - Multi-column layouts collapse to fewer columns — do not stretch or squish.
106
+ - Catalog cards and non-lockup elements should align on one axis (usually left), not fill column widths.
107
+ - Avoid dense or small components at the base (mobile) breakpoint.
@@ -0,0 +1,83 @@
1
+ # Typography
2
+
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
+
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).
6
+
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
+ **DESIGN.md drift:** [`DESIGN.Percipio.md`](../../DESIGN.Percipio.md) and [`DESIGN.LXStudio.md`](../../DESIGN.LXStudio.md) sometimes describe **Roboto** or **Hanken Grotesk** for those products. **Shipped `gamut-styles` themes** currently use the stacks below (Skillsoft Text / Sans). Treat DESIGN YAML as product narrative until it matches code — confirm with the design platform when they disagree.
10
+
11
+ ## Themes × font families
12
+
13
+ Semantic keys (`base`, `accent`, `monospace`, `system`) are stable; resolved stacks depend on `GamutProvider` theme ([`setup.md`](../setup.md)).
14
+
15
+ | Theme | `fontFamily.base` | `fontFamily.accent` | `fontFamily.monospace` | `fontFamily.system` |
16
+ | --------------------------------- | ------------------------------------ | ------------------------------------- | -------------------------------------- | ------------------------------ |
17
+ | **Core**, **Admin**, **Platform** | Apercu stack (`fontBase`) | Suisse + Apercu stack (`fontAccent`) | Monaco / Menlo stack (`fontMonospace`) | System UI stack (`fontSystem`) |
18
+ | **Percipio** | Skillsoft Text (`fontPercipioBase`) | Skillsoft Sans (`fontPercipioAccent`) | Roboto Mono | Roboto (`system`) |
19
+ | **LX Studio** | Same as Percipio (`base` / `accent`) | Same | Same stack as Core (`fontMonospace`) | Same as Core (`fontSystem`) |
20
+
21
+ Admin and Platform extend Core for colors / modes only — typography matches Core.
22
+
23
+ **Licensing:** Apercu is licensed for Codecademy surfaces only; Skillsoft products use Percipio/LX stacks above.
24
+
25
+ ## Font size scale
26
+
27
+ Values are `rem`-backed keys on `theme.fontSize` (aliases shown as px for readability).
28
+
29
+ | Token | Size | Common use |
30
+ | ----- | ---- | ---------------------------- |
31
+ | `64` | 64px | Hero / display |
32
+ | `44` | 44px | Page titles |
33
+ | `34` | 34px | Section titles |
34
+ | `26` | 26px | Sub-section titles |
35
+ | `22` | 22px | Card titles, large UI labels |
36
+ | `20` | 20px | Secondary titles |
37
+ | `18` | 18px | Large body, intro text |
38
+ | `16` | 16px | Default body text |
39
+ | `14` | 14px | Small body, captions, labels |
40
+
41
+ ## Line height
42
+
43
+ | Token | Value | Use |
44
+ | ------------- | ----- | ---------------------------- |
45
+ | `base` | 1.5 | Body text |
46
+ | `spacedTitle` | 1.3 | Sub-headlines, medium titles |
47
+ | `title` | 1.2 | Large headlines |
48
+
49
+ ## Font weight (semantic)
50
+
51
+ Use **semantic keys** on components — do not assume a numeric bold everywhere.
52
+
53
+ | Token | Core / Admin / Platform | Percipio / LX Studio |
54
+ | ------- | ----------------------- | --------------------------------- |
55
+ | `base` | 400 | 400 |
56
+ | `title` | **700** | **500** (`fontWeightMediumTitle`) |
57
+
58
+ Headlines, CTAs, and buttons should use **`fontWeight="title"`** so Percipio/LX get **500**, Core gets **700**. Literal `700` breaks Skillsoft branding on those themes.
59
+
60
+ Numeric **`400`** and **`700`** keys also exist on the theme for rare explicit needs.
61
+
62
+ ## Codecademy (Core / Admin / Platform) — voice & layout
63
+
64
+ These UX rules target **Apercu + Suisse** products; do not blindly apply to Percipio/LX without brand guidance.
65
+
66
+ - **`fontFamily="base"` (Apercu):** default UI and marketing type. Emphasis inside body copy: **Italic**, not Bold for intra-paragraph stress.
67
+ - **`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.
68
+ - **Alignment:** left-align by default; center only short marketing headlines; avoid right-align except tabs / numerics.
69
+ - **Letter-spacing:** do not tweak tracking unless design specifies.
70
+ - **Line length:** ~45–85 characters per line (~66 ideal for single-column body); constrain container width, not arbitrary CSS letter-spacing.
71
+
72
+ ## Line length (all products)
73
+
74
+ | Context | Target |
75
+ | ------------------ | ------------------- |
76
+ | Single-column body | ~66 chars (max ~85) |
77
+ | Multi-column | ≤50 chars per line |
78
+ | Minimum | ~45 chars |
79
+
80
+ ## Related skills
81
+
82
+ - [`gamut-typography`](../../skills/gamut-typography/SKILL.md) — deeper editorial patterns for agents.
83
+ - [`gamut-theming`](../../skills/gamut-theming/SKILL.md) — accessing `theme.font*` in styled components.
@@ -0,0 +1,40 @@
1
+ # Gamut Design System
2
+
3
+ Gamut is the Codecademy / Skillsoft design system — React component library (`@codecademy/gamut`), design tokens (`@codecademy/gamut-styles`), and Figma components with live code previews via Figma Code Connect.
4
+
5
+ **Design voice**: "Ruled by logic, but creative and a bit unexpected." Structured and trustworthy for a learning platform, with engaging personality. Medium density — information-rich layouts with strong typographic hierarchy. Never cramped or overly airy.
6
+
7
+ **Core principles**:
8
+
9
+ - Components are color mode–aware by default — never hardcode hex values for adaptive, accessible UI
10
+ - All components work across all themes without modification
11
+ - 12-column grid
12
+ - Use **semantic theme tokens** from `@codecademy/gamut-styles` for **color roles** (ColorMode-aware), **typography**, **spacing**, **border radii**, and shared **layout** values (`elements`, …) — not raw palette hex or magic numbers. Defaults support accessible pairings, but **no token set guarantees WCAG AA** for every composition; validate non-standard combinations.
13
+
14
+ **ColorMode in product UI:** Use `<ColorMode>` and `<Background>` from `@codecademy/gamut-styles` for scoped light/dark and contrast-safe surfaces — see [foundations/modes.md](foundations/modes.md) and the `gamut-color-mode` skill. Storybook: [ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page), [Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) (semantic tokens + `css` / `variant` / `states`).
15
+
16
+ ## Themes
17
+
18
+ Runtime stacks come from `@codecademy/gamut-styles` (see [foundations/typography.md](foundations/typography.md)). Product `DESIGN.*.md` may differ until reconciled.
19
+
20
+ | Theme | Product | Primary UI fonts (shipped theme) | Dark mode |
21
+ | ------------- | ------------------------------- | ------------------------------------------------------------------------------ | --------- |
22
+ | **Core** | Codecademy (default) | Apercu + Suisse (`accent`) | ✓ |
23
+ | **Admin** | Codecademy admin tools | Same as Core | ✓ |
24
+ | **Platform** | Codecademy learning environment | Same as Core | ✓ |
25
+ | **LX Studio** | LX Studio application | Skillsoft Text / Sans (`base` / `accent`); DESIGN docs may list Hanken Grotesk | — |
26
+ | **Percipio** | Skillsoft Percipio | Skillsoft Text / Sans; DESIGN docs may list Roboto | — |
27
+
28
+ Set the theme at the app root via `<GamutProvider theme={...}>`.
29
+
30
+ ## Reading order
31
+
32
+ | File | What it covers |
33
+ | ------------------------------------------------------ | ------------------------------------------------------------------------------ |
34
+ | [setup.md](setup.md) | Packages, GamutProvider, theme selection |
35
+ | [foundations/color.md](foundations/color.md) | Semantic roles (all themes), where to verify hex, Core-only cheatsheets |
36
+ | [foundations/modes.md](foundations/modes.md) | Light/dark ColorMode, Background component |
37
+ | [foundations/typography.md](foundations/typography.md) | Theme fonts, scales, semantic `title` weight (700 vs 500), Core voice rules |
38
+ | [foundations/spacing.md](foundations/spacing.md) | Spacing scale, radii, Layout grid; system props + responsive/container queries |
39
+ | [components/overview.md](components/overview.md) | Full component catalog |
40
+ | [components/buttons.md](components/buttons.md) | Button variants, props, decision tree |