Grove

Where living systems take root

by Edgar Diaz
0.19.0-alpha.4

Brand Identity

Name

Grove — A design system rooted in craft.

The name evokes the space between wild forest and manicured garden: structured freedom, designed organicity, cultivated wildness. Grove is where living systems take root.

Voice

Calm confidence. Clear, unhurried prose. The quiet authority of someone who has done the work.

  • Warm but not casual
  • Approachable but not folksy
  • Helpful but not hovering
  • Patient growth over rapid scaling
  • Depth over breadth

Write like helping a colleague, not instructing a stranger. Use "you" freely. Short sentences. Lead with what matters. Include the why.

Typography

Display: Cakra — Experimental display typeface with unique personality, contemporary vibe, bold cuts, geometric tension.

Body: Switzer — Clean grotesque with understated character, professional without sterile, warm without soft.

Icons: Phosphor — Available in Regular and Fill variants.

Primary Colors

RoleNameHexDescription
BrandGrove Grass#416943Earthy, mossy green. Maturity, groundedness, organic sophistication.
AccentGrove Prune#7F3999Rich purple. Used sparingly for high-priority actions and links.
GroundParchment#FAF8F2Warm off-white. The surface everything sits on.
Dark BaseObsidian#0B0B0BNear-black. Primary text on light surfaces.

What Grove Is Not

  • Not precious or twee. No leaf illustrations, acorns, eco clichés. Borrows from nature conceptually, not literally.
  • Not cold or corporate. Despite being a system, it has warmth.
  • Not maximalist. Restraint is a core value. White space is clarity, not emptiness.
  • Not trendy. Aims for longevity over novelty.
  • Not apologetic. Makes decisions and stands by them.
  • Not exclusive. Exists to help people build.

Design Principles

Living and Intentional

Grove feels organic but not decorative, structured but not rigid. Every element breathes, but nothing is arbitrary. The system grows with purpose—each addition earns its place.

Quiet Confidence

Grove doesn't shout. It communicates through restraint, precision, and considered choices. Visual hierarchy emerges from thoughtful contrast, not competing for attention. When something stands out, it matters.

Rooted Flexibility

Like a tree that bends without breaking, Grove provides strong foundations that adapt to context. The system has opinions but not dogma. It guides without constraining, offering clear paths while allowing for intentional deviation.

Honest Craft

Every token, every value, every relationship exists because it was tested and refined. Grove favors substance over style, durability over trends. The work shows care without showing off.


Color System

Design Intent

Grove's color system is built in OKLCH — a perceptually uniform color space where equal numeric steps produce equal perceived lightness differences. This means the brand/300 swatch looks exactly as "halfway between light and mid" as brand/600 does, regardless of the hue. It also allows mixing and transforming colors without producing muddy intermediates.

There are six color families, each with a distinct role in the design language:

FamilyRoleDominance
GrayUI chrome, neutral containers, body text backgrounds~60% of all surfaces
Brand (Green)Identity moments, marketing, primary CTAs~25%
Accent (Purple)Secondary interactive, creative elements~10%
Danger (Red)Error states, destructive actions~5%
Success (Aqua)Confirmation, completed states~5%
Information (Blue)Informational banners, helper text~5%

Gray is the workhorse. Brand is used intentionally and sparingly to preserve its emotional weight. Accent is a complement to brand — use it for secondary interactive elements where brand would create too much visual competition. Danger, Success, and Information are reserved exclusively for their semantic meaning; never use them decoratively.

When to Use Primitives vs Semantic Tokens

Primitives are the raw numbered values (--color-brand-500, --color-gray-200). They carry no meaning beyond their hue and lightness.

Semantic tokens are named by role (--semantic-color-surface-brand-terrace, --semantic-color-text-on-gray-ground-base). They encode the design decision.

Use caseToken typeExample
SVG illustrations, isotypes, iconsPrimitive --color-brand-500
Component backgroundsSemantic --semantic-color-surface-brand-terrace
Text on surfacesSemantic --semantic-color-text-on-brand-terrace-base
Borders and dividersSemantic --semantic-color-border-on-ground
ShadowsSemantic--drop-shadow-brand-summit

