Skip to content

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 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.section in tokens.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’s padding-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.css and figma.tokens.json are 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.

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):

  1. Install the Tokens Studio plugin in the Figma file.
  2. Create a GitHub fine-grained PAT with read-only access to this repo (Contents: Read) — pull-only sync needs nothing more.
  3. In the plugin: Settings → Sync providers → Add → GitHub, then set Personal Access Token to your PAT, Repository quarry-design-group/quarry.team, Branch main, File path packages/ui/tokens/figma.tokens.json.
  4. Pull — the core set 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).

  • 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’s xs floor.

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 live as .astro components (in apps/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.
  • CtaBand is 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.
  • Prose is 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.
  • Select is 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. Select hides 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. size matches the form’s text inputs (md for the contact and grievance forms, lg for search); fieldClass carries the form’s skin. src/lib/form-primitives.test.ts fails CI on a bare <select> anywhere else in the site source, and tests/e2e/select.spec.ts measures 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).
  • 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 with list-none p-0 and carries role="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.json are the same contract — they should never disagree.