Typography
Bumi uses four font families, each with a distinct role. The combination of serif titles, sans-serif body, and monospace data creates a clear visual hierarchy without relying on color.
Font Families
Display: Plus Jakarta Sans
The primary UI typeface. Designed by Tokotype, an Indonesian type foundry. Used for headings, labels, navigation, and UI chrome.
font-family: 'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;Serif: Lora
Used exclusively for page titles. Adds editorial weight and distinguishes the page-level heading from all other text.
font-family: 'Lora', Georgia, 'Times New Roman', serif;Body: Inter
The workhorse. Used for body text, descriptions, table cells, and long-form content. Optimized for screen readability.
font-family: 'Inter', system-ui, -apple-system, sans-serif;Mono: JetBrains Mono
Used for numerical data, prices, SKUs, timestamps, transaction IDs, and code. Monospace alignment makes columns of numbers easy to scan.
font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;Type Scale
| Size | px | rem | Usage |
|---|---|---|---|
| Micro | 10px | 0.625 | Micro labels, legal text |
| Badge | 11px | 0.6875 | Badges, pills, status tags |
| Label | 12px | 0.75 | Labels, metadata, timestamps |
| Body Small | 13px | 0.8125 | Nav items, secondary body text |
| Body | 14px | 0.875 | Default body text, table cells |
| Body Large | 16px | 1.0 | Emphasized body, intro paragraphs |
| Card Title | 18px | 1.125 | Card headings, dialog titles |
| Section Header | 24px | 1.5 | Section headings (Jakarta Sans) |
| Sub-page Title | 28px | 1.75 | Sub-page headings (Jakarta Sans) |
| Page Title | 32px | 2.0 | Page titles (Lora) |
Font Weights
| Weight | Value | Usage |
|---|---|---|
| Regular | 400 | Body text, descriptions |
| Medium | 500 | Labels, nav items, medium emphasis |
| Semibold | 600 | Card titles, emphasis, table headers |
| Bold | 700 | Section headings, strong emphasis |
| Extrabold | 800 | Display numbers (dashboard KPIs) |
Line Height
| Context | Value | Usage |
|---|---|---|
| Display | 1.1 | Page titles, large headings |
| Headings | 1.3 | Section headers, card titles |
| Body | 1.5 | Default body text |
| Long text | 1.6 | Paragraphs, descriptions, help text |
Letter Spacing
| Context | Value | Usage |
|---|---|---|
| Display / Serif | -0.02em | Page titles in Lora |
| Body | 0 | Default --- no adjustment |
| Uppercase labels | 0.04em | Section group labels, tab labels |
| Section labels | 0.08em | Sidebar section headers, overlines |
Usage by Context
Page Title
.page-title {
font-family: 'Lora', Georgia, serif;
font-size: 32px;
font-weight: 400; /* Lora looks best at normal weight */
line-height: 1.1;
letter-spacing: -0.02em;
color: var(--text-1);
}Section Header
.section-header {
font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
font-size: 24px;
font-weight: 700;
line-height: 1.3;
color: var(--text-1);
}Card Title
.card-title {
font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
font-size: 18px;
font-weight: 600;
line-height: 1.3;
color: var(--text-1);
}Body Text
.body {
font-family: 'Inter', system-ui, sans-serif;
font-size: 14px;
font-weight: 400;
line-height: 1.5;
color: var(--text-1);
}Data / Numbers
.data {
font-family: 'JetBrains Mono', monospace;
font-size: 14px;
font-weight: 400;
line-height: 1.5;
font-variant-numeric: tabular-nums;
color: var(--text-1);
}Sidebar Section Label
.sidebar-section {
font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
font-size: 11px;
font-weight: 600;
line-height: 1.3;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text-3);
}Badge / Pill
.badge {
font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
font-size: 11px;
font-weight: 600;
line-height: 1;
letter-spacing: 0.02em;
}Loading Fonts (Web)
Add to your HTML <head> or import in CSS:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lora&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&family=Plus+Jakarta+Sans:wght@500;600;700;800&display=swap" rel="stylesheet">Mobile Font Strategy
On mobile (React Native), loading four web fonts impacts startup time and bundle size. Use this approach:
| Role | Font | Mobile Strategy |
|---|---|---|
| Headings | Plus Jakarta Sans | Load via expo-font --- this is our identity font |
| Serif titles | Lora | Skip --- use Jakarta Sans bold instead |
| Body | Inter | Use system font (San Francisco on iOS, Roboto on Android) |
| Mono | JetBrains Mono | Use system monospace (Platform.select({ ios: 'Menlo', android: 'monospace' })) |
// React Native font loading
import { useFonts } from 'expo-font';
const [fontsLoaded] = useFonts({
'PlusJakartaSans-Medium': require('../assets/fonts/PlusJakartaSans-Medium.ttf'),
'PlusJakartaSans-SemiBold': require('../assets/fonts/PlusJakartaSans-SemiBold.ttf'),
'PlusJakartaSans-Bold': require('../assets/fonts/PlusJakartaSans-Bold.ttf'),
});DO and DON'T
DO
- Use Lora for the single top-level page title only
- Use JetBrains Mono for all prices, quantities, IDs, and timestamps
- Use tabular-nums (
font-variant-numeric: tabular-nums) for numbers in tables - Keep body text at 14px --- this is the readable default for dense data apps
DON'T
- Don't use Lora for card titles, section headers, or labels --- that is Jakarta Sans territory
- Don't use more than two font families in a single component
- Don't go below 10px for any text (accessibility)
- Don't use font-weight 300 (light) --- it lacks presence on low-DPI screens