Guide: Design system ("Quarried")
“Quarried” is Quarry’s design system — warm-serious editorial. This guide covers how to use it: tokens, type, color, and components. The values are owned by design tokens (ADR 0003) and consumed through Tailwind v4 (ADR 0007).
The token contract
Section titled “The token contract”The single source of truth is packages/ui/tokens/tokens.json. A build step (pnpm tokens, packages/ui/src/build-tokens.ts) generates two projections from it — tokens.css (CSS custom properties, the code side) and figma.tokens.json (a Tokens Studio file the design side pulls, below) — so design and code resolve to identical values.
- Primitives = raw scales (color ramps, type sizes, spacing steps).
- Semantic tokens = intent-named tokens that reference primitives (
color-surface,color-text,color-accent,space-*,radius-*). - Section rhythm =
--space-section(space.sectionintokens.json), the single vertical padding for full-width page bands (.section,ToolsSection, the 404). Adjacent sections stack to exactly 2× this value — never hand-roll a section’spadding-block. - Header height =
--header-height(size.header-height), the sticky header’s height; the header bar, the heroes pulled up beneath it, sticky rails, and the mobile menu’s max height all offset by it. - Application code uses semantic tokens, never raw hex/px.
tokens.cssandfigma.tokens.jsonare generated — never hand-edit them. CI fails if either is stale.
To change a value: edit tokens.json → pnpm tokens → commit the regenerated files. The Figma side follows from the same source — see below.
Syncing tokens to Figma (Tokens Studio)
Section titled “Syncing tokens to Figma (Tokens Studio)”Figma consumes the tokens; it is not a second source of truth. pnpm tokens emits packages/ui/tokens/figma.tokens.json — the same tokens in the Tokens Studio single-file format (one core set) — and CI fails if it drifts from tokens.json. The Tokens Studio Figma plugin pulls that file from Git and applies it as Figma Variables. This works on a Figma Pro seat — no Enterprise Variables API.
One-time setup (per file):
- Install the Tokens Studio plugin in the Figma file.
- Create a GitHub fine-grained PAT with read-only access to this repo (Contents: Read) — pull-only sync needs nothing more.
- In the plugin: Settings → Sync providers → Add → GitHub, then set Personal Access Token to your PAT, Repository
quarry-design-group/quarry.team, Branchmain, File pathpackages/ui/tokens/figma.tokens.json. - Pull — the
coreset loads. Then Styles & Variables → Export to Figma → Variables creates/updates the Variable collection from the tokens.
On every token change thereafter: values change in tokens.json, CI regenerates figma.tokens.json, and a designer clicks Pull → Export to Figma to refresh the Variables — never hand-editing variables in Figma.
What maps, and what doesn’t. Colors, spacing, radii, and sizes become first-class Figma Variables. space.section (a clamp()), the font stacks, and the easing curves have no native Figma variable type, so they import as string variables or are skipped — they live on the code side only. Light/dark is a CSS semantic-alias concern, not primitive Variables, so a single-mode collection is correct (multi-mode would need Tokens Studio Pro).
Typography
Section titled “Typography”- Display: Fraunces — for headings and expressive editorial moments. Carries the “serious editorial” tone.
- Text: Hanken Grotesk — body and UI copy; clean, readable. Upright and italic faces both ship, so emphasis renders as true italics under the global
font-synthesis: none. - Labels / mono: JetBrains Mono — labels, metadata, code, and small technical accents. The discipline tags set their uppercase labels in
text-2xs, a fixed 0.7rem below the fluid scale’sxsfloor.
Use the type scale from the tokens; respect heading hierarchy (a11y depends on correct heading order). Long-form bodies (posts, cases, roles, and policies, through Prose) step one token per heading level above their text-lg body copy: title 4xl, h2 3xl, h3 2xl, h4 xl. Load fonts without layout shift (NFR: CLS ≤ 0.1).
- Quarry Blue
#0C53C7— the primary brand color. - Stone — the neutral ramp (surfaces, text, borders) that gives the system its warm-serious base.
- Ember — the accent, used sparingly for emphasis/CTA.
- Discipline (categorical) — one hue for each of the five disciplines (strategy, design, engineering, ecommerce, data), each with a
-tint(pale chip background) and-ink(AA-darkened text on that tint) pair, used by the discipline tags.
Always reference colors via semantic tokens (color-surface, color-text, color-accent, …), not raw hex. All foreground/background pairings must meet WCAG 2.2 AA contrast — verify when introducing a new combination.
Components
Section titled “Components”- Components live as
.astrocomponents (inapps/web), structured markup styled with Tailwind utilities that resolve to tokens. - Reuse existing components before creating new ones; new components should compose tokens, not introduce new raw values.
CtaBandis the closing call-to-action band (blue panel, display title, optional sub, primary CTA); marketing pages (home, services, team, AI services, compliance, how we use AI) end with it, and index and utility pages end with their content.Proseis the reading column for rendered MDX bodies (posts, cases, roles, policies). It owns the heading, paragraph, image, link, photo-credit, and pullquote rules, so every long-form template sets the same typography; a pullquote’s closing paragraph takes the attribution style only when the quote runs to more than one paragraph.Selectis the only way to render a dropdown. A native<select>draws the platform’s arrow, which ignores the field’s padding (Chrome sets it against the border) and takes the platform’s color and weight, and it ignores line-height, so it renders shorter than the inputs beside it.Selecthides the platform arrow, draws a chevron in the text color inside a reserved right padding, and sets a minimum height of one line plus the field’s padding and border.sizematches the form’s text inputs (mdfor the contact and grievance forms,lgfor search);fieldClasscarries the form’s skin.src/lib/form-primitives.test.tsfails CI on a bare<select>anywhere else in the site source, andtests/e2e/select.spec.tsmeasures every rendered dropdown at phone and desktop widths: arrow hidden, chevron clear of the border and the text, height equal to the neighbouring input.- A constrained subset is available inside MDX for editorial content:
<Motion>(an animated clip with its poster, in posts) and<Email>(an encoded address, in policies) — see the content authoring guide. - Respect
prefers-reduced-motion; keep interactivity to genuine islands (ADR 0002).
Rules of thumb
Section titled “Rules of thumb”- Tokens are the vocabulary; Tailwind is the grammar. Express layout/state with utilities; pull every constant from tokens.
- No raw hex or magic spacing in components or MDX — if a value is missing, add it to
tokens.json. - Don’t fork the palette in a Tailwind config — Tailwind reads the tokens.
- Accessibility is part of the design, not a later pass: contrast, focus states, semantics, reduced motion.
- Lists keep their markers by default. The base layer restores what Tailwind’s preflight strips, so a
<ul>or<ol>in a page, a component, or rendered markdown shows bullets or numbers with no extra classes. A layout list (nav, cards, a logo track) opts out explicitly withlist-none p-0and carriesrole="list", which keeps its list semantics in Safari once the markers are gone. Never rely on the reset to hide markers. - When in doubt, the Figma file and
tokens.jsonare the same contract — they should never disagree.