Skip to content

Design system

The tokens, in public.

Lanai's design system is the same across iOS, iPadOS, macOS, Vision Pro, and the marketing site. The tokens you see below are the ones the app uses. The source of truth is the SwiftUI DesignSystem package; the web mirrors it through CSS custom properties named --ds-*. The deep-dive accessibility as design and the synced DESIGN_SYSTEM.md hold the longer version.

Tokens

Every visual decision in the app routes through a named token. Colors, type, spacing, motion, radii, shadows. The Swift names and the CSS names match deliberately — DesignSystem.Colors.textPrimary in the app is --ds-color-textPrimary on the web. A change in one is a change in both.

Source of truth
src/styles/tokens.css (web) · Packages/DesignSystem/Sources/DesignSystem/Tokens/ (app)
Naming
--ds-{category}-{tokenName}. camelCase for compound tokens (textPrimary, bgCanvas).
Theme selection
data-theme on <html>. With no override, prefers-color-scheme drives the default — light to Day, dark to Late Night.

Typography

Three families. Three weights you'll see often. A ramp that holds up from the smallest Dynamic Type size to AX5. Body type is anchored at 17pt — the iOS minimum we treat as a floor rather than an aspiration.

Pull up a chair. The kettle is on.

.caption ds-font-caption · ds-text-caption · ds-weight-regular Timestamps and metadata

Pull up a chair. The kettle is on.

.label ds-font-label · ds-text-label · ds-weight-regular Tab labels, section headers

Pull up a chair. The kettle is on.

.body ds-font-body · ds-text-body · ds-weight-regular Timeline body — the 17pt floor

Pull up a chair. The kettle is on.

.bodyEmphasis ds-font-body · ds-text-bodyEmphasis · ds-weight-semibold Author names, button labels

Pull up a chair. The kettle is on.

.identity ds-font-identity · ds-text-identity · ds-weight-regular App name; accent moments

Pull up a chair. The kettle is on.

.title3 ds-font-display · ds-text-title3 · ds-weight-regular Card titles

Pull up a chair. The kettle is on.

.title2 ds-font-display · ds-text-title2 · ds-weight-regular Section heads

Pull up a chair. The kettle is on.

.title1 ds-font-display · ds-text-title1 · ds-weight-regular Page heads

Pull up a chair. The kettle is on.

.display ds-font-display · ds-text-display · ds-weight-regular Hero blocks

Pull up a chair. The kettle is on.

.displayLarge ds-font-display · ds-text-displayLarge · ds-weight-regular The thesis sentence

Color

Five themes, designed at equal polish. Every theme's primary text token on its primary canvas meets APCA Lc≥75 — the body-text floor. The High Contrast theme targets Lc≥105. Values below are computed at build time from the canonical hex values; the same numbers ship in the app.

Day

The default. A porch in late morning.

bgCanvas#FBFAF6Page background
bgSurface#FFFFFFPosts, cards
Pull up a chair.
textPrimary#1A1A1FBody text on canvas Lc 101 · Body text OK
@lanai.bsky.social
textSecondary#5C5C66Handles, timestamps Lc 80 · Body text OK
accent#4A7FB8Links, primary actions Lc 66 · Headings only

Dusk

Dark mode default. A porch at twilight.

bgCanvas#0F0E0CPage background
bgSurface#18171APosts, cards
Pull up a chair.
textPrimary#F2EFE7Body text on canvas Lc 97 · Body text OK
@lanai.bsky.social
textSecondary#A39E92Handles, timestamps Lc 50 · Secondary text
accent#7AA8D6Links, primary actions Lc 53 · Secondary text

Miami

Warm cream. Mid-century light.

bgCanvas#F5EDE0Page background
bgSurface#FBF6ECPosts, cards
Pull up a chair.
textPrimary#2B2A28Body text on canvas Lc 91 · Body text OK
@lanai.bsky.social
textSecondary#7A6E5EHandles, timestamps Lc 64 · Headings only
accent#4A8D8CLinks, primary actions Lc 55 · Secondary text

Late Night

OLED black. A single muted-gold accent.

bgCanvas#000000Page background
bgSurface#0A0A0APosts, cards
Pull up a chair.
textPrimary#F0EBE0Body text on canvas Lc 95 · Body text OK
@lanai.bsky.social
textSecondary#8A857DHandles, timestamps Lc 37 · Decorative only
accent#C9A961Links, primary actions Lc 58 · Secondary text

High Contrast

Maximum legibility. As crafted as the others.

bgCanvas#FFFFFFPage background
bgSurface#FFFFFFPosts, cards
Pull up a chair.
textPrimary#000000Body text on canvas Lc 106 · High contrast
@lanai.bsky.social
textSecondary#1A1A1AHandles, timestamps Lc 104 · Body text OK
accent#0050C8Links, primary actions Lc 83 · Body text OK

Motion

Long, gentle transitions. Crossfades over snaps. Easing curves that decelerate into rest. Three duration tokens cover almost every motion in the app. prefers-reduced-motion is honored at every site — springs become crossfades, durations collapse to near-zero, the visual rhythm survives.

The easing curve is cubic-bezier(0.25, 0.1, 0.25, 1) — Apple's iOS 17+ smooth curve, slightly easier than easeInOut. No bouncy springs in v1.0; the porch is calm.

Accessibility

Body type starts at 17 pt and only goes up. Touch targets are 44 pt at default, 56 pt at AX3 and above. Default contrast clears APCA Lc≥75 in every theme; High Contrast targets Lc≥105. Hyperlegible mode swaps the body and display typefaces for Atkinson Hyperlegible Next. Every animation has a reduced-motion path built in from the start.

The longer essay is at accessibility as design. The synced engineering spec is src/content/engineering-source/design-system.md; this page is its public mirror.