@codecademy/gamut

72.3.072.3.1-alpha.f273fd.0
agent-tools/DESIGN.LXStudio.md
~agent-tools/DESIGN.LXStudio.mdModified
+60−51
Index: package/agent-tools/DESIGN.LXStudio.md
===================================================================
--- package/agent-tools/DESIGN.LXStudio.md
+++ package/agent-tools/DESIGN.LXStudio.md
@@ -140,90 +140,99 @@
 
 **Design philosophy**:
 
 - Larger border radii (`sm`–`lg`) for a softer, more modern feel
-- Brand blue (`sapphire` / `primary`) drives CTAs, buttons, and links
+- Brand blue (`sapphire` / `primary`) drives CTAs, buttons, and links in **light mode** — in dark mode `primary` falls back to Core's `yellow-500`, not `sapphire` (see Semantic Color Aliases)
 - Soft shadows (`shadow-primary` → `navy-200`)
 - Skillsoft Text (`base`) and Skillsoft Sans (`accent`) for all UI typography
+- Dark mode is supported but not bespoke — `lxStudioTheme` only overrides light-mode tokens (see `packages/gamut-styles/src/themes/lxStudio.ts`); dark mode falls back to Core's dark palette unmodified
 
 ---
 
 ## Themes
 
-LX Studio uses a single Gamut theme — light mode only.
+LX Studio uses a single Gamut theme with both light and dark modes.
 
-| Theme         | Use case                               | Base font             | Dark mode  |
-| ------------- | -------------------------------------- | --------------------- | ---------- |
-| **LX Studio** | Skillsoft LX Studio authoring platform | Skillsoft Text / Sans | light only |
+| Theme         | Use case                               | Base font             | Dark mode                                             |
+| ------------- | -------------------------------------- | --------------------- | ----------------------------------------------------- |
+| **LX Studio** | Skillsoft LX Studio authoring platform | Skillsoft Text / Sans | ✓ light + dark (dark inherited from Core, unmodified) |
 
-The active theme is set at the app root via `<GamutProvider theme={lxStudioTheme}>`.
+The active theme is set at the app root via `<GamutProvider theme={lxStudioTheme}>`. `lxStudioTheme` calls `.addColorModes('light', { light: {...} })` with **only** a `light` override map — there is no `dark` key in the theme definition, so every semantic token falls back to Core's `dark` values for that token when the app is in dark mode. This is different from `adminTheme`/`platformTheme`, which define their own explicit `dark` overrides on top of Core.
 
 ---
 
 ## Semantic Color Aliases
 
-Use these token names when specifying colors. LX Studio is light mode only — there are no dark mode counterparts.
+Use these token names when specifying colors — they work in both light and dark mode via `<ColorMode>`. **Light** below is LX Studio's own value where it overrides Core (in `lxStudio.ts`); everywhere else, Light is simply inherited from Core. **Dark** is always Core's unmodified dark value for that token, since `lxStudioTheme` never defines a `dark` override map.
 
 ### Text
 
-| Token            | Resolves to | Use for                     |
-| ---------------- | ----------- | --------------------------- |
-| `text`           | `navy-800`  | Default body and UI text    |
-| `text-accent`    | `navy-900`  | Stronger emphasis text      |
-| `text-secondary` | `navy-600`  | Supporting / secondary copy |
-| `text-disabled`  | `navy-500`  | Disabled state labels       |
+Not overridden by LX Studio at all — these are Core's values in both modes.
 
+| Token            | Light      | Dark        | Use for                     |
+| ---------------- | ---------- | ----------- | --------------------------- |
+| `text`           | `navy-800` | `white`     | Default body and UI text    |
+| `text-accent`    | `navy-900` | `beige`     | Stronger emphasis text      |
+| `text-secondary` | `navy-600` | `white-600` | Supporting / secondary copy |
+| `text-disabled`  | `navy-500` | `white-500` | Disabled state labels       |
+
 ### Background
 
-| Token                 | Resolves to         | Use for                           |
-| --------------------- | ------------------- | --------------------------------- |
-| `background`          | `white`             | Default page/component background |
-| `background-primary`  | `lxStudioBgPrimary` | Slightly elevated surfaces        |
-| `background-contrast` | `white`             | Maximum contrast surface          |
-| `background-selected` | `navy-100`          | Selected row / item               |
-| `background-hover`    | `navy-200`          | Hover state overlay               |
-| `background-disabled` | `navy-200`          | Disabled surface                  |
-| `background-success`  | `green-0`           | Success state container           |
-| `background-warning`  | `yellow-0`          | Warning state container           |
-| `background-error`    | `red-0`             | Error state container             |
+| Token                 | Light               | Dark         | Use for                           |
+| --------------------- | ------------------- | ------------ | --------------------------------- |
+| `background`          | `white`             | `navy-800`   | Default page/component background |
+| `background-primary`  | `lxStudioBgPrimary` | `navy-900`   | Slightly elevated surfaces        |
+| `background-contrast` | `white`             | `black`      | Maximum contrast surface          |
+| `background-selected` | `navy-100`          | `white-100`  | Selected row / item               |
+| `background-hover`    | `navy-200`          | `white-200`  | Hover state overlay               |
+| `background-disabled` | `navy-200`          | `white-200`  | Disabled surface                  |
+| `background-success`  | `green-0`           | `green-900`  | Success state container           |
+| `background-warning`  | `yellow-0`          | `yellow-900` | Warning state container           |
+| `background-error`    | `red-0`             | `red-900`    | Error state container             |
 