Rule: If you find yourself picking a primitive for a UI element, stop and find the semantic token. Primitives are not responsive to dark mode; semantic tokens are.

Cross-references

  • → Elevation — defines which semantic surface colors exist and at what depth
  • → Text-on — defines which text colors pair with each surface token

Primitive Colors

Primitive colors are the raw palette. All semantic colors derive from these primitives. Primitives should only be used directly for SVG illustrations—use semantic tokens for all other applications.

Base

TokenHexName
base/light#FAF8F2Parchment
base/dark#0B0B0BObsidian

Brand (Green)

TokenHexName
brand/50#DAEFDAHoneydew
brand/100#C2E2C2Celadon
brand/200#9AC59ASage
brand/300#7BA57CFern
brand/400#5E865FLaurel
brand/500#416943Grove Grass
brand/600#345B35Forest
brand/700#264D28Pine
brand/800#193F1BJuniper
brand/900#0A320FSpruce
brand/950#002503Evergreen

Accent (Purple)

TokenHexName
accent/50#FED8FFThistle
accent/100#F7BFFFLilac
accent/200#DF95FCWisteria
accent/300#BE76DAOrchid
accent/400#9E57B9Heather
accent/500#7F3999Grove Prune
accent/600#702989Plum
accent/700#62187ADamson
accent/800#53026AAubergine
accent/900#45005BNightshade
accent/950#330046Blackberry

Gray (Rock)

TokenHexName
gray/50#EAE7E4Chalk
gray/100#DBD7D2Limestone
gray/200#BCB6B1Pebble
gray/300#9C9792Flint
gray/400#7E7974Slate
gray/500#615D58Granite
gray/600#534F4AShale
gray/700#46423DBasalt
gray/800#393530Coal
gray/900#2C2824Onyx
gray/950#201C18Site

Danger (Red)

TokenHexName
danger/50#FFDAD7Blush
danger/100#FFC1BERose
danger/200#FF8D8BCoral
danger/300#E66E6DPoppy
danger/400#C34F51Vermilion
danger/500#9E2B32Rust
danger/600#901D27Crimson
danger/700#80041ACarmine
danger/800#6F000CBurgundy
danger/900#590006Maroon
danger/950#440002Oxblood

Success (Aqua Green)

TokenHexName
success/50#C2F5E0Seafoam
success/100#A3E9CDSpearmint
success/200#72CCABOpal
success/300#51AC8CCove
success/400#2E8D6FSerpentine
success/500#006F53Myrtle
success/600#006145Mangrove
success/700#005238Kelp
success/800#00432CReef
success/900#003421Grotto
success/950#002616Seabed

Information (Blue)

TokenHexName
information/50#C3EFFFMist
information/100#A6E0FFSky
information/200#77C1F0Azure
information/300#58A1CFCerulean
information/400#3882AECobalt
information/500#12648FLapis
information/600#005680Sapphire
information/700#004871Navy
information/800#003A62Indigo
information/900#002D4FMidnight
information/950#00203CInk

Elevation

Design Intent

Free color picking leads to arbitrary compositions — a green card inside an orange section inside a purple page, with no systemic logic. Grove solves this with a track + depth model: you choose a color family (track) and a depth level, and the system provides exactly one valid surface color for that combination. This eliminates guesswork and ensures every surface composition is deliberate.

The depth axis (Ground → Terrace → Path → Summit) maps to perceived visual weight: lighter is flatter, darker is more prominent. The progression is always forward — a nested element must be darker than its parent within the same track, or start a new track from a lower depth.

Aurora

Aurora is not a container depth. It is an interactive state — the hover/active variant of Summit. Never place other elements inside an Aurora surface. Only Summit-level interactive elements (buttons, chips, links) use Aurora. Apply it via :hover or :active CSS states only.

