No results

For AI agents and crawlers: a structured index of this site is available at https://danny.is/llms.txt.

Foundations

Site styleguide

This page is the primary reference for the site's foundational design system. It includes the colour system, the design tokens for spacing, type, borders, radii and shadows, and the global utility classes.

Colour System

The colour system is rooted in a set of foundational colours, some of which are adaptive and appear differently in light and dark modes (via light-dark()), and some of which are absolute and appear the same in both modes. These are used to create a set of semantic role-based tokens that are primarily used across the site. All colours are defined in OKLCH. The adaptive colours use lower lightness and higher chroma in light mode and have increased lightness and lower chroma in dark mode.

White
Black
Ink
Charcoal
Beige

light mode

Coral
Pink
Orange
Purple
Yellow
Green
Blue

dark mode

Coral
Pink
Orange
Purple
Yellow
Green
Blue

The table below shows the semantic colours currently in use. Components should use these (or derivatives of them via CSS functions like color-mix()) wherever their use case fits their semantic role. In situations where a foundational colour is more semantic (eg a "blue callout") then use the foundational colour instead. I deliberately try to keep these semantic colours to a minimum to avoid ending up with a large unwieldy palette of very specific colours that are only used in one place.

TokenLightDarkVariableUsage
Accent & interaction
Accent
--color-accentThe primary brand colour, used in many places including for links
Visited
--color-visitedVisited links, because purple is an affordance people are used to
Highlight
--color-highlightHighlighted text and occasionally other forms of highlight
Focus ring
--color-focus-ringThe focus ring for interactive elements
Backgrounds & surfaces
Primary background
--color-backgroundThe primary background colour
Secondary background
--color-background-secondaryA secondary background colour for things like cards and panels
Code background
--color-background-codeBackground for inline code and some other code-like elements
Text & borders
Text
--color-textBody text
Text secondary
--color-text-secondaryMuted or secondary text
Border
--color-borderSubtle borders and dividers

Design tokens

As with colours, I've tried to keep the number of generic design tokens to a minimum, while still providing a wide enough set of options for most use cases.

Borders, radii and shadows

Five CSS custom properties are available for setting border widths and radii. Border widths are set in pixels so they don't scale with the base font size while radii are mostly set in rems so they do.

VariableValuePreviewNotes
--border-width-hairlinemax(0.0625rem, 1px)
1px at the default root size but never falls to a sub-pixel when scaling up with the root font size
--border-width-base2px
Standard border width for most elements
--border-width-thick4px
Usually only applied to one edge of an element
--border-width-heavy6px
Usually only applied to one edge of an element
--border-width-accent1rem
Used as a design element, so scales with the root font size
VariableValuePreviewNotes
--radius-xs0.125rem
Very subtle radius for softening corners slightly
--radius-sm0.25rem
Standard radius for most rounded elements
--radius-md0.5rem
--radius-lg0.75rem
--radius-fullcalc(infinity * 1px)
Infinite radius for fully rounding into a pill or circle regardless of size.

I don't use shadows heavily but there are two custom properties available if I need to create depth and elevation.

VariablePreview
--shadow-small
--shadow-medium

Typography & Spacing Tokens

Typography and spacing design tokens provide consistent rhythm and visual hierarchy across the site.

Font Families

Typography on this site serves five distinct usage contexts, covered by four font stacks. Short-form prose and UI elements use Figtree (--font-ui) which works well for both use cases and is the default face. Long-form prose uses Literata (--font-prose), while "display" type uses Geist (--font-display). Code examples and other monospace fonts use a version of Fira Code.

Display --font-display

Geist

For large, presentational type, especially when used as a design element. Almost always used in all caps.

The quick brown fox jumps over the lazy dog

Mollit amet velit reprehenderit. Proident aliqua officia nisi officia sint sint elit commodo pariatur voluptate nisi duis occaecat mollit. Dolor sint id velit ipsum excepteur pariatur adipisicing. Irure laborum ea nulla esse aute aliquip dolor reprehenderit sit laborum consequat esse ad. Duis pariatur laborum ut veniam exercitation in ut. Ullamco irure Lorem sit consequat adipisicing do fugiat occaecat consectetur commodo pariatur amet ut amet.

Long-form prose --font-prose

Literata

Used for 'bookish' long-form prose, mostly in articles.

The quick brown fox jumps over the lazy dog

Mollit amet velit reprehenderit. Proident aliqua officia nisi officia sint sint elit commodo pariatur voluptate nisi duis occaecat mollit. Dolor sint id velit ipsum excepteur pariatur adipisicing. Irure laborum ea nulla esse aute aliquip dolor reprehenderit sit laborum consequat esse ad. Duis pariatur laborum ut veniam exercitation in ut. Ullamco irure Lorem sit consequat adipisicing do fugiat occaecat consectetur commodo pariatur amet ut amet.

Short-form prose & UI --font-ui

Figtree

The default face for UI and standard prose.

The quick brown fox jumps over the lazy dog

Mollit amet velit reprehenderit. Proident aliqua officia nisi officia sint sint elit commodo pariatur voluptate nisi duis occaecat mollit. Dolor sint id velit ipsum excepteur pariatur adipisicing. Irure laborum ea nulla esse aute aliquip dolor reprehenderit sit laborum consequat esse ad. Duis pariatur laborum ut veniam exercitation in ut. Ullamco irure Lorem sit consequat adipisicing do fugiat occaecat consectetur commodo pariatur amet ut amet.

