@codecademy/gamut

72.3.072.3.1-alpha.f273fd.0
agent-tools/DESIGN.Percipio.md
~agent-tools/DESIGN.Percipio.mdModified
+55−51
Index: package/agent-tools/DESIGN.Percipio.md
===================================================================
--- package/agent-tools/DESIGN.Percipio.md
+++ package/agent-tools/DESIGN.Percipio.md
@@ -129,91 +129,95 @@
 **Density**: Medium. Information-dense layouts with softer shadows and a muted neutral palette.
 
 **Design philosophy**:
 
-- Light mode only — no dark mode support
-- Brand blue (`sapphire` / `primary`) for buttons, links, and focus rings
+- Dark mode is supported but not bespoke — `percipioTheme` only overrides light-mode tokens (see `packages/gamut-styles/src/themes/percipio.ts`); dark mode falls back to Core's dark palette unmodified (see Semantic Color Aliases below)
+- Brand blue (`sapphire` / `primary`) for buttons, links, and focus rings in **light mode** — in dark mode `primary` resolves to Core's `yellow-500`, not `sapphire`
 - Text uses dedicated Percipio palette tokens (`percipioTextPrimary`, etc.)
 - Shadows are soft and minimal (`shadow-primary` → `navy-200`)
 - Title font weight is **500** via `fontWeight="title"` — use semantic weight, not literal `700`
 
 ---
 
 ## Themes
 
-Percipio uses a single Gamut theme — light mode only.
+Percipio uses a single Gamut theme with both light and dark modes.
 
-| Theme        | Use case                    | Base font             | Dark mode  |
-| ------------ | --------------------------- | --------------------- | ---------- |
-| **Percipio** | Skillsoft Percipio platform | Skillsoft Text / Sans | light only |
+| Theme        | Use case                    | Base font             | Dark mode                                             |
+| ------------ | --------------------------- | --------------------- | ----------------------------------------------------- |
+| **Percipio** | Skillsoft Percipio platform | Skillsoft Text / Sans | ✓ light + dark (dark inherited from Core, unmodified) |
 
-The active theme is set at the app root via `<GamutProvider theme={percipioTheme}>`.
+The active theme is set at the app root via `<GamutProvider theme={percipioTheme}>`. `percipioTheme` 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. Percipio 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 Percipio's own value (overridden in `percipio.ts` where noted); **Dark** is Core's unmodified dark value for that same token, since `percipioTheme` never defines a `dark` override map. A token whose Light column is a plain palette name (not a `percipio*` token) is itself inherited from Core in light mode too — Percipio didn't touch it in either mode.
 
 ### Text
 
-| Token            | Resolves to             | Use for                                          |
-| ---------------- | ----------------------- | ------------------------------------------------ |
-| `text`           | `percipioTextPrimary`   | Default body and UI text                         |
-| `text-accent`    | `percipioTextPrimary`   | Emphasis text (same value as `text` in Percipio) |
-| `text-secondary` | `percipioTextSecondary` | Supporting / secondary copy                      |
-| `text-disabled`  | `percipioTextDisabled`  | Disabled state labels                            |
+| Token            | Light                                                 | Dark        | Use for                     |
+| ---------------- | ----------------------------------------------------- | ----------- | --------------------------- |
+| `text`           | `percipioTextPrimary`                                 | `white`     | Default body and UI text    |
+| `text-accent`    | `percipioTextAccent` (same hex as `text` in Percipio) | `beige`     | Stronger emphasis text      |
+| `text-secondary` | `percipioTextSecondary`                               | `white-600` | Supporting / secondary copy |
+| `text-disabled`  | `percipioTextDisabled`                                | `white-500` | Disabled state labels       |
 
 ### Background
 
-| Token                 | Resolves to         | Use for                           |
-| --------------------- | ------------------- | --------------------------------- |
-| `background`          | `white`             | Default page/component background |
-| `background-primary`  | `percipioBgPrimary` | Slightly elevated surfaces        |
-| `background-selected` | `navy-100`          | Selected row / item               |
-| `background-hover`    | `navy-200`          | Hover state overlay               |
-| `background-disabled` | `navy-200`          | Disabled surface                  |
-| `background-success`  | `percipioBgSuccess` | Success state container           |
-| `background-warning`  | `percipioBgWarning` | Warning state container           |
-| `background-error`    | `percipioBgError`   | Error state container             |
+| Token                 | Light               | Dark         | Use for                           |
+| --------------------- | ------------------- | ------------ | --------------------------------- |
+| `background`          | `white`             | `navy-800`   | Default page/component background |
+| `background-primary`  | `percipioBgPrimary` | `navy-900`   | Slightly elevated surfaces        |
+| `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`  | `percipioBgSuccess` | `green-900`  | Success state container           |
+| `background-warning`  | `percipioBgWarning` | `yellow-900` | Warning state container           |
+| `background-error`    | `percipioBgError`   | `red-900`    | Error state container             |
 