.button-primary {
	background-color: var(--semantic-color-surface-brand-summit);
}
.button-primary:hover {
	background-color: var(--semantic-color-surface-brand-aurora);
}

UI Color Distribution — Page Anatomy

The 60/25/10/5 guideline describes the visual proportion of color in a typical page:

┌─────────────────────────────────────────────────────────┐
│  GROUND (60%)  — page background, most of the viewport  │
│  ┌───────────────────────────────────────────────────┐  │
│  │  TERRACE (25%) — cards, sections, sidebars        │  │
│  │  ┌──────────────────────────────────────────┐     │  │
│  │  │  PATH / SUMMIT (10%) — nested elements,  │     │  │
│  │  │  buttons, highlighted rows               │     │  │
│  │  └──────────────────────────────────────────┘     │  │
│  └───────────────────────────────────────────────────┘  │
│  AURORA (5%) — hover/active states only                 │
└─────────────────────────────────────────────────────────┘

A page that uses Summit for 60% of its surface area will feel visually heavy and fatiguing. Reserve saturated, dark surfaces for elements that need immediate attention.

Cross-references

  • → Text-on — once you've chosen a surface, find its paired text tokens
  • → Shadows — when to add shadows to Terrace and Summit surfaces
  • → Borders & Dividers — border and divider tokens per surface

Overview

Elevation in Grove uses tracks—color lanes that define which surfaces are available at each depth level. You pick a track, then follow its depth progression.

Tracks

There are six tracks:

  • Brand — Grove Grass. Primary brand expression.
  • Accent — Grove Prune. High-priority actions, links.
  • Gray — Neutral surfaces. The default for most UI.
  • Danger — Error states, destructive actions.
  • Success — Confirmation, positive feedback.
  • Information — Notices, helpful context.

Depths

DepthToken ValueRole
Groundbase/lightThe base surface. Where everything begins.
Terrace100Light surface. Containers, cards, sections.
Path200Mid surface. Elements inside containers. Brand and Gray only.
Summit500Dark surface. High-priority interactive elements.
Aurora700Hover state for Summit. Not a container.

Track Definitions (Light Mode)

Brand Track

DepthTokenHexName
Terracesurface/brand/terrace#C2E2C2Celadon
Pathsurface/brand/path#9AC59ASage
Summitsurface/brand/summit#416943Grove Grass
Aurorasurface/brand/aurora#264D28Pine

Accent Track

DepthTokenHexName
Terracesurface/accent/terrace#F7BFFFLilac
Summitsurface/accent/summit#7F3999Grove Prune
Aurorasurface/accent/aurora#62187ADamson

Accent has no Path depth.

Gray Track

DepthTokenHexName
Terracesurface/gray/terrace#DBD7D2Limestone
Pathsurface/gray/path#BCB6B1Pebble
Summitsurface/gray/summit#615D58Granite
Aurorasurface/gray/aurora#46423DBasalt

Danger Track

DepthTokenHexName
Terracesurface/danger/terrace#FFC1BERose
Summitsurface/danger/summit#9E2B32Rust
Aurorasurface/danger/aurora#80041ACarmine

Danger has no Path depth.

Success Track

DepthTokenHexName
Terracesurface/success/terrace#A3E9CDSpearmint
Summitsurface/success/summit#006F53Myrtle
Aurorasurface/success/aurora#005238Kelp

Success has no Path depth.

Information Track

DepthTokenHexName
Terracesurface/information/terrace#A6E0FFSky
Summitsurface/information/summit#12648FLapis
Aurorasurface/information/aurora#004871Navy

Information has no Path depth.

Depth Availability

DepthBrandAccentGrayDangerSuccessInformation
Ground
Terrace
Path
Summit
Aurora

Composition Rules

1. Ground is the base.

Every layout starts on Ground (surface/ground). All tracks can be placed on Ground.

2. Within a track, depths progress forward.

Move from lighter to darker: Terrace → Path → Summit. You can skip depths but never go backward within the same track.

Correct:

brand/terrace → brand/path → brand/summit
brand/terrace → brand/summit (skipping path)

Wrong:

