Design System
Design System
Plain CSS design system for principles.design. No preprocessors, no build tools — CSS custom properties and modern CSS only.
Live Documentation
The design system page at /design-system/ uses Jekyll includes to render component previews. This keeps the documentation in sync with the actual components automatically — when a component changes, the preview updates too.
Components support a preview parameter to disable interactive elements:
{% include footer.html preview=true %}
When preview=true:
- Form inputs and buttons are disabled
- Form submission is prevented
- Required validation is skipped
Architecture
_includes/css/
tokens.css Design tokens (colors, scale, spacing)
reset.css Modern CSS reset
typography.css Typographic scale and vertical rhythm
layout.css Grid system and content areas
components/
navigation.css Site navigation and active states
tile.css Example cards and grid/list views
forms.css Search, subscribe, filters
footer.css Site footer and credits
misc.css Links, sorting, menus, decorations
docs.css Design system documentation page
utilities.css Spacing, visibility, accessibility helpers
assets/css/
site.css Jekyll-processed entry point (concatenates all includes)
Design Tokens
Colors
| Token | Value | Usage |
|---|---|---|
--color-primary |
#f7d708 |
Yellow — brand, highlights, CTAs |
--color-primary-light |
#fdf7ce |
Light yellow — subtle backgrounds |
--color-secondary |
#0015dd |
Blue — hover states, accents |
--color-text |
#333 |
Body text, headings, borders |
--color-text-muted |
#666 |
Secondary text |
--color-text-subtle |
#999 |
Tertiary text, captions |
--color-border |
#e6e6e6 |
Borders, dividers |
--color-surface |
#fff |
Page background |
--color-surface-alt |
#f5f5f5 |
Alternate backgrounds |
--color-surface-dark |
#2c2c2c |
Dark footer background |
--color-text-light |
#f0f0f0 |
Off-white text on dark backgrounds |
--color-success |
#388E3C |
Success states, confirmations |
--color-error |
#d32f2f |
Error states, warnings |
Typography
Font: Inter (variable, self-hosted) - Live on production
Font stack: 'Inter', system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif
Font file: Inter-Variable.woff2 (291KB) - Full character set with variable weight support
Root size: 19px
Scale (rem):
| Token | Size | Computed | Usage |
|---|---|---|---|
--step-0 |
1rem |
19px | Body text, h4 |
--step-1 |
1.3158rem |
25px | Large body text |
--step-2 |
1.6316rem |
31px | h3 (desktop), h2 (mobile) |
--step-3 |
2.6316rem |
50px | h2 (desktop), h1 (mobile) |
--step-4 |
4.2105rem |
80px | h1 (desktop) |
The scale steps down one level on mobile (below 920px). For example, h2 uses --step-2 on mobile and --step-3 on desktop.
Vertical Rhythm
All vertical spacing is based on a single baseline unit:
--baseline: 1.5263rem (29px)
This is one line of body text (19px × 1.5263). All margins, padding, and spacing should be whole multiples of this unit.
Spacing scale
| Token | Multiple | Computed |
|---|---|---|
--space-4xs |
0.125× | ~3.6px |
--space-3xs |
0.25× | ~7.3px |
--space-2xs |
0.375× | ~10.9px |
--space-xs |
0.5× | ~14.5px |
--space-s |
0.75× | ~21.7px |
--space-m |
1× | 29px |
--space-l |
1.5× | ~43.4px |
--space-xl |
2× | 58px |
--space-2xl |
3× | 87px |
--space-3xl |
4× | 116px |
Transitions
| Token | Value | Usage |
|---|---|---|
--transition-fast |
0.2s ease-in-out |
Hover states, micro-interactions |
--transition-slow |
0.3s ease-in-out |
Background changes, larger state changes |
Rule: Heading margins always snap to whole baseline units. Body text (p, ul, ol) has margin-bottom: var(--baseline).
Heading rhythm
| Element | Mobile | Desktop |
|---|---|---|
| h1 | 1 baseline top, 1 bottom | 1 baseline top, 2 bottom |
| h2 | 1 baseline top, 0 bottom | 1 baseline top, 1 bottom |
| h3 | 1 baseline top, 0 bottom | 1 baseline top, 0 bottom |
| h4 | 1 baseline top, 0 bottom | 1 baseline top, 0 bottom |
Measure
Body text has a maximum width of 40rem (~65–75 characters) for optimal readability.
Layout
12-column CSS grid with a maximum width of 1080px and 85% viewport width.
Breakpoints
| Name | Value | Usage |
|---|---|---|
| Small | 400px |
Minor mobile adjustments |
| Medium | 700px |
Two-column layouts, form changes |
| Large | 920px |
Typography scale steps up, three-column tiles |
| Extra large | 1100px |
Navigation switches to horizontal bar |
Grid classes
| Class | Span (mobile) | Span (desktop) |
|---|---|---|
.full |
12 | 12 |
.two-up |
12 | 6 |
.two-thirds |
12 | 8 |
.three-up |
6 | 3 |
.info-block |
12 | 8 |
aside |
12 | 4 |
Utilities
| Class | Effect |
|---|---|
.mtn |
margin-top: 0 |
.mbn |
margin-bottom: 0 |
.mbm |
margin-bottom: 0.6rem |
.pbn |
padding-bottom: 0 |
.lhs |
line-height: 1.4 |
.bold |
font-weight: bold |
.tdn |
text-decoration: none |
.sr-only |
Visually hidden, accessible to screen readers |
Usage
Adding a new component
- Create a new file in
_includes/css/components/ - Add
{% include css/components/yourfile.css %}to bothassets/css/site.cssand_includes/css.html - Use tokens for all values — never hardcode colors, spacing, or font sizes
CSS loading strategy
CSS source files live in _includes/css/ so Jekyll’s {% include %} tag can find them. Loading is handled in _includes/css.html and switches automatically based on environment:
Development (default)
bundle exec jekyll serve
# or
./scripts/dev.sh
jekyll.environmentdefaults to"development"- Loads
assets/css/site.cssvia a<link>tag site.cssis a Jekyll-processed file (has front matter) that concatenates all CSS via{% include %}- Supports live reload — edit a CSS file, Jekyll rebuilds automatically
- Single HTTP request — one concatenated file
Production (GitHub Pages)
- GitHub Pages sets
JEKYLL_ENV=productionautomatically _includes/css.htmluses{% include %}to concatenate all CSS files into a single inline<style>block- Zero HTTP requests for CSS — everything is embedded in the HTML
- No render-blocking external stylesheets
Testing production mode locally
JEKYLL_ENV=production bundle exec jekyll serve
Adding a new CSS file
When you add a new CSS file, it must be registered in two places:
assets/css/site.css— add a{% include css/components/yourfile.css %}line (for development)_includes/css.html— add a{% include css/components/yourfile.css %}line inside the<style>block (for production)
Current file load order
tokens.css → Design tokens (custom properties)
reset.css → Modern CSS reset
typography.css → Typographic scale and vertical rhythm
layout.css → Grid system and content areas
components/navigation.css
components/tile.css
components/forms.css
components/footer.css
components/misc.css
components/docs.css
utilities.css → Spacing, visibility helpers (loaded last to ensure overrides)
Order matters: tokens must load first (other files reference them), utilities must load last (they need to override component styles).
Live documentation
The design system is documented at /design-system/ — a Jekyll page that renders all tokens, typography specimens, spacing scales, and component examples using the actual CSS. This page stays in sync automatically because it uses the same tokens and classes as the rest of the site.
Source: _pages/design-system.html
CSS: _includes/css/components/docs.css
Migration notes
This system replaces the previous Ruby Sass setup (_sass/ directory). The _sass/ directory is retained as reference but is no longer compiled or used. The Sass config has been removed from _config.yml.