<!-- https://getkonjo.com/design/foundations/iconography · source: docs/design/foundations/iconography.md -->

# Iconography

Weight, size, colour, and when a glyph may stand alone.

> Part of the [Konjo design language](../konjo-design-language.md). The laws in the spine
> apply here unless this chapter contradicts them.

**In the mobile app, every icon comes from
[`src/components/Icon.tsx`](../../../src/components/Icon.tsx), which wraps Phosphor.** No ad-hoc
imports from `phosphor-react-native`, no SVG pasted into a component, no emoji.

**Studio uses Lucide** ([the dialect](../studio/dialect.md)), and this chapter's rules split
accordingly. The sizes (`iconSize` 16 inline / 19 status / 24 standalone), the colour rules, the
one-glyph-per-tile budget and the never-decorative rule are set-independent and apply to both.
The **weight** system below is Phosphor's — `regular` and `fill`, where fill is a state and
never emphasis — and Lucide has no weights: a Studio icon is a single stroke, and a Studio
"filled" state is carried by the control around the glyph, not by the glyph. Studio has no
`Icon` wrapper of its own, so its imports are direct and its discipline is convention rather
than a chokepoint. This paragraph exists because the sentence above it said "every icon" and
was false for a third of the product. The wrapper exists so the set stays finite and one name means one glyph
everywhere — the alternative is three different "add" icons on three tabs.

Need a glyph the wrapper does not export? Add it to the wrapper. That is a two-line change and
it is the whole system working.

## Weight

Phosphor ships six weights. **Konjo uses two**, and the wrapper already picks between them:
`weight ?? (active ? 'fill' : 'regular')`.

| Weight | When |
|---|---|
| `regular` | Everything. The default, and correct unless the glyph is showing state. |
| `fill` | The selected tab, the active filter, a completed step, a liked post. |

`fill` is a **state**, not emphasis. Filling an icon to make it look important is the same
mistake as making a heading red — it spends a budget on decoration. `thin`, `light`, `bold`
and `duotone` do not appear in Konjo; mixing weights across one screen reads as two icon sets.

## Size

Three sizes, from the `iconSize` scale:

| Size | Use |
|---|---|
| `inline` | Sitting in a line of text — a 16pt glyph beside a 15pt label. Optically matched to the type, never larger. |
| `status` | A status glyph on a tile or row. Small enough to stay a marker, big enough to identify. |
| `control` | Standing alone as a tappable thing: header actions, tab bar, an icon-only button. Always inside a 44pt target. |

Nothing between. A glyph that needs to be bigger than `control` is not an icon, it is
illustration — see [imagery](imagery.md).

## Colour

- **`text.primary`** by default. An icon is content.
- **`text.tertiary`** for a chevron or other pure affordance — it is furniture, and it is
  card-only (on the tinted page use `text.secondary`).
- **Never `text.quaternary`** for anything meaningful. It is legal only for a genuinely
  disabled glyph or an unfilled track.
- **Red only if the icon *is* the screen's one red role.** A red glyph plus a red button is
  two roles and one has to give. See L4.
- On a hero block, `text.onHero` — never a hardcoded hex.

An icon carrying meaning is non-text content: it needs **3:1** against its background
(SC 1.4.11), which is why a status glyph sits bare on the tile rather than inside a tinted
chip at 1.14:1.

## Icon-only controls

An icon alone is legible when **all three** hold:

1. It is a platform convention — back, close, search, share, add, more.
2. It sits in chrome, where people expect symbols.
3. It carries an `accessibilityLabel` saying what it does.

Otherwise it takes a label. A glyph you invented for "reconcile attendance" teaches nobody,
and the person who needed it most is the one who will not tap an unfamiliar square.

**Never an icon and a label that say different things.** If the label is "Log a session", the
icon is not a stopwatch because stopwatches look nice.

## Icon plus label

- Icon leads, label follows, `spacing.tight` between them.
- Optically centred on the text baseline, not the box.
- One icon per label. A row with a leading glyph, a trailing chevron and a status marker is
  already at its limit.

## Never

- A glyph used as decoration next to a heading.
- Two icons meaning the same thing in one feature.
- An icon substituting for an empty state.
- A brand logo used as an icon.
- Emoji anywhere in chrome. See [voice](../voice/voice.md).