brand/path → brand/terrace (going backward)
brand/terrace → brand/terrace (restarting)

3. Starting a new track requires a depth change.

When nesting a new track inside a parent, the new track cannot start at the same depth. This ensures visible contrast between surfaces.

Preferably, go one depth deeper. Going further is allowed but not recommended.

From Terrace: Start new track at Path (preferred) or Summit.

From Path: Start new track at Summit (preferred) or return to Ground.

From Summit: Return to Ground.

Examples:

gray/terrace
  └── brand/path ✓ (one depth over, preferred)

gray/terrace └── brand/summit ✓ (allowed, not preferred)

gray/terrace └── brand/terrace ✗ (same depth, no contrast)

brand/summit └── gray/ground ✓ (return to ground) ```

4. Gray is universal.

Gray can appear inside any track at any depth. It's the neutral foundation.

5. Accent can appear inside Gray.

Accent elements (like buttons) can be placed within gray surfaces for emphasis.

6. Brand and semantic tracks don't mix.

Brand and Accent tracks should not contain Danger, Success, or Information tracks inside them. Semantic colors communicate specific states and shouldn't be nested within brand expression.

7. Aurora is a state, not a container.

Aurora is the hover state for Summit elements. It never contains other elements. Only Summit changes surface color on hover.

8. Floating elements return to Ground.

Modals, popovers, and tooltips reset context. They start fresh from Ground.

UI Color Distribution

A guideline for visual balance:

  • 60% — Ground
  • 25% — Terrace
  • 10% — Path / Summit
  • 5% — Aurora (interactive states only)

Text-on

Every surface has paired text colors that ensure readable contrast.

Text Roles

RolePurpose
EmphasisHighest hierarchy. Headings, key content.
BaseDefault body text.
SubtleDe-emphasized. Captions, hints, timestamps.
Unvisited-linkLink, not yet clicked.
Visited-linkLink, already clicked.

Role Availability by Depth

RoleGroundTerracePathSummitAurora
Emphasis
Base
Subtle
Unvisited-link
Visited-link

Summit and Aurora are terminal elements. They need base and subtle for labels, but not emphasis or links.

Token Structure

text-on/ground/{role}
text-on/{track}/{depth}/{role}

Examples:

  • text-on/ground/base — Body text on ground
  • text-on/brand/terrace/emphasis — Heading on brand terrace
  • text-on/gray/summit/base — Label on gray summit

Borders & Dividers

Border-around

Used for component edges: input fields, cards, containers.

border-around/ground
border-around/{track}/{depth}

Divider-on

Used for separating content within a surface: list items, table rows.

divider-on/ground
divider-on/{track}/{depth}

Both provide a single value per surface—no role hierarchy.


Typography

Design Intent

Grove's type system is built around two contrasting typefaces that never compete with each other: Cakra for expressive moments, Switzer for everything readable. The distinction is simple — if it serves communication, it's Switzer. If it expresses character, it's Cakra.

Font Pairing Rules

FamilyWhen to useWhen NOT to use
Switzer (sans)Body copy, UI labels, navigation, form fields, captionsFull-page hero text, logotypes
Cakra (display)Hero headings, section titles in marketing contexts, the hero and display type stylesBody paragraphs, form labels, button text

Rule: Never use both Cakra and Switzer on adjacent lines within the same text block. The transition between expressive and functional is always at the component boundary, not mid-paragraph.

Level Selection Guide

Use the composite typography tokens (via CSS classes) rather than assembling font-size + weight + line-height individually.

UI roleRecommended classFamily
Page hero / product name.hero.singlelineCakra
Tagline / campaign headline.display.singlelineCakra
Page title, section heading.title.singlelineSwitzer
Card heading.heading.singlelineSwitzer
Sub-section header.subheading.singlelineSwitzer
Body copy.base.multilineSwitzer
Secondary / supportive text.subtle.multilineSwitzer
Blockquote, callout.quote.multilineSwitzer
Form label, tag, chip.label.singlelineSwitzer
Image caption, timestamp.caption.singlelineSwitzer
Legal text, footnote.footnote.singlelineSwitzer

Single-line vs Multi-line

The .singleline and .multiline suffixes control line-height:

  • .singleline — tight leading (1.0–1.1×). Use for headings, labels, buttons — anything that fits on one line and doesn't need breathing room between lines.
  • .multiline — looser leading (1.2–1.6×). Use for body copy, descriptions, anything that wraps across two or more lines.

Rule: Apply .singleline to interactive and heading elements. Apply .multiline to any text block that might exceed one line.

Emphasis

For Switzer levels (title through footnote), add .emphasis to increase font-weight to semibold. Use sparingly — only to signal hierarchy within a block, never decoratively.

<span class="label singleline emphasis">Required</span>

hero and display (Cakra) have no emphasis variant. Cakra's single weight is already expressive enough.

Icon Fonts

Phosphor comes in two variants: Regular (outline strokes) and Fill (solid fills).

VariantWhen to use
RegularDecorative, informational, neutral state icons
FillActive state, selected, toggled-on state

Never use Fill for inactive states — the solid weight implies action or selection.

Cross-references

  • → Text-on — color tokens that pair with surfaces for readable contrast
  • → Spacing & Grid — gap values for spacing between text blocks

Font Families

TokenValueUsage
font-family/sans-serifSwitzerBody text, UI elements
font-family/serifCakraDisplay, headings, marketing
font-family/icons-regularPhosphorIcons (outline)
font-family/icons-fillPhosphor-FillIcons (solid)

Font Weights

StyleTokenValue
Normalfont-weight/normal/extra-lightExtralight
Normalfont-weight/normal/regularRegular
Normalfont-weight/normal/semi-boldSemibold
Italicfont-weight/italic/extra-lightExtralight Italic
Italicfont-weight/italic/regularItalic
Italicfont-weight/italic/semi-boldSemibold Italic

Font Size Scale (Digital)

TokenSizeUsage
font-size/2xs10pxFine print
font-size/xs12pxCaptions, labels
font-size/sm14pxSecondary text
font-size/base16pxBody text
font-size/md20pxLarge body, small headings
font-size/lg24pxHeadings
font-size/xl32pxSection headings
font-size/2xl40pxPage headings
font-size/3xl80pxHero text
font-size/4xl240pxDisplay

Font Size Scale (Print)

TokenSize
font-size/2xs6pt
font-size/xs6pt
font-size/sm8pt
font-size/base8pt
font-size/md12pt
font-size/lg16pt
font-size/xl24pt
font-size/2xl32pt
font-size/3xl64pt
font-size/4xl192pt

Line Height

Two modes: single-line (labels, buttons) and multi-line (paragraphs).

Single-line (Digital)

TokenValue
line-height/single-line/2xs12px
line-height/single-line/xs16px
line-height/single-line/sm16px
line-height/single-line/base20px
line-height/single-line/md24px
line-height/single-line/lg28px
line-height/single-line/xl36px
line-height/single-line/2xl44px
line-height/single-line/3xl88px
line-height/single-line/4xl264px

Multi-line (Digital)

TokenValue
line-height/multi-line/2xs16px
line-height/multi-line/xs20px
line-height/multi-line/sm20px
line-height/multi-line/base24px
line-height/multi-line/md28px
line-height/multi-line/lg32px
line-height/multi-line/xl40px
line-height/multi-line/2xl48px
line-height/multi-line/3xl96px
line-height/multi-line/4xl304px

Letter Spacing

TokenValueUsage
letter-spacing/tight-2pxDisplay text, Cakra headings
letter-spacing/normal0pxDefault
letter-spacing/loose2pxAll caps labels
letter-spacing/extra-loose4pxSpaced headings

Spacing & Grid

Design Intent

The soft grid is a spacing scale, not a CSS grid. It provides a set of predefined values (1px increments at small sizes, 4px at larger) so spacing decisions are always consistent and intentional — no arbitrary 17px or 22px values.

The number in each token name is the value in pixels at the default 16px root font size. In code, all values are expressed in rem so they respect user font-size preferences.

Semantic Groupings

Not all spacing values are equal — they serve different layers of the UI:

RangeValuesTypical use
Micro0–8pxInternal component spacing — icon-to-label gap, input padding, badge insets
Component12–24pxComponent padding, gap between related elements in a group
Layout32–64pxGap between sections, card margins, hero padding
Section72–96pxPage-level vertical rhythm, spacious section breaks

Rule: If you're spacing elements within a component, stay in 0–24px. If you're spacing between components or sections, use 32px+.

System vs Landing Grid

Two grid presets exist for different contexts:

Grid typeUse caseMargin at laptop
SystemProduct UI, app shells, dashboards32px
LandingMarketing pages, documentation, hero sections64px

Landing grids use wider margins to give content more breathing room and center the reading line at large viewports.

Breakpoints

NameMin-width
Mobile0px
Tablet768px
Laptop1280px
Desktop1560px

Cross-references

  • → Elevation — padding values used within each surface depth

Soft Grid

Spacing values for margins, padding, and gaps.

TokenValue
00px
11px
22px
44px
66px
88px
1010px
1212px
1414px
1616px
1818px
2020px
2424px
2828px
3232px
3636px
4040px
4444px
4848px
5252px
5656px
6060px
6464px
7272px
8080px
8888px
9696px

Layout Grid

Two grid types: system (applications) and landing (marketing pages).

Base / Mobile (< 768px)

PropertySystemLanding
Columns44
Margin16px16px
Gutter16px16px

Tablet (≥ 768px)

PropertySystemLanding
Columns88
Margin24px32px
Gutter16px24px

Laptop (≥ 1280px)

PropertySystemLanding
Columns1212
Margin32px64px
Gutter20px32px

Desktop (≥ 1560px)

PropertySystemLanding
Columns1212
Margin32px96px
Gutter24px48px

Border Width & Radius

Border Width

TokenValueUsage
border-width/none0pxNo border
border-width/hairline0.5pxSubtle dividers
border-width/base1pxDefault borders
border-width/heavy2pxEmphasized borders
border-width/thick4pxStrong visual weight

Border Radius

TokenValueUsage
border-radius/none0pxSharp corners
border-radius/sm4pxSmall elements, tags
border-radius/base8pxDefault
border-radius/md12pxCards
border-radius/lg16pxLarge cards
border-radius/xl20pxModals
border-radius/2xl24pxLarge containers
border-radius/3xl28pxHero elements
border-radius/4xl32pxFull rounded
border-radius/6xl40pxPills
border-radius/8xl48pxLarge pills
border-radius/10xl56pxCapsules
border-radius/12xl64pxFull capsules

Shadows

Shadows come in three depths, each using two layers for a softer, more natural appearance. Shadows use the track's own color family for cohesive integration.

Design Intent

Shadows serve one purpose: reinforcing depth that surface contrast alone doesn't fully communicate. If two surfaces already have clear contrast (e.g. a dark Summit button on a light Ground), don't add a shadow — it creates visual noise without adding hierarchy information.

Only use shadows on Terrace and Summit surfaces. Ground-level elements don't receive shadows because they have nothing to be elevated above.

When to Use Each Depth

DepthCSS classVisual weightUse for
Summitdrop-shadow-{track}-summitTight, balancedCards, panels, buttons, form inputs
Terracedrop-shadow-{track}-terraceWide, airyModals, sheets, floating containers, popovers

Available tracks: brand, accent, gray, information, danger, success

Rules

  • Don't combine shadows with heavy borders on the same element — choose one signal of elevation, not both.
  • Match the shadow track to the surface track — a brand Summit button uses drop-shadow-brand-*, not drop-shadow-gray-*.
  • Don't shadow Ground elements — a flat page background doesn't need a shadow.

Usage (CSS class)

<!-- Card on a surface -->
<div class="drop-shadow-gray-summit">...</div>

<!-- Modal --> <div class="drop-shadow-gray-terrace">...</div>

<!-- Brand button --> <button class="drop-shadow-brand-summit">...</button> ```