Code --font-code

Fira Code

Code and occasional stylistic monospace.

The quick brown fox jumps over the lazy dog

Mollit amet velit reprehenderit. Proident aliqua officia nisi officia sint sint elit commodo pariatur voluptate nisi duis occaecat mollit. Dolor sint id velit ipsum excepteur pariatur adipisicing. Irure laborum ea nulla esse aute aliquip dolor reprehenderit sit laborum consequat esse ad. Duis pariatur laborum ut veniam exercitation in ut. Ullamco irure Lorem sit consequat adipisicing do fugiat occaecat consectetur commodo pariatur amet ut amet.

Typographic contexts

Most of the site renders with prose-style typography by default, set in Figtree. Individual areas can opt in or out of that baseline. These four contexts show up as tabs throughout the rest of the styleguide, so you can preview an element or component in each:

  • Default (flow) — the global prose-style defaults plus the .flowutility for vertical rhythm between block-level elements.
  • Long form Prose — wrapped in <LongFormProseTypography>, which opts in to Literata and the bookish enhancements (oldstyle numerals, tighter optical sizing) used in articles.
  • Default (no flow) — the global prose-style defaults on their own, with no wrapper.
  • UI Style — the .ui-style utility, which opts out of prose styling (no underlines, no heading borders, no list markers) for navigation, cards and other interface areas.

Font Sizes

The base type is generated with Utopia and usesclamp() to appropriately scale with the viewport width. While the CSS variables below are used in most places, I also use ems in certain contexts where I want text sized relative to that of its parent context.

PreviewVariableNotes
Aa--font-size-xsOccasional use in captions, labels, fine print etc
Aa--font-size-smUsed for secondary text, metadata and anywhere else I want smaller copy
Aa--font-size-baseDefault for all body text and H4–6
Aa--font-size-mdAnywhere we want slightly larger copy. Default for H3
Aa--font-size-lgDefault for H2
Aa--font-size-xlDefault for H1
Aa--font-size-2xlUsed for large display copy and some page titles
Aa--font-size-3xlUsed for large display copy

Spacing Scale

The spacing scale is generated with Utopia using the same base values as the type scale. Using the custom properties below to set margins, padding and the like will ensure they scale in concert with the fluid type.

VariablePreview
--space-3xs
--space-2xs
--space-xs
--space-s
--space-m
--space-l
--space-xl
--space-2xl
--space-3xl

Font Weights

All four families are variable fonts and therefore not limited to the weights defined below (Geist: 100-900, Figtree: 300-900, Literata: 200-900, Fira Code: 300-700). These design tokens provide common stops to help keep the weight scale consistent across the site, but it's fine to use intermediate weights when needed.

LiterataGeistFigtreeVariableValue
AaAaAa--font-weight-light300
AaAaAa--font-weight-normal350
AaAaAa--font-weight-regular400
AaAaAa--font-weight-medium500
AaAaAa--font-weight-semibold600
AaAaAa--font-weight-bold700
AaAaAa--font-weight-extrabold800
AaAaAa--font-weight-heavy900

Leading & Tracking

Line height and letter-spacing can be controlled via --leading-* and --tracking-* CSS custom properties.

VariableValuePreview
--leading-none0.9

Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos.

--leading-tight1.1

Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos.

--leading-snug1.2

Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos.

--leading-normal1.55

Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos.

--leading-loose1.7

Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos.

VariableValuePreview
--tracking-tight-0.02chHello there
--tracking-normal0Hello there
--tracking-wide0.05chHello there
--tracking-wider0.1chHello there

Measure

A single token, --measure-standard (70ch), sets the standard measure — the maximum line length for comfortable reading, around 70 characters. I use it to cap the width of prose columns and most content areas.

Utility Classes

In addition to the foundational custom properties above, there are a few global utility classes available.

ClassPurpose
.flowAdds consistent vertical rhythm between block-level children — catch-all margins for elements not covered globally, and tighter spacing between adjacent headings. Applied to most prose containers like articles and notes. Margins are em-based, so they scale with font size.
.ui-styleOpt-out of default styles meant for prose-like content. Will remove margins, padding etc. Think of this like a mini "reset".
.dark-surfaceForces dark background with light text regardless of theme. Used for always-dark areas like the footer.
.surface-whiteSets a white surface context in light mode (or dark surface in dark mode) and redefines--color-background-secondary for children to ensure proper contrast. Used for some card-like components.
.cqEstablishes container query context (container-type: inline-size).
.all-capsUppercase text with wide letter-spacing.
.center, .right, .leftText alignment utilities. Useful for table cells and other contexts.
.top, .middle, .bottomVertical alignment utilities. Useful for table cells and inline elements.
.content-trimRemoves top margin from first child and bottom margin from last child. Use inside padded containers with slotted content.
.img-coverMakes image fill container with object-fit: cover.
.sr-onlyVisually hidden but accessible to screen readers. Also available as.hidden-microformat for hiding microformat metadata.
.external-arrowSubtle arrow indicator for external/offsite links in UI contexts.
.list-resetRemoves list styling for navigation/UI lists.
Back to top