# Typography Tokens

## Overview

The system uses IBM Plex Sans as the default web font for interface text, headings, and body copy.

Typography tokens are defined in [typography.css](/Users/stuft2/Projects/design-system/src/css/typography.css).

IBM Plex Sans is a variable font, so these tokens can use weight values between `100` and `700`.

## Usage

Use the shared typography tokens directly when a component needs text styling that should stay aligned with the system:

- Use `--font-family-sans` for default UI text and controls.
- Use `--font-size` and `--font-line-height-body` for standard control text.
- Use `--font-size-caption` for helper text, native captions, caption-like metadata, and compact supporting copy.
- Use `--font-size-title` for compact page or component titles that should not use the full page-heading scale.
- Use the heading size tokens for semantic heading levels instead of hardcoding absolute sizes.
- Use `--font-line-height-heading` for semantic heading levels instead of hardcoding heading line-height values.
- Use `--heading-margin-block-end` to customize the block-end rhythm after semantic headings; its default follows the current layout theme's stack spacing.
- Use the body weight tokens for inline emphasis and prose-level text roles.
- Use the heading weight tokens for semantic heading levels instead of hardcoding numeric weights.

For exact shared typography values, use [typography.css](/Users/stuft2/Projects/design-system/src/css/typography.css) as the source of truth.

## Truncation Utilities

Use `.truncate` when constrained text must remain on one line and end with an ellipsis. The element needs a constrained inline size; flex and grid children may also need `min-inline-size: 0` from their surrounding composition.

Use `.line-clamp` to limit constrained text to two lines. Set `--line-clamp-lines` to a positive integer when another line count is needed:

```html
<p class="line-clamp" style="--line-clamp-lines: 3;">Long supporting text…</p>
```

Truncation is visual only and does not impose a character limit. Keep the complete text in the document. When users need the hidden content to understand or complete a task, provide a visible disclosure such as a “Show more” button; do not rely on `title` as the only way to reach it.

## Authoring Rules

- Use shared typography tokens before creating component-level font, weight, or line-height values.
- Keep the default UI font family centralized so components and documentation examples inherit the same base text treatment.
- Use the shared default link treatment so links use the subtle text accent color in light mode, keep the text accent color in dark mode, remove underline by default, and show the strong text accent underline hover state unless a component intentionally overrides it.
- Use the shared body emphasis tokens so inline `em`, `i`, `b`, and `strong` elements render with the documented IBM Plex Sans body weights.
- Let global text elements such as `body`, `p`, `small`, `blockquote`, `caption`, and `figcaption` inherit their default typography from this layer unless a component has a stronger semantic reason to override them.
- Balance blockquote wrapping so centered quotations distribute text more evenly across lines.
- Treat direct child paragraphs in direct child `main` headers as caption text and size them from `--font-size-caption`.
- Uppercase `h1` text so top-level page headings keep the intended title presentation from authored lowercase text.
- Prefer semantic size tokens for headings, titles, captions, and supporting text instead of scattering raw `rem` values through components.
- Derive typography size tokens from `--font-size` so theme authors configure one size source.
- Prefer semantic weight tokens for documented text roles instead of scattering raw numeric font weights through components.
- Derive body and heading weight tokens from `--font-weight-base` so theme authors configure one weight source.
- Keep semantic headings free of browser-default block margins: use zero block-start margin and the shared heading block-end token, while tighter component contracts may remove both margins.
- Do not create a token for a text style unless it reflects a reusable design decision.

## Heading Groups

Use a native `hgroup` when one semantic heading has associated supporting copy such as a subtitle or kicker:

```html
<hgroup>
  <h2>Student Account</h2>
  <p>Review tuition, financial aid, and recent payments.</p>
</hgroup>
```

The group removes the direct children's default block margins so the heading and supporting copy stay together. Its final supporting child uses the subtle text color. Let a parent `.flow` control spacing around the complete group; customize `--hgroup-space` only when the lines inside the group need intentional separation.

## Behavior

Covered by [Playwright behavior tests](../../tests/e2e/typography.spec.js).

- TYP-001: `.truncate` keeps constrained text on one line, clips its overflow, and renders an ellipsis where the text is cut off.
- TYP-002: `.line-clamp` visually limits constrained text to `--line-clamp-lines`, defaults that value to two, and keeps the complete authored text in the document.
- TYP-003: A native `hgroup` removes its own margin and the block margins of its direct children so a heading and its supporting copy form one tight composition.
- TYP-004: The final supporting child in an `hgroup` uses the shared subtle text color by default.
- TYP-005: `--hgroup-space` controls only the internal space between direct children while the parent layout controls spacing around the complete group.
- TYP-006: Semantic `h1` through `h6` headings have zero block-start margin and a block-end margin that follows the current layout theme's stack spacing, while headings inside `hgroup` and card headers remain marginless.
- TYP-007: `--heading-margin-block-end` overrides the block-end spacing for semantic headings without changing heading selectors.

## Variables

| Variable | Type | Description |
| --- | --- | --- |
| `--font-family-sans` | `Any` | Default sans-serif font family for application UI, form controls, headings, and body copy. Use for: default UI text and content that should inherit the IBM Plex Sans system font Avoid for: icon fonts or display typography that needs a distinct semantic decision |
| `--font-line-height-body` | `<number>` | Default unitless line-height multiplier for standard body text and interactive controls. Use for: readable body text, control text, and line-height values that should scale with local font size Avoid for: dense data text that needs a separate semantic type token |
| `--font-line-height-heading` | `<number>` | Heading line height for semantic heading levels. Use for: `h1` through `h6` and equivalent heading treatments Avoid for: body copy, control text, captions, and supporting text that should use `--font-line-height-body` |
| `--font-size` | `<length-percentage>` | Default font size for standard interactive controls. Use for: `input`, `select`, `textarea`, and button text when they share the default control type scale Avoid for: headings or component-specific display typography |
| `--font-size-caption` | `<length>` | Caption text size for native `caption`, `figcaption`, and caption-like metadata. Derived from: `--font-size` Use for: table captions, figure captions, helper text, range limits, eyebrow metadata, compact supporting labels, and `small` Avoid for: larger header caption text, which should calculate from this token |
| `--font-size-heading-1` | `<length>` | Heading 1 size. Derived from: `--font-size` Use for: `h1` and equivalent top-level page headings Avoid for: component titles or lower-level section headings |
| `--font-size-heading-2` | `<length>` | Heading 2 size. Derived from: `--font-size` Use for: `h2` and equivalent second-level headings Avoid for: top-level page titles or lower-level section headings |
| `--font-size-heading-3` | `<length>` | Heading 3 size. Derived from: `--font-size` Use for: `h3` and equivalent third-level headings Avoid for: body text or compact labels |
| `--font-size-heading-4` | `<length>` | Heading 4 size. Derived from: `--font-size` Use for: `h4` and equivalent fourth-level headings Avoid for: non-heading uppercase labels |
| `--font-size-heading-5` | `<length>` | Heading 5 size. Derived from: `--font-size` Use for: `h5` and equivalent fifth-level headings Avoid for: replacing body text emphasis |
| `--font-size-heading-6` | `<length>` | Heading 6 size. Derived from: `--font-size` Use for: `h6` and equivalent sixth-level headings Avoid for: standard body copy |
| `--font-size-title` | `<length>` | Compact title size for branded headers and other title treatments that sit below the full page-heading scale. Derived from: `--font-size` Use for: application or site titles inside component chrome Avoid for: semantic page headings that should use the heading size tokens |
| `--font-weight-base` | `<number>` | Authored base text weight for IBM Plex Sans. Use for: the single configurable weight source that body and heading weights derive from Avoid for: direct component styling when a semantic body or heading weight token exists |
| `--font-weight-body-bold` | `<number>` | Bold body text weight for IBM Plex Sans. Derived from: `--font-weight-base` Use for: inline strong emphasis within body copy Avoid for: heading levels that have their own weight tokens |
| `--font-weight-body-italic` | `<number>` | Body italic weight for IBM Plex Sans. Derived from: `--font-weight-base` Use for: italicized body text when the content should retain the standard body weight Avoid for: relying on weight alone to communicate emphasis without italic styling |
| `--font-weight-body-regular` | `<number>` | Default body text weight for IBM Plex Sans. Derived from: `--font-weight-base` Use for: standard body copy and default paragraph text Avoid for: emphasized headings or strong action labels |
| `--font-weight-heading-1` | `<number>` | Heading 1 weight for IBM Plex Sans. Derived from: `--font-weight-base` Use for: `h1` and equivalent top-level page headings Avoid for: lower heading levels or emphasized body text |
| `--font-weight-heading-2` | `<number>` | Heading 2 weight for IBM Plex Sans. Derived from: `--font-weight-base` Use for: `h2` and equivalent second-level headings Avoid for: body text or smaller heading levels |
| `--font-weight-heading-3` | `<number>` | Heading 3 weight for IBM Plex Sans. Derived from: `--font-weight-base` Use for: `h3` and equivalent third-level headings Avoid for: body text or lower-emphasis labels |
| `--font-weight-heading-4` | `<number>` | Heading 4 weight for IBM Plex Sans. Derived from: `--font-weight-body-bold` Use for: `h4` and equivalent fourth-level headings Avoid for: replacing semantic body emphasis styles |
| `--font-weight-heading-5` | `<number>` | Heading 5 weight for IBM Plex Sans. Derived from: `--font-weight-base` Use for: `h5` and equivalent fifth-level headings Avoid for: stronger heading levels that require more emphasis |
| `--font-weight-heading-6` | `<number>` | Heading 6 weight for IBM Plex Sans. Derived from: `--font-weight-base` Use for: `h6` and equivalent sixth-level headings Avoid for: standard body copy when the regular body token should be used instead |
| `--heading-margin-block-end` | `<length-percentage>` | Block-end rhythm after semantic headings. Derived from: `--layout-space-stack` Use for: adjusting the space after `h1` through `h6` without restoring browser-default margins Avoid for: spacing inside tighter component contracts such as heading groups and card headers |
| `--hgroup-color-supporting` | `<color>` | Text color for the final supporting line in a heading group. Defaults to the shared subtle text color so subtitles recede from their heading. Use for: subtitles, kickers, and other supporting copy grouped with a semantic heading Avoid for: primary heading text or long-form body copy |
| `--hgroup-space` | `<length-percentage>` | Internal block spacing between direct children of a semantic heading group. Defaults to zero for a tight heading-and-supporting-copy composition. Use for: adding a small intentional separation inside `hgroup` Avoid for: spacing between the whole heading group and surrounding content, which belongs to the parent layout |
| `--line-clamp-lines` | `<integer>` | Number of visible lines in the line-clamp typography utility. Defaults to `2`. Use for: choosing how many lines of constrained supporting text remain visible Avoid for: character-based content limits or hiding content users must read to complete a task |