Cross-references

  • → Elevation — which depths are valid containers for shadows
  • → Borders & Dividers — don't use thick borders with shadows on the same element

Shadow structure (Brand, light mode)

DepthLayerOffset X/YBlurSpreadOpacity
Summit14px / 4px16px2px4%
Summit21px / 1px4px1px12%
Terrace116px / 16px32px4px4%
Terrace24px / 4px16px2px8%

All other tracks follow the same structure with their own hue.


Token Reference

Collection Overview

CollectionModesDescription
colorValuePrimitive color palette
semantic-colorLight, Dark\*Surface, text-on, border-around, divider-on
typographyDigital, PrintFont size, line height, letter spacing
font-familyTypeface definitions
font-weightValueWeight names
soft-gridSpacing scale
gridBase, Tablet, Laptop, DesktopLayout grid
border-radiusCorner radius scale
border-widthStroke width scale
shadowShadow definitions

\*Dark mode values are placeholders. Structure is ready for integration.

Naming Convention

{collection}/{category}/{variant}/{property}

Examples:

  • color/brand/500/value → Primitive green
  • surface/brand/terrace → Semantic surface
  • text-on/brand/terrace/base → Text on surface
  • typography/font-size/base → 16px
  • shadow/brand/terrace/layer-1/blur → Shadow property

