Design system

Still morning.

Warm paper with a lime undercurrent. Crimson Pro for display type, Mozilla Text for body. A layered texture system — noise grain, lime wash, diagonal hatch, fine grid — that gives structure without weight.

Color

Backgrounds

bg-primary

#f7f6f4 — warm off-white page

bg-elevated

#ffffff — pure white, content panels

bg-overlay

Translucent warm wash

bg-overlay-strong

Stronger translucent wash

Lime tonal scale

The site's primary accent hue. Used for header zones, the footer, pattern lines, eyebrow labels, and the ambient lime wash on the page surface.

lime-50

oklch(97% 0.012 118) — footer base

lime-100

oklch(92% 0.04 118) — header bands

lime-200

oklch(86% 0.09 118) — borders on lime

lime-400

#bac820 — accent-lime, vibrant

lime-600

#5c6900 — accent-sunset, text-safe olive

Section accents

Each section of the site has a tonal scale. Lime is the primary accent; sage anchors Garden; slate anchors About.

accent-lime

#bac820 — Granola lime, vibrant fills

accent-sunset

#5c6900 — links, eyebrows, text accent

accent-sage

#5e7a5c — Garden section

accent-slate

#5a6e8a — About section

Text

text-primary --text-primary · #181614
text-secondary --text-secondary · #4a4642
text-muted --text-muted · #7a7572
text-faint --text-faint · #b0acaa — avoid on lime surfaces

Borders

--border · #e6e4e1 — default hairline
--border-strong · #cccac7 — structural rules, dotted dividers
--lime-400 dotted — footer/lime zone borders

Typography

Typefaces

Crimson Pro

--font-display · Display headings, editorial titles, page heroes

Regular Medium Italic

Mozilla Text

--font-body · --font-sans · Body copy, UI labels, meta, captions

Regular Medium Semibold

Type scale

--text-5xl 48px Display hero
--text-4xl 40px Large hero
--text-3xl 32px Section hero
--text-2xl 24px Page title
--text-xl 22px Section title
--text-lg 18px Lead paragraph
--text-md 16px Emphasized body
--text-base 15px Body (default)
--text-sm 13px Secondary body
--text-xs 12px Meta, captions
--text-2xs 11px Micro labels

Named styles

.editorial__title

The orchard.

.editorial__lede

Lead paragraph — the first thing you read after the title.

.editorial__eyebrow

Work

Spacing

4px base grid. All spacing tokens are multiples of 4px.

--space-1
4px 0.25rem
--space-2
8px 0.5rem
--space-3
12px 0.75rem
--space-4
16px 1rem
--space-5
20px 1.25rem
--space-6
24px 1.5rem
--space-8
32px 2rem
--space-10
40px 2.5rem
--space-12
48px 3rem
--space-16
64px 4rem
--space-20
80px 5rem
--space-24
96px 6rem

Texture & Patterns

A layered texture system gives the site surface depth without weight. Four patterns, each with a specific role. The rule: textures live in structural zones, never behind running prose.

Body — noise + lime wash

Every page surface has paper grain (feTurbulence SVG, multiply blend) with a 7%-opacity lime wash underneath. This ties all surfaces to the lime system without changing --bg-primary.

Body surface — visible on any gap or margin
/* Applied globally on body */
background-image: var(--noise-svg), var(--texture-lime-wash);
background-size: 200px 200px, 100% 100%;
background-blend-mode: multiply, normal;

.surface-noise-gradient — hero / header zones

Structural zone bands: noise + 80px square grid + lime-to-paper gradient. Used on page header intros and work case-study titles. Control endpoints with --ng-from / --ng-to.

.surface-noise-gradient
/* Header breakout — set gradient vars, then break out to column edges */
.editorial__intro {
  --ng-from: var(--lime-50);   /* gradient start — use lime-100 for stronger */
  --ng-to:   var(--bg-primary);
  margin-inline: calc(-1 * var(--content-pad));
  padding-inline: var(--content-pad);
}

.surface-hatch-lime — gutters / side panels

Lime-tinted 45° diagonal lines at 18% opacity. Use in structural gutters (work entry side columns) and non-reading zones. Never behind text.

.surface-hatch-lime
/* Token */
--texture-hatch-lime:
  repeating-linear-gradient(
    -45deg,
    oklch(62% 0.08 118 / 0.18) 0 0.5px,
    transparent 0.5px 10px
  );

