Visual identity system for Haleiki -- covering the brand mark, colour architecture, typography, spacing, and implementation. Built in OKLCH, scaled with a perfect fourth, fluid from phone to ultrawide.
The Haleiki brand mark is a single geometric letterform -- the "H" -- rendered in the accent colour against a rounded rectangle. It functions at every scale: favicon, topnav, footer, and documentation.
Shown at 120px on both surface treatments. The mark uses --accent-primary as its background, which shifts from terracotta (day) to amber (night) with theme switching.
Haleiki communicates scholarly warmth, navigational clarity, and the quiet confidence of a well-organized library. The design language draws from Wikipedia's information architecture, modernized with perceptually uniform colour, geometric type scale, and intrinsic layout composition.
Day theme colour tokens. All values defined in OKLCH for perceptual uniformity -- equal lightness steps produce equal perceived brightness.
Night theme colour tokens. The palette shifts to deep oxide surfaces with amber accents, maintaining the same semantic structure as the day theme.
How each semantic token resolves across themes. The token name stays constant; the OKLCH value shifts to maintain contrast and legibility in each context.
| Token | Day (OKLCH) | Night (OKLCH) | Purpose |
|---|---|---|---|
| surface-ground | 0.97 0.01 80 | 0.16 0.02 55 | Page background |
| surface-primary | 0.99 0.005 80 | 0.20 0.02 55 | Card / panel background |
| surface-secondary | 0.95 0.015 75 | 0.24 0.025 52 | Sidebar, input fields |
| surface-tertiary | 0.92 0.02 72 | 0.28 0.03 50 | Hover states, zebra rows |
| surface-invert | 0.25 0.03 55 | 0.92 0.02 75 | Inverted sections, card headers |
| border-subtle | 0.88 0.025 75 | 0.30 0.03 50 | Soft dividers |
| border-default | 0.82 0.03 72 | 0.36 0.035 48 | Standard borders |
| border-strong | 0.70 0.04 65 | 0.48 0.04 50 | Prominent borders |
| text-primary | 0.22 0.02 55 | 0.90 0.015 75 | Body text, headings |
| text-secondary | 0.40 0.03 60 | 0.72 0.02 65 | Subtitles, descriptions |
| text-tertiary | 0.55 0.025 65 | 0.55 0.025 58 | Captions, metadata |
| accent-primary | 0.55 0.14 45 | 0.72 0.14 70 | Brand mark, buttons, links |
| accent-hover | 0.48 0.15 42 | 0.78 0.15 72 | Interactive hover state |
| accent-subtle | 0.92 0.04 50 | 0.28 0.06 60 | Active TOC item background |
| accent-text | 0.45 0.12 40 | 0.78 0.12 72 | Accent-coloured text |
| info-surface | 0.94 0.03 80 | 0.24 0.03 55 | Callout background |
| code-surface | 0.95 0.01 80 | 0.22 0.02 55 | Code block background |
| code-text | 0.38 0.08 40 | 0.78 0.1 72 | Code text |
Each typeface serves a distinct role. Together they create a reading experience that is structured yet warm -- navigational without being mechanical, scholarly without being cold.
Clean geometric sans-serif designed by Jeremy Mickel for Red Hat. Open counters, slightly rounded stroke endings, and generous x-height make it legible at every scale -- from navigation labels to hero headings. The variable weight axis provides fine control over visual hierarchy.
The geometric clarity of Red Hat Display communicates the structured, navigational quality of a knowledge base. Its humanist touches -- the slightly rounded stroke endings, the open counters -- keep it warm rather than clinical.
Production Type's Newsreader is a variable serif with optical sizing. Transitional old-style roots designed for sustained reading. The editorial energy fits a knowledge base -- it says "here is something worth reading carefully."
The opsz axis is key: at 72, Newsreader is elegant and refined for headlines; at 14, the letterforms are sturdier, with more open spacing and thicker thin strokes for comfortable body reading.
Monospace with human warmth. Used for code blocks, inline code, metadata, tags, section labels, and system-level information. IBM Plex Mono avoids the cold, mechanical quality of many monospace faces -- its curves and proportions echo the warmth of the rest of the type stack.
| Step | Min | Max | Usage |
|---|---|---|---|
| step 4 | 50.5px | 56.8px | Hero / page title (Red Hat Display) |
| step 3 | 37.9px | 42.6px | Article title, section heading (Red Hat Display) |
| step 2 | 28.4px | 32px | Subsection heading (Red Hat Display) |
| step 1 | 21.3px | 24px | Lead paragraph, subtitle (Newsreader) |
| step 0 | 16px | 18px | Body text (Newsreader) |
| step -1 | 12px | 13.5px | Caption, TOC links (Newsreader) |
| step -2 | 9px | 10.1px | Metadata, labels (IBM Plex Mono) |
Fluid spacing tokens generated from the same perfect fourth ratio. All values interpolate between min and max using CSS clamp() with the vi unit.
| Token | Min | Max | Typical Use |
|---|---|---|---|
| space-3xs | 4px | 5px | Tight inline gaps, tag internal padding |
| space-2xs | 8px | 9px | Icon-to-label, compact gaps |
| space-xs | 12px | 13.5px | Label-to-input, list item spacing |
| space-s | 16px | 18px | Default component padding |
| space-m | 24px | 27px | Card padding, paragraph spacing |
| space-l | 32px | 36px | Section padding |
| space-xl | 48px | 54px | Major section gaps |
| space-2xl | 64px | 72px | Hero padding, page-level rhythm |
| space-3xl | 96px | 108px | Full-page vertical breathing room |
Steeper interpolation between two named sizes. Used where spacing should grow more aggressively on wider viewports.
| Token | Min | Max | Typical Use |
|---|---|---|---|
| space-s-m | 16px | 27px | Component-to-component within a region |
| space-s-l | 16px | 36px | Responsive page padding |
| space-m-l | 24px | 36px | Column gap in layout primitives |
| space-m-xl | 24px | 54px | Section top margin (prose h2) |
| space-l-xl | 32px | 54px | Footer top margin, major breaks |
Intra-group spacing must always be tighter than inter-group spacing. This activates gestalt proximity grouping -- the perceptual mechanism that makes related elements feel connected. A card with uniform 16px everywhere destroys all spatial information. Title-to-subtitle at 4px, subtitle-to-meta at 8px, card padding at 16px, between cards at 24px -- four scales communicating four relationships.
Intrinsic layout using Every Layout primitives and Utopia fluid spacing. Zero media queries for column arrangement -- the layout adapts by measuring its own available space.
The article page uses a nested Sidebar pattern: a left navigation column (table of contents), a main article column, and a right sidebar (taxonomy card). The columns wrap intrinsically when there is not enough space -- the left nav disappears first, then the right sidebar stacks above the article.
| Token | Value | Purpose |
|---|---|---|
| --content-max | 58ch | Prose line length (optimal readability) |
| --sidebar-width | 280px | Right sidebar (taxonomy card) |
| --nav-width | 220px | Left navigation (TOC) |
| --page-max | 1320px | Outer page container |
No media queries for layout. The flexbox-based Sidebar primitives use min-inline-size and flex-grow to decide when columns should wrap. This means the layout works at every viewport width, including sizes that media queries would miss (split-screen, embedded views, print).
Content decisions use media queries. Hiding the left nav on narrow viewports is a content decision (removing a component), not a layout decision. This is the one place a breakpoint is used: @media (max-width: 60rem).
Three tiers: Primitive tokens (OKLCH values) map to semantic tokens (--surface-primary, --accent-text) which feed component tokens (.topnav background, .info-card-header colour). This indirection enables theme switching: swap the primitive-to-semantic mapping, and every component updates automatically.
The stylesheet is organized into cascade layers to eliminate specificity conflicts:
@layer tokens, reset, base, layout, components, utilities
Tokens define custom properties. Reset normalizes elements. Layout handles structural positioning. Components style individual UI pieces. Utilities provide overrides. Each layer has strictly higher priority than the one before it.
All type and spacing values use CSS clamp() for fluid interpolation. The vi unit (viewport inline) is used instead of vw to respect writing direction. No breakpoints are needed for sizing -- values scale continuously between their min and max bounds.
Cobalt static site generator with Liquid templates. Pagefind for client-side search indexing. Content authored in Markdown, compiled to static HTML. No JavaScript frameworks, no build-time CSS processing -- just clean CSS custom properties and cascade layers.
Geometric scale. Every size derives from one ratio (4:3). No magic numbers.
Perceptual uniformity. OKLCH ensures equal lightness steps look equal to human eyes.
Semantic naming. Tokens describe purpose, not appearance. --accent-primary, not --terracotta.
Constraint. Fewer choices, made well. Three typefaces. One ratio. Two themes.
Unity not uniformity. Day and night themes share structure but differ in expression.
Proximity as syntax. Spacing communicates relationships. Tighter = more related.
Design the invariants. Build the system that survives content changes, not a page that looks good with today's content.