+Note the dark values for `background-primary`/`success`/`warning`/`error` are **Core's** dark tokens, not Percipio-specific — the `percipioBg*` tokens Percipio defines have no dark counterpart.
+
 ### Interactive
 
-| Token             | Resolves to                    | Use for                              |
-| ----------------- | ------------------------------ | ------------------------------------ |
-| `primary`         | `sapphire`                     | Primary CTA, links, focus rings      |
-| `primary-hover`   | `percipioActionPrimaryHover`   | Hover state of primary interactive   |
-| `primary-inverse` | `white`                        | Primary on a colored background      |
-| `secondary`       | `percipioActionSecondary`      | Secondary CTA, ghost buttons         |
-| `secondary-hover` | `percipioActionSecondaryHover` | Hover state of secondary interactive |
-| `danger`          | `percipioDanger`               | Destructive actions, error states    |
-| `danger-hover`    | `percipioActionDangerHover`    | Hover on danger interactive          |
+| Token             | Light                          | Dark         | Use for                              |
+| ----------------- | ------------------------------ | ------------ | ------------------------------------ |
+| `primary`         | `sapphire`                     | `yellow-500` | Primary CTA, links, focus rings      |
+| `primary-hover`   | `percipioActionPrimaryHover`   | `yellow-400` | Hover state of primary interactive   |
+| `primary-inverse` | `white`                        | `hyper-500`  | Primary on a colored background      |
+| `secondary`       | `percipioActionSecondary`      | `white`      | Secondary CTA, ghost buttons         |
+| `secondary-hover` | `percipioActionSecondaryHover` | `white-700`  | Hover state of secondary interactive |
+| `danger`          | `percipioDanger`               | `red-300`    | Destructive actions, error states    |
+| `danger-hover`    | `percipioActionDangerHover`    | `red-400`    | Hover on danger interactive          |
 
+**`primary` does not stay Percipio's brand blue in dark mode.** `sapphire` is a light-mode-only override; dark mode uses Core's `yellow-500` (the same value Core itself uses, since `percipioTheme` never defines a `dark` override). If a design calls for `sapphire` to persist in dark mode, that requires an actual theme change — adding a `dark` override to `percipioTheme` — not a documentation fix. Flag it rather than assuming the token already does this.
+
 ### Border
 
-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.
+Percipio's border weights use a non-standard order in light mode: `primary` is mid-weight, `secondary` is very light, `tertiary` is the strongest (solid navy). Use them for their semantic intent, not their numeric rank. Dark values are Core's unmodified dark borders.
 
-| Token              | Resolves to | Use for                             |
-| ------------------ | ----------- | ----------------------------------- |
-| `border-primary`   | `navy-400`  | Standard input and card borders     |
-| `border-secondary` | `navy-200`  | Subtle dividers, section separators |
-| `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` | Subtle dividers, section separators |
+| `border-tertiary`  | `navy-800` | `white-300` | Strong structural borders           |
+| `border-disabled`  | `navy-300` | `white-500` | Disabled input borders              |
 
 ### Feedback
 
-| Token              | Resolves to               | Use for                          |
-| ------------------ | ------------------------- | -------------------------------- |
-| `feedback-error`   | `percipioDanger`          | Error messages, validation       |
-| `feedback-success` | `percipioFeedbackSuccess` | Success messages, confirmations  |
-| `feedback-warning` | `percipioFeedbackWarning` | Warning messages, caution states |
+| Token              | Light                     | Dark        | Use for                          |
+| ------------------ | ------------------------- | ----------- | -------------------------------- |
+| `feedback-error`   | `percipioDanger`          | `red-300`   | Error messages, validation       |
+| `feedback-success` | `percipioFeedbackSuccess` | `green-400` | Success messages, confirmations  |
+| `feedback-warning` | `percipioFeedbackWarning` | `yellow-0`  | Warning messages, caution states |
 
 ### Shadow
 
-| Token              | Resolves to |
-| ------------------ | ----------- |
-| `shadow-primary`   | `navy-200`  |
-| `shadow-secondary` | `navy-400`  |
+| Token              | Light      | Dark        |
+| ------------------ | ---------- | ----------- |
+| `shadow-primary`   | `navy-200` | `white`     |
+| `shadow-secondary` | `navy-400` | `white-600` |
 
 Use `shadow-primary` for standard elevated surfaces.
 
 ---
@@ -377,10 +381,10 @@
 
 ### Colors
 
 - **Do** use semantic color aliases (`primary`, `text`, `background`, etc.) — never hardcode hex values.
-- **Do** use `primary` (resolves to palette `sapphire`) as the brand interactive color.
-- **Don't** attempt dark mode — Percipio is light only.
+- **Do** use `primary` (resolves to palette `sapphire` in light mode) as the brand interactive color.
+- **Don't** assume Percipio 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.
 
 ### Typography
 
 - **Do** use title weight (500) for headlines, CTAs, and buttons — not 700.