+`background-primary` is the only row LX Studio overrides in light mode (`lxStudioBgPrimary`); its dark value is Core's plain `navy-900`, not an LX-specific token.
+
 ### Interactive
 
-| Token             | Resolves to  | Use for                              |
-| ----------------- | ------------ | ------------------------------------ |
-| `primary`         | `sapphire`   | Primary CTA, links, focus rings      |
-| `primary-hover`   | `navy-800`   | Hover state of primary interactive   |
-| `primary-inverse` | `yellow-500` | Primary on a colored background      |
-| `secondary`       | `navy-800`   | Secondary CTA, ghost buttons         |
-| `secondary-hover` | `navy-700`   | Hover state of secondary interactive |
-| `danger`          | `red-500`    | Destructive actions, error states    |
-| `danger-hover`    | `red-600`    | Hover on danger interactive          |
+| Token             | Light        | Dark         | Use for                              |
+| ----------------- | ------------ | ------------ | ------------------------------------ |
+| `primary`         | `sapphire`   | `yellow-500` | Primary CTA, links, focus rings      |
+| `primary-hover`   | `navy-800`   | `yellow-400` | Hover state of primary interactive   |
+| `primary-inverse` | `yellow-500` | `hyper-500`  | Primary on a colored background      |
+| `secondary`       | `navy-800`   | `white`      | Secondary CTA, ghost buttons         |
+| `secondary-hover` | `navy-700`   | `white-700`  | Hover state of secondary interactive |
+| `danger`          | `red-500`    | `red-300`    | Destructive actions, error states    |
+| `danger-hover`    | `red-600`    | `red-400`    | Hover on danger interactive          |
 
+**`primary` does not stay LX Studio's brand blue in dark mode.** `sapphire`/`navy-800` are light-mode-only overrides; dark mode uses Core's `yellow-500`/`yellow-400` (the same values Core itself uses), since `lxStudioTheme` never defines a `dark` override. If a design calls for `sapphire` to persist in dark mode, that requires an actual theme change, not a documentation fix.
+
 ### Border
 
-| Token              | Resolves to | Use for                         |
-| ------------------ | ----------- | ------------------------------- |
-| `border-primary`   | `navy-400`  | Standard input and card borders |
-| `border-secondary` | `navy-600`  | Medium-weight borders           |
-| `border-tertiary`  | `navy-800`  | Strong structural borders       |
-| `border-disabled`  | `navy-300`  | Disabled input borders          |
+| Token              | Light      | Dark        | Use for                         |
+| ------------------ | ---------- | ----------- | ------------------------------- |
+| `border-primary`   | `navy-400` | `white`     | Standard input and card borders |
+| `border-secondary` | `navy-600` | `white-600` | Medium-weight borders           |
+| `border-tertiary`  | `navy-800` | `white-300` | Strong structural borders       |
+| `border-disabled`  | `navy-300` | `white-500` | Disabled input borders          |
 
-`border-primary` resolves to `navy-400` — mid-weight borders for inputs and cards.
+`border-primary` resolves to `navy-400` in light mode — mid-weight borders for inputs and cards. `border-secondary` is the only row here LX Studio does not override; it's inherited from Core in both modes.
 
 ### Feedback
 
-| Token              | Resolves to       | Use for                          |
-| ------------------ | ----------------- | -------------------------------- |
-| `feedback-error`   | `red-600`         | Error messages, validation       |
-| `feedback-success` | `lxStudioSuccess` | Success messages, confirmations  |
-| `feedback-warning` | `yellow-500`      | Warning messages, caution states |
+| Token              | Light             | Dark        | Use for                          |
+| ------------------ | ----------------- | ----------- | -------------------------------- |
+| `feedback-error`   | `red-600`         | `red-300`   | Error messages, validation       |
+| `feedback-success` | `lxStudioSuccess` | `green-400` | Success messages, confirmations  |
+| `feedback-warning` | `yellow-500`      | `yellow-0`  | Warning messages, caution states |
 
+`feedback-error` and `feedback-warning` are inherited from Core in light mode too (not LX-specific); `feedback-success` is LX Studio's own light override, but its dark value falls back to Core's `green-400`, not `lxStudioSuccess`.
+
 ### Shadow
 
-| Token              | Resolves to |
-| ------------------ | ----------- |
-| `shadow-primary`   | `navy-200`  |
-| `shadow-secondary` | `navy-600`  |
+| Token              | Light      | Dark        |
+| ------------------ | ---------- | ----------- |
+| `shadow-primary`   | `navy-200` | `white`     |
+| `shadow-secondary` | `navy-600` | `white-600` |
 
 Use `shadow-primary` for standard elevated surfaces.
 
 ---
@@ -379,10 +388,10 @@
 
 ### Colors
 
 - **Do** use semantic color aliases (`primary`, `text`, `background`, etc.) — never hardcode hex values.
-- **Do** use `primary` (resolves to palette `sapphire`) for buttons and links.
-- **Don't** attempt dark mode — LX Studio is light only.
+- **Do** use `primary` (resolves to palette `sapphire` in light mode) for buttons and links.
+- **Don't** assume LX Studio has a bespoke dark palette — it inherits Core's dark values unmodified (see Semantic Color Aliases). `primary` in particular becomes Core's `yellow-500` in dark mode, not `sapphire` — verify visually rather than assuming brand color persists.
 - **Don't** use raw palette swatches for adaptive UI — use semantic aliases.
 
 ### Typography