> ## Documentation Index
> Fetch the complete documentation index at: https://invoca-5bd45748-mintlify-6c3474a6.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Color

> How color carries meaning in Titan, and which token to reach for when.

## What it governs

Every color that renders: surfaces, text, borders, icons, states, and status. Color in Titan
is not a palette you pick from. It is a set of named intents that resolve to different
values depending on mode.

Color is the largest foundation — **97 of the 244 tokens on `theme.tokens` are color**, and
every one is token-bound rather than an untokenised literal.

## Vocabulary

The colour vocabulary is fully specified. Four axes apply.

| Axis           | Values                                                                       | Means                                                                                                                                             |
| -------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| **attribute**  | `background` `text` `border` `icon` `link` `overlay`                         | What is being painted                                                                                                                             |
| **purpose**    | `success` `info` `error` `warning` `neutral` `default` `destructive` `focus` | What it means                                                                                                                                     |
| **prominence** | `primary` `secondary` `tertiary` `invert`                                    | How much weight it carries. The design team's button vocabulary — see [TITAN-DIV-11](/invoca-design-system/foundations/divergences#titan-div-11). |
| **state**      | `default` `alt` `hover` `pressed` `selected` `visited` `disabled` `focus`    | Which interaction state                                                                                                                           |

<Note>
  **Sourced from Invoca's design-token naming specification**, confirmed by its owner as the
  baseline the design language is being built on. This is the vocabulary of record — not
  inferred from token names.
</Note>

<Warning>
  **`alt` is a state, not a shade.** `background-error-alt` is the alternate *state* of the
  error background — the tinted partner to the bold fill — sitting on the same axis as
  `hover` and `pressed`. Reading it as "a lighter error" is the most common misuse.

  **`invert` sits on two axes** — a prominence (`text-invert`, for content on an inverted
  surface) and a state. Read it from position in the name.
</Warning>

<Note>
  **Two terms overlap and the spec does not separate them.** `neutral` and `disabled` both
  appear as purposes, and `background-neutral` and `background-disabled` resolve to the same
  value — see [TITAN-GAP-04](/invoca-design-system/foundations/open-decisions#titan-gap-04).
</Note>

## The model

Titan's colors are authored in three tiers as DTCG JSON, and flattened at build time.

```
Primitive   color.blue.50                  = #2666f9
Semantic    tokens.background-selected     = {color.blue.10}
Component   chip-info-tint                 = {color.blue.20}
```

**Component code reaches the semantic tier**, which is flat: you write
`background-selected`, not the alias chain behind it.

```
JS        theme.vars.tokens["background-selected"]
CSS       var(--titan-tokens-background-selected)
SCSS      $background-selected          — legacy surface, frozen
```

The primitive tier is published as `--titan-color-*` and exists to be aliased, never
referenced directly. The component tier is where Titan's stated model and its source
disagree — see [TITAN-DIV-01](/invoca-design-system/foundations/divergences#titan-div-01).

The same name resolves to a different value depending on the active color scheme. That
resolution is the entire mechanism — there is nothing to configure and nothing to opt into.

<Note>
  Every color token also ships a `…Channel` companion — `background-selectedChannel` is
  `"212 224 254"`, the space-separated RGB triplet. They exist so transparency can be
  applied to a color internally. **Do not use them directly** — deriving a color by applying
  alpha to a channel is the opacity anti-pattern [TITAN-COLOR-06](#constraints) prohibits.
</Note>

## The naming pattern

Four families, and two modifiers that appear throughout. Learning the modifiers is most of
learning the system.

| Family         | Applies to                                            |
| -------------- | ----------------------------------------------------- |
| `background-*` | Surfaces and fills (27 tokens)                        |
| `text-*`       | Rendered text (17)                                    |
| `border-*`     | Borders, dividers, outlines (18, plus 4 width tokens) |
| `icon-*`       | Icon glyphs (18, including 4 size tokens)             |

| Modifier                       | Means                                                                                                                                                      |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| *(none)*                       | The saturated, full-strength value. A **fill** color.                                                                                                      |
| `-alt`                         | The alternate-weight partner. On a `background`, a **tinted** surface; on `text` or `icon`, a **darkened** value that carries contrast on a light surface. |
| `-hover`, `-pressed`           | Interaction states                                                                                                                                         |
| `-bold-hover`, `-bold-pressed` | Interaction states for *filled* variants, which move in the opposite direction from tinted ones                                                            |
| `-invert`                      | For use on an inverted (dark-in-light-mode) surface                                                                                                        |

<Warning>
  **`-alt` is not "a lighter version." It is the contrast-carrying partner**, and its
  direction depends on the family. `background-success-alt` is a pale tint (`#d5f2de`);
  `text-success-alt` is nearly black-green (`#0d5400`). They are designed to be used
  *together*. Reaching for a plain status token where an `-alt` belongs is the most common
  source of contrast failures in Titan — see [TITAN-COLOR-07](#constraints).
</Warning>

## Choosing a token

**This is the section to read.** The left column is what you are trying to express — in your
words, not the system's.

### Surfaces

| You need…                                                          | Use                          | Not                                                                                                                                                      |
| ------------------------------------------------------------------ | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The page canvas                                                    | `background-view-background` | `background-default`. The canvas is `#f5f6fa`, not white — and contrast must be checked against it.                                                      |
| A surface sitting on the canvas — card, panel, menu, dialog        | `background-default`         | A hardcoded white — invisible to the audit and carrying no recorded intent.                                                                              |
| A dark, high-emphasis surface — a filled header, an inverted panel | `background-strong`          | A dark primitive. Pair with `text-primary-invert`.                                                                                                       |
| A neutral, low-emphasis fill                                       | `background-neutral`         | `background-disabled`. They share a value and mean different things — see [TITAN-GAP-04](/invoca-design-system/foundations/open-decisions#titan-gap-04). |
| A row or cell under the pointer                                    | `background-hover`           | An opacity overlay — opacity composites unpredictably over tinted surfaces                                                                               |
| A row or cell being pressed                                        | `background-pressed`         | The hover token — pressed must be distinguishable from hover                                                                                             |
| A selected row that stays selected                                 | `background-selected`        | The hover token. Hover is transient; selection persists.                                                                                                 |
| A strongly marked selection — a filled active tab or nav item      | `background-selected-alt`    | `background-selected` at a heavier weight                                                                                                                |
| An unavailable control                                             | `background-disabled`        | Reduced opacity on the normal surface                                                                                                                    |
| A modal scrim                                                      | `overlay-default`            | A black at some alpha — see the [known defect](/invoca-design-system/foundations/color/open-issues#gaps-in-the-current-rules)                            |
| The backdrop behind a loading state                                | `overlay-loading`            | `overlay-default` — loading is not a modal block                                                                                                         |

### Text

| You need…                                                  | Use                                           | Not                                                                                             |
| ---------------------------------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| Body text at full emphasis                                 | `text-primary`                                | Black. `text-primary` is `#15243e` — a near-black with a blue cast that reads softer at length. |
| Supporting text, captions, metadata                        | `text-secondary`                              | An opacity on primary — opacity produces unpredictable contrast against non-default surfaces    |
| Text with more weight than secondary but less than primary | `text-strong`                                 | Bolding `text-secondary`. Weight and emphasis are separate channels.                            |
| Text on a dark or inverted surface                         | `text-primary-invert`                         | White. The surface is not guaranteed dark in every mode.                                        |
| Text in an unavailable control                             | `text-disabled`                               | Secondary text. Disabled and de-emphasized are different meanings and must not collide.         |
| Text indicating a selected item                            | `text-selected`                               | `text-info` — they differ, and selection is not a status                                        |
| A link                                                     | `link-default` (`link-hover`, `link-visited`) | `text-selected` — links have their own family                                                   |

### Borders

| You need…                                      | Use               | Not                                                                 |
| ---------------------------------------------- | ----------------- | ------------------------------------------------------------------- |
| To separate content within a group             | `border-default`  | A darker border — too heavy at list scale, turns a list into a grid |
| To bound a control (input, outlined button)    | `border-default`  | A subtle tint — the control stops reading as interactive            |
| To emphasize a boundary — an active panel edge | `border-strong`   | A thicker default border                                            |
| The border of a selected control               | `border-selected` | `border-info` — selection is not a status                           |
| The border of an unavailable control           | `border-disabled` | Reduced opacity                                                     |
| A field that failed validation                 | `border-error`    | Red. The token carries the dark-mode value; a raw red does not.     |

Border **widths** are separate tokens:

| Token                   | Value |
| ----------------------- | ----- |
| `border-width-sm`       | 1px   |
| `border-width-md`       | 2px   |
| `border-width-lg`       | 3px   |
| `border-width-emphasis` | 2px   |

<Note>
  **`border-width-md` and `border-width-emphasis` are both 2px, but they are not the same
  token.** Source records `border-width-emphasis` as the emphasized width for buttons, filter
  outlines, and slider thumbs; `border-width-md` records nothing. They also differ
  structurally — `border-width-md` aliases the primitive scale, while `border-width-emphasis`
  is a literal `2px` declared at the semantic tier.

  Because the values are identical, the distinction is invisible on screen. See
  [TITAN-GAP-04](/invoca-design-system/foundations/open-decisions#titan-gap-04).
</Note>

### Status

Four statuses. A fifth invented locally is not a status — it is an unmet need, and it
belongs in a token proposal.

Each status has two complete treatments. **Pick one and use it consistently.**

| Treatment              | Surface                   | Text / icon                              | Use for                                                                     |
| ---------------------- | ------------------------- | ---------------------------------------- | --------------------------------------------------------------------------- |
| **Tinted** (preferred) | `background-{status}-alt` | `text-{status}-alt`, `icon-{status}-alt` | Banners, inline alerts, form validation — anything containing readable text |
| **Bold fill**          | `background-{status}`     | `text-invert`                            | Small, high-attention marks — badges, dots, count chips                     |

| Status    | Means                                       |
| --------- | ------------------------------------------- |
| `info`    | Neutral context the user did not ask for    |
| `success` | An action completed                         |
| `warning` | Proceeding is possible but has consequences |
| `error`   | Something failed or is invalid              |

<Warning>
  **The bold-fill treatment fails AA for success and warning.** `text-invert`
  on `background-success` measures **2.41:1**; on `background-warning`, **2.74:1**. Both are
  far below the 4.5:1 minimum.

  Use the tinted treatment for anything containing text. Seven of its eight mode
  combinations pass AA outright. Full measurements in
  [Accessibility](/invoca-design-system/foundations/accessibility#contrast).
</Warning>

<Warning>
  **Color is never the sole carrier of meaning** — see [TITAN-COLOR-03](#constraints). Every
  status pairs a color with an icon and text. Roughly 1 in 12 men has some form of color
  vision deficiency; a red-only error state is invisible to them, and to anyone in bright
  sunlight or on a poorly calibrated display.
</Warning>

## Token reference

<Snippet file="generated/tokens/color.mdx" />

### The primitive tier

Tier 1 exists and is published — 106 raw ramp values as `--titan-color-*` custom properties.
Semantic tokens alias into it; component code never touches it.

Nine ramps run from `0` (lightest) to `100` (darkest) in steps of 10. Each cell is the
value of `color.{ramp}.{step}`, so `color.green.50` is `#2cbf58`. Values are identical
in light and dark mode.

| Ramp         | 0         | 10        | 20        | 30        | 40        | 50        | 60        | 70        | 80        | 90        | 100       |
| ------------ | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- |
| **blue**     | `#e9f0fe` | `#d4e0fe` | `#b0cdff` | `#7da3fb` | `#5185fa` | `#2666f9` | `#1c53e9` | `#1643d5` | `#1335bf` | `#122aa6` | `#11228c` |
| **green**    | `#e9f8ee` | `#d5f2de` | `#abe5bc` | `#80d99b` | `#56cc79` | `#2cbf58` | `#1cad3a` | `#129922` | `#0a830e` | `#0a6b04` | `#0d5400` |
| **orange**   | `#fff0ec` | `#ffe2da` | `#ffc6b5` | `#ffa98f` | `#ff8d6a` | `#ff7045` | `#f35e2c` | `#e6511a` | `#d6480d` | `#c44105` | `#b33b00` |
| **red**      | `#fff2f2` | `#fdbbbc` | `#fa8688` | `#f5575a` | `#ed3036` | `#e4131b` | `#d70009` | `#c7000a` | `#b3000b` | `#9e000c` | `#87000b` |
| **purple**   | `#f3effb` | `#e7e0f9` | `#d0c1f2` | `#b8a1ec` | `#a182e5` | `#855ede` | `#763ed2` | `#6a23c0` | `#5f11a7` | `#530587` | `#440066` |
| **pink**     | `#fee9f0` | `#fed3e3` | `#fda7c6` | `#fc7caa` | `#fb508d` | `#e4126f` | `#c9076e` | `#aa0269` | `#8f005a` | `#89005f` | `#660050` |
| **teal**     | `#e5fbf8` | `#ccf8f2` | `#99f2e4` | `#66ebd7` | `#33e5c9` | `#00debc` | `#00d1b4` | `#00c1a9` | `#00ad9a` | `#009788` | `#007e73` |
| **yellow**   | `#fffbe5` | `#fff7cc` | `#ffef99` | `#ffe866` | `#ffe033` | `#ffd800` | `#f3cb00` | `#e6bd00` | `#d6ad00` | `#c49c00` | `#b38c00` |
| **ui-black** | `#f3f4f5` | `#e7e9eb` | `#d0d3d8` | `#b8bdc5` | `#a1a7b2` | `#8a919e` | `#737c8b` | `#5b6577` | `#445065` | `#2c3951` | `#15243e` |

Seven named values sit outside the ramps:

| Token                       | Value                  |
| --------------------------- | ---------------------- |
| `color.common.asphalt`      | `#66708e`              |
| `color.common.invoca-green` | `#00B388`              |
| `color.common.light-grey`   | `#f5f6fa`              |
| `color.common.night-shade`  | `#081340`              |
| `color.common.white`        | `#ffffff`              |
| `color.shadow.deep`         | `rgba(0, 0, 0, 0.55)`  |
| `color.shadow.default`      | `rgba(12, 0, 51, 0.2)` |

Remember [TITAN-COLOR-01](#constraints): these hex values are for reference and design
handoff, never for component code. If you need one of these colors, use the semantic
token that aliases it.

<Snippet file="generated/tokens/color-primitive.mdx" />

### Every semantic color, with its alias chain

<Snippet file="generated/tokens/color-semantic.mdx" />

## Interaction states

The state tokens, grouped by the state they express. Each is a normal semantic color token —
there is no separate state mechanism.

<Snippet file="generated/tokens/interaction-states.mdx" />

**Hover is not available on touch.** Never let hover color be the only signal that something
is interactive — see [TITAN-COLOR-09](#constraints).

## Surface layering

**Proposed, pending sign-off** — see [Open issues](/invoca-design-system/foundations/color/open-issues) for what that leaves unsettled.

| Level    | Surface token                | Sits on    | Pair borders with                  |
| -------- | ---------------------------- | ---------- | ---------------------------------- |
| Canvas   | `background-view-background` | The page   | `border-default`                   |
| Raised   | `background-default`         | The canvas | `border-default`                   |
| Recessed | `background-neutral`         | Either     | `border-disabled`                  |
| Inverted | `background-strong`          | Either     | — pairs with `text-primary-invert` |

Titan does not specify what happens below the raised level. A card inside a card has no
defined surface, and inventing one locally is how a layering model stops being one.

## Constraints

| ID                 | Constraint                                                                                                          | Rationale                                                                                                                                                    |
| ------------------ | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **TITAN-COLOR-01** | Component code references a color token. Never a hex value, an `rgb()`, or a `…Channel` variable.                   | A literal is invisible to the audit and carries no recorded intent. Every system-wide color change becomes a search-and-replace.                             |
| **TITAN-COLOR-02** | Text meets WCAG 2.2 AA against the surface it sits on.                                                              | Four status pairings fail today. Contrast is arithmetic, so it is checkable before review rather than after.                                                 |
| **TITAN-COLOR-03** | Color never carries meaning alone. Pair with an icon, a label, or both.                                             | Color vision deficiency, monochrome displays, and bright ambient light all remove color as a channel.                                                        |
| **TITAN-COLOR-04** | New color needs are met by proposing a token, never by a local override.                                            | A local override is invisible to the audit, to Figma, and to every other consumer. It is how a design system stops being one.                                |
| **TITAN-COLOR-05** | Status color comes from the four statuses. A fifth is a token proposal, not a hex value.                            | Five statuses cannot be reliably distinguished by color, and an ad-hoc fifth has no dark-mode value and no contrast guarantee.                               |
| **TITAN-COLOR-06** | Opacity is never used to derive a color variant.                                                                    | Opacity composites against whatever is behind it, so the resulting contrast is unknowable at author time. Use the token for the intent instead.              |
| **TITAN-COLOR-07** | Status text and icons use the `-alt` variant. Bold fills pair with `text-invert`, and never for success or warning. | The plain status tokens measure 2.41–2.74:1. Mixing the two treatments is the primary source of contrast failures.                                           |
| **TITAN-COLOR-08** | Contrast is verified against `background-view-background`, not only `background-default`.                           | The canvas is `#f5f6fa`. `text-info` and `text-error` pass on white and fail on the canvas.                                                                  |
| **TITAN-COLOR-09** | Hover color is never the only signal that an element is interactive.                                                | Hover does not exist on touch, and it is unavailable to keyboard navigation. Pair it with an affordance that persists — a cursor, a border, a control shape. |

## Accessibility

Full measured tables live in [Accessibility](/invoca-design-system/foundations/accessibility). The headlines:

* **`text-success` (2.41:1) and `text-warning` (2.74:1) fail AA on all light surfaces.** Use
  the `-alt` variants.
* **`text-info` and `text-error` pass on white but fail on the page canvas.**
* **There is no *semantic* focus token.** Three component-scoped rings ship —
  `form-field-focus-ring`, `form-field-focus-ring-error`, `data-grid-focus-ring` — each
  authored independently against a primitive. Nothing supplies a focus ring for the general
  case, so every other component decides for itself. See
  [TITAN-DIV-02](/invoca-design-system/foundations/divergences#titan-div-02).
* Disabled controls are exempt from contrast minimums, which is exactly why disabled state
  must never be the sole signal.
* Do not rely on hover color alone to indicate interactivity; it does not exist on touch.

## Known issues

<Card title="Color: open issues" icon="triangle-exclamation" href="/invoca-design-system/foundations/color/open-issues">
  Divergences, open decisions, and undocumented gaps for Color.
</Card>

## Related

**34 core components consume this foundation** — derived from token usage in
`components/core/src/components`, not assumed:

`Accordion` · `AddList` · `Badge` · `Button` · `ButtonGroup` · `Card` · `Checkbox` · `Chip` · `CircularProgress` · `DataGrid` · `DatePicker` · `Dropzone` · `Footer` · `Form` · `FormInput` · `Header` · `List` · `LoaderOverlay` · `Menu` · `Modal` · `Progress` · `Radio` · `SearchableSelect` · `Select` · `Slider` · `Tabs` · `TextField` · `TextFieldWithSearchIcon` · `TextLink` · `Tile` · `Toast` · `Toggle` · `Tooltip` · `Typography`

## Why it works this way

**Semantic tokens are named for intent, not appearance.** `background-selected` rather than
`background-light-blue`. Appearance names become lies the moment a second mode exists — and
they were already lying to the person reading the code, who wants to know *why* the surface
is that color.

**Two treatments per status, not one.** A single status color cannot serve both a 12px
badge and a paragraph of error text: what is legible as a small saturated mark is unreadable
as a text color, and what carries text contrast is too dark to read as "success" at a
glance. The plain/`-alt` split is that problem solved — provided the pairs stay paired.

**Four statuses, not six.** Systems that add "neutral," "pending," and "in progress" as
distinct status colors find that no user can distinguish them without reading the label — at
which point the label is doing the work and the color is decorative. Four is the number that
survives being squinted at.
