Files
nick-doc/05 - Design System/Typography.md
Siavash Sameni dceaf82934 audit: 2026-05-30 full-codebase audit — report, issues, docs, runbooks
Full-codebase-audit 2026-05-30 outputs:
- Audit report: 09 - Audits/Full Codebase Audit - 2026-05-30.md
- 81 issue files ISSUE-055..135 (decisions + 1 skipped no-brainer).
- Scanner docs from scratch (was zero): architecture, data model, API ref, payment
  flow, operations runbook + repo README.
- Doc-sync updates across API reference, data models, flows, design system.
- Secret Rotation Runbook (08 - Operations) for the exposed credentials.
- Reusable workflow guide (07 - Development) + .claude/workflows/full-codebase-audit.js.

Issues remain status:open intentionally — the code fixes are uncommitted-then-committed
working-tree changes per repo and aren't "resolved" until merged/deployed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 18:48:04 +04:00

5.6 KiB
Raw Blame History

title, tags, created, updated
title tags created updated
Typography
design-system
typography
fonts
2026-05-23 2026-05-30

Typography

[!info] Amaneh Design System v2.7.0 (commit 56fc84e) The font stack changed in v2.7.0 from Public Sans + Barlow to a three-font purposeful stack:

  • Source Serif 4 — headings in italic; editorial, humanist character
  • IBM Plex Sans — body and UI text; technical clarity, RTL-compatible
  • IBM Plex Mono — amounts, wallet addresses, tx hashes; monospaced, tabular-nums built-in

The system uses a three-font purposeful stack for the Amaneh design. Locale-specific Persian/Arabic faces are loaded when the active language requires them.


1. Font stack

Loaded via @fontsource-variable. Current active fonts (frontend/package.json):

"@fontsource-variable/source-serif-4": "...",  // Headings (italic)
"@fontsource/ibm-plex-sans":           "...",  // UI / body
"@fontsource/ibm-plex-mono":           "...",  // Amounts, addresses, hashes

The settings drawer still lists alternative fonts (DM Sans, Inter, Nunito Sans, Public Sans) for user override.

Default font-family stack in the theme:

/* Headings */
font-family: "Source Serif 4 Variable", Georgia, serif;
/* UI / body */
font-family: "IBM Plex Sans", "Helvetica", "Arial", sans-serif;
/* Monospaced (amounts / addresses) */
font-family: "IBM Plex Mono", "Courier New", monospace;

Use sx={{ fontFamily: 'IBMPlexMono' }} (theme alias) for any USDT amounts, contract addresses, or transaction hashes.


2. Type scale

Variant Size (px) Line height Weight Use
h1 64 80 800 Hero titles only
h2 48 64 800 Page titles
h3 32 48 700 Section titles
h4 24 36 700 Card titles, dialog headers
h5 20 30 700 Sub-section titles
h6 18 28 700 Item titles, sidebar headers
subtitle1 16 24 600 Form section labels
subtitle2 14 22 600 List item subtitles
body1 16 24 400 Body copy default
body2 14 22 400 Secondary copy, table cells
caption 12 18 400 Helper text, timestamps
overline 12 18 700 Tags, all-caps category labels
button 14 24 700 Button text — NOT uppercase

Tip

Use responsiveFontSizes(theme) once at theme creation to scale h1/h2 on small screens automatically.


3. Weights

The variable Public Sans face supports 100900. Convention:

Weight Token Use
400 fontWeightRegular Body
500 fontWeightMedium Mild emphasis
600 fontWeightSemiBold Subtitles, table headers
700 fontWeightBold Headings
800 (raw) Display

Never use font-weight: bolder — always pick from the table.


4. Letter-spacing

  • Headings (h1h2): -1 (tight, modern)
  • Overline: +1.1 (open, all-caps)
  • Body, subtitle: 0

5. Numeric variants

Tabular figures matter for financial UI (payments, prices). Enable per-instance:

<Typography variant="body1" sx={{ fontVariantNumeric: 'tabular-nums' }}>
  {amount}
</Typography>

6. Multi-script support

The system officially supports Latin, Persian (Farsi), and Arabic rendering; French and Vietnamese use Latin glyphs already covered by Public Sans; Chinese (Simplified) falls back to the OS-default CJK font (the current fontsource set does not ship CJK).

Persian/Arabic font swap is layered at theme build:

fontFamily:
  locale === 'fa' || locale === 'ar'
    ? '"Vazirmatn", "Public Sans Variable", "Tahoma", sans-serif'
    : '"Public Sans Variable", "Helvetica", sans-serif'

Note

"Vazirmatn" is the recommended Persian face for new installations — it has full Unicode coverage and a variable axis. If not installed via @fontsource, ship it as a self-hosted woff2 under public/fonts/.

For Chinese (cn), consider adding "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC" to the family at the front.

For Vietnamese (vi) — Public Sans already covers all needed glyphs.


7. Line-length

Aim for 4575 characters per line on body copy. Constrain with maxWidth:

<Typography variant="body1" sx={{ maxWidth: 720 }}>{longBody}</Typography>

8. Text truncation

Single-line:

<Typography noWrap>{text}</Typography>

Multi-line (clamp at 2 lines):

<Typography
  sx={{
    display: '-webkit-box',
    WebkitLineClamp: 2,
    WebkitBoxOrient: 'vertical',
    overflow: 'hidden',
  }}
>{text}</Typography>

9. Bidi & RTL considerations

  • Don't hard-code text-align: left/right — use text-align: start/end so it flips with direction.
  • For inline mixed-script (Persian + English), prefer the auto direction inside <bdi> or wrap with the Unicode (RLE) / (PDF) markers.
  • Numeric formatting per locale handled by Intl.NumberFormat; do NOT translate digits manually.

10. Loading & FOUC prevention

  • All fonts loaded at the route segment that needs them (Next.js best practice).
  • font-display: swap is the default in fontsource — visible text uses fallback first, then swaps.
  • For the FIRST PAINT on auth pages, preload the primary Latin face by adding <link rel="preload" as="font" /> to the root layout.

11. Customising

Add a font:

  1. yarn add @fontsource-variable/<name>
  2. import '@fontsource-variable/<name>' in src/app/layout.tsx.
  3. Add to fontFamily stack in theme/options/typography.ts.
  4. Register as a settings option if user-selectable.