/* Usage */
.gutter-column { background-image: var(--texture-hatch-lime); }

.surface-lime — terminal zones (footer)

Full lime zone: --lime-50 base, fine 20px grid that fades in from the bottom (hidden at top, full at 82%), noise grain. Used for the footer across all pages. Add z-index: 101; position: relative to stack above the column-edge lines (z-index: 100).

.surface-lime — grid emerges toward bottom
/* Global utility — use the class directly */
<footer class="footer surface-lime"></footer>

/* The class (defined in global.css) */
.surface-lime {
  background-color: var(--lime-50);
  background-image:
    var(--noise-svg),
    linear-gradient(to bottom, var(--lime-50) 0%, transparent 82%),
    linear-gradient(var(--pattern-grid-line-lime) 1px, transparent 1px),
    linear-gradient(90deg, var(--pattern-grid-line-lime) 1px, transparent 1px);
  background-size: 200px 200px, 100% 100%, 20px 20px, 20px 20px;
  background-blend-mode: multiply, normal, normal, normal;
}

Pattern tokens

--noise-svg feTurbulence SVG data URI, 200×200px tile, 45% amplitude grain
--texture-hatch-lime Lime-tinted diagonal hatch (repeating-linear-gradient, -45°, 10px pitch)
--texture-lime-wash Flat 7%-opacity lime overlay — ambient lime cast on any surface
--pattern-dots Faint warm-gray dot grid — toolbar bands + related-section cells
--pattern-grid-line Neutral grid line color (rgb 176 172 170 / 0.10) — 80px structural grid
--pattern-grid-line-lime Lime grid line color (oklch 32% 0.09 118 / 0.12) — 20px fine grid

Usage rules

Noise grain runs everywhere via body — it's the ambient floor.
Lime-tinted patterns (hatch, fine grid) only in lime surface zones.
Neutral dot grid (--pattern-dots) for blueprint zones — toolbar bands, related cells.
Never place any pattern directly behind reading prose.
Don't use --text-faint on .surface-lime — use --text-muted minimum.
Don't mix lime and neutral pattern tokens in the same zone.

Borders & Surfaces

Card surfaces

bg-primary + border

bg-elevated + border

lime-50 + lime-200 border

lime-100 + lime-200 border

Structural rules

Full-bleed horizontal rules use .rule-full (bleeds to viewport edges) with variants .rule-dashed, .rule-dotted. .rule-marked adds a + crosshair where the rule crosses the column-edge lines.

rule-full (solid)
rule-dashed
rule-dotted
lime-400 dotted (footer/lime zones)

Buttons & Links

Link styles

Work entry (hover to preview)

Stage tags

Garden notes carry a growth stage. Three stages map to design tokens: --stage-seedling (amber), --stage-budding (sage), --stage-evergreen (deep forest). The colored dot is a ::before pseudo on any element with a data-stage attribute.

Default — post headers

Seedling Budding Evergreen

Small — card metadata

Seedling Budding Evergreen

Motion

Page transitions

Blur + opacity only — no translate. Powered by Astro's ClientRouter (View Transitions API). Out at 0.18s ease, in at 0.42s with spring easing. Direction (forward/back) is stored in sessionStorage and applied to html[data-transition-dir] before the swap so both outgoing and incoming frames animate correctly.

/* Out */
animation: pt-out 0.18s cubic-bezier(0.4, 0, 0.2, 1) forwards;
@keyframes pt-out { to { opacity: 0; filter: blur(8px); } }

/* In */
animation: pt-in 0.42s cubic-bezier(0.16, 1, 0.3, 1) forwards;
@keyframes pt-in {
  from { opacity: 0; filter: blur(10px); }
  60%  { opacity: 1; filter: blur(2px);  }
  to   { opacity: 1; filter: blur(0);    }
}

Entry animations

.animate-in 0s delay
.animate-in-delay-1 60ms
.animate-in-delay-2 120ms
.animate-in-delay-3 180ms
.animate-in-delay-4 240ms

Grain texture

Static feTurbulence SVG at 200×200px, tiled across the body via background-image with background-blend-mode: multiply. A flat lime overlay (--texture-lime-wash) sits beneath the noise in the same background stack, casting a faint green warmth across the grain. No JavaScript, no animation — pure CSS texture.