typography

Elegant, modern typography sets the foundation for professional interfaces.

Typography

Elegant, modern typography sets the foundation for professional interfaces.

Font Selection

Primary Fonts

1. Zen (https://hanzo.ai/font) - USE FOR ALL UI TEXT

Hanzo's own family, drawn for interfaces. It ships in @hanzo/font, so a project carries it rather than fetching it.

Characteristics:

Use Zen for:

font-family: 'Zen', -apple-system, BlinkMacSystemFont, sans-serif;

2. Zen Mono (https://hanzo.ai/font) - USE FOR ALL CODE/TECHNICAL

Purpose-built for developers.

Characteristics:

Use Zen Mono for:

font-family: 'Zen Mono', 'Fira Code', Consolas, monospace;
font-size: 14px; /* minimum */
font-variant-ligatures: common-ligatures; /* enable ligatures */

Alternative Elegant Fonts

If Zen or Zen Mono are unavailable:

Sans-serif alternatives:

Monospace alternatives:

System font fallback:

/* If custom fonts fail to load */
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif

Font Loading Strategy

Use optimal loading to prevent FOIT (Flash of Invisible Text):

One import declares both faces, already set to font-display: swap:

import '@hanzo/font/css';

It expands to this, which is what to write by hand if you are self-hosting the files rather than taking the package:

@font-face {
  font-family: 'Zen';
  src: url('/fonts/zen-sans/Zen-Variable.woff2') format('woff2');
  font-display: swap; /* Show fallback immediately, swap when loaded */
  font-weight: 100 900; /* Variable font weight range */
}

@font-face {
  font-family: 'Zen Mono';
  src: url('/fonts/zen-mono/ZenMono-Variable.woff2') format('woff2');
  font-display: swap;
  font-weight: 100 900;
}

Typography Scales

Use a modular scale for consistent hierarchy.

Common scales:

Example: 1.25 scale (recommended):

:root {
  --font-size-xs: 0.64rem;   /* 10.24px */
  --font-size-sm: 0.8rem;    /* 12.8px */
  --font-size-base: 1rem;    /* 16px */
  --font-size-lg: 1.25rem;   /* 20px */
  --font-size-xl: 1.563rem;  /* 25px */
  --font-size-2xl: 1.953rem; /* 31.25px */
  --font-size-3xl: 2.441rem; /* 39px */
  --font-size-4xl: 3.052rem; /* 48.8px */
}

Usage:

body {
  font-size: var(--font-size-base);
  line-height: 1.6;
}

h1 { font-size: var(--font-size-4xl); }
h2 { font-size: var(--font-size-3xl); }
h3 { font-size: var(--font-size-2xl); }
h4 { font-size: var(--font-size-xl); }

small { font-size: var(--font-size-sm); }

Line Height

Body text: 1.5-1.6 for readability Headings: 1.1-1.3 for impact Code: 1.5-1.6 for clarity

body {
  line-height: 1.6;
}

h1, h2, h3, h4, h5, h6 {
  line-height: 1.2;
}

code, pre {
  line-height: 1.6;
}

Font Weights

Zen supports variable weights (100-900):

Zen Mono:

/* Semantic weight variables */
:root {
  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
}

Best Practices

Do:

Don't:

Accessibility

Minimum sizes:

Contrast requirements:

Example Complete Setup

/* CSS Variables */
:root {
  /* Font families */
  --font-sans: 'Zen', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: 'Zen Mono', 'Fira Code', Consolas, monospace;
  
  /* Font sizes (1.25 scale) */
  --font-size-xs: 0.64rem;
  --font-size-sm: 0.8rem;
  --font-size-base: 1rem;
  --font-size-lg: 1.25rem;
  --font-size-xl: 1.563rem;
  --font-size-2xl: 1.953rem;
  --font-size-3xl: 2.441rem;
  --font-size-4xl: 3.052rem;
  
  /* Font weights */
  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
}

/* Base styles */
body {
  font-family: var(--font-sans);
  font-size: var(--font-size-base);
  line-height: 1.6;
  font-weight: var(--font-weight-normal);
}

/* Code elements */
code, pre, kbd, samp {
  font-family: var(--font-mono);
  font-size: 14px; /* minimum readable size */
  line-height: 1.6;
  font-variant-ligatures: common-ligatures;
}

/* Headings */
h1 { 
  font-size: var(--font-size-4xl);
  font-weight: var(--font-weight-bold);
  line-height: 1.2;
}

h2 { 
  font-size: var(--font-size-3xl);
  font-weight: var(--font-weight-semibold);
  line-height: 1.2;
}

h3 { 
  font-size: var(--font-size-2xl);
  font-weight: var(--font-weight-semibold);
  line-height: 1.3;
}

Loading Fonts in Next.js/React

Zen and ZenMono arrive already built — subsetting, display: swap and the fallback metrics are baked in, so there is nothing to call and nothing to pass.

// app/layout.tsx or _app.tsx
import { Zen, ZenMono } from '@hanzo/font';

export default function RootLayout({ children }) {
  return (
    <html className={`${Zen.variable} ${ZenMono.variable}`}>
      <body>{children}</body>
    </html>
  );
}

They publish --font-zen-sans and --font-zen-mono.

Quick Reference

| Element | Font | Size | Weight | |---------|------|------|--------| | Body text | Zen | 16px (1rem) | 400 | | UI labels | Zen | 14-16px | 500 | | Headings | Zen | Scale-based | 600-700 | | Buttons | Zen | 14-16px | 500-600 | | Code blocks | Zen Mono | 14px min | 400 | | Terminal | Zen Mono | 14px | 400 | | Small text | Zen | 14px min | 400 |