
# Typography

`theme.fonts` maps a **role** to a font configuration. Each role key generates a `--font-{role}` CSS custom property and a matching `font-{role}` utility, so type decisions live in config rather than scattered across `className` strings.

```yaml
theme:
  fonts:
    heading:
      family: Inter
      fallback: 'system-ui, sans-serif'
      weights: [600, 700]
      lineHeight: '1.2'
      letterSpacing: '-0.02em'
    body:
      family: Inter
      fallback: 'system-ui, sans-serif'
      weights: [400, 500]
      size: '16px'
      lineHeight: '1.6'
    mono:
      family: 'JetBrains Mono'
      fallback: 'ui-monospace, monospace'
```

Role keys are alphabetic and freely chosen. `heading`, `body` and `mono` are the conventional three — Sovrium's prebuilt components look for them — but a design that needs `display` or `caption` simply declares it.

## Font Properties

| Property        | Description                                                                                     |
| --------------- | ----------------------------------------------------------------------------------------------- |
| `family`        | **Required.** Font family name, e.g. `Inter`, `Roboto`.                                         |
| `fallback`      | Fallback stack used until the family loads, or if it never does.                                |
| `weights`       | Numeric weights to load, from 100 to 900. Declaring only what you use keeps the download small. |
| `style`         | `normal` (default), `italic`, or `oblique`.                                                     |
| `size`          | Base size as a CSS value, e.g. `16px`, `1rem`.                                                  |
| `lineHeight`    | Multiplier or CSS value, e.g. `1.5`.                                                            |
| `letterSpacing` | CSS value, e.g. `0.05em`, `-0.01em`.                                                            |
| `transform`     | `none`, `uppercase`, `lowercase`, or `capitalize`.                                              |
| `url`           | Font file or Google Fonts URL, injected as a `<link>` in the document head.                     |

## Loading a Web Font

Give the role a `url` and Sovrium injects the stylesheet link for you. Nothing else is required — no manual `<head>` entry, no `@font-face` block.

```yaml
theme:
  fonts:
    body:
      family: Inter
      fallback: 'system-ui, sans-serif'
      weights: [400, 600]
      url: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap'
```

:::callout
**Always pair `url` with `fallback`.** A remote font is a network request the first paint does not wait for. Without a fallback stack, text is laid out in the browser default and reflows when the font lands; with one, the swap is a change of typeface rather than a change of layout.
:::

Self-hosted fonts work the same way — point `url` at a stylesheet in your public directory. That keeps the request on your own origin, which matters when a third-party font CDN is not acceptable under your privacy posture.

## Sizing the Base

`size` on the `body` role sets the document's base font size, and every `rem`-based Tailwind spacing and type utility scales with it. Raising it from `16px` to `17px` enlarges the whole interface proportionally — usually a better first move than overriding individual type utilities.

## Related Pages

- [Theme Overview & Colors](/en/docs/theme) — the theme block and color tokens.
- [Spacing, Radius & Shadows](/en/docs/theme-spacing) — the remaining token categories.
- [Baseline & Dark Mode](/en/docs/theme-dark-mode) — how a second palette is applied.
- [Content Components](/en/docs/content-components) — the text these roles style.
- [Ecoconception](/en/docs/ecoconception) — the footprint cost of remote font loading.