File Structure

{collection}_{mode}.tokens.json

Examples:

  • color_tokens.json
  • semantic-color_light_tokens.json
  • semantic-color_dark_tokens.json
  • typography_digital_tokens.json
  • grid_tablet_tokens.json

Composition Examples

Example 1: Card on Ground

Ground (surface/ground)
  └── gray/terrace (card)
        ├── text-on/gray/terrace/emphasis (heading)
        ├── text-on/gray/terrace/base (body)
        ├── text-on/gray/terrace/subtle (timestamp)
        └── accent/summit (button)
              └── text-on/accent/summit/base (label)

Example 2: Brand Section

Ground (surface/ground)
  └── brand/terrace (hero section)
        ├── text-on/brand/terrace/emphasis (headline)
        ├── text-on/brand/terrace/base (description)
        └── brand/summit (primary action)
              └── text-on/brand/summit/base (label)

Example 3: Nested Depth Progression

Ground (surface/ground)
  └── brand/terrace (card)
        └── brand/path (highlighted section)
              ├── text-on/brand/path/base (content)
              ├── text-on/brand/path/unvisited-link (link)
              └── brand/summit (action)
                    └── text-on/brand/summit/base (label)

Example 4: Starting New Track (Correct Depth Change)

Ground (surface/ground)
  └── gray/terrace (card)
        └── brand/path (nested brand element, one depth over)
              └── brand/summit (action)

Example 5: Danger Banner

Ground (surface/ground)
  └── danger/terrace (error banner)
        ├── text-on/danger/terrace/base (message)
        └── danger/summit (dismiss)
              └── text-on/danger/summit/base (label)

Example 6: Modal (Context Reset)

[Page: brand/terrace → brand/path]
  └── [Modal opens — returns to Ground]
        └── Ground (surface/ground)
              └── gray/terrace (modal body)
                    ├── text-on/gray/terrace/emphasis (title)
                    ├── text-on/gray/terrace/base (content)
                    └── accent/summit (confirm)

Example 7: Gray with Accent Button

Ground (surface/ground)
  └── gray/terrace (card)
        ├── text-on/gray/terrace/base (content)
        └── accent/summit (CTA button)
              └── text-on/accent/summit/base (label)

Appendix: Dark Mode

Dark mode token values are currently placeholders.

The structure is identical to light mode. When dark mode values are finalized:

  1. Update semantic-color_dark_tokens.json with correct mappings
  2. Surface depths may map to different primitive values
  3. Text-on values will adjust for light text on dark surfaces
  4. Composition rules remain unchanged

Grove Design System — Where living systems take root.