FairGarden Design

Color contract

Every component takes a primary and a secondary Radix scale, and colors its parts only through the --primaryN, --secondaryN and --role-* variables those scales publish.

Two props on every component

  • primary takes a scale from the primary roster: the neutrals olive, sage, slate, sand, gray and mauve, plus brown, bronze, gold, red, ruby, crimson, tomato, pink, plum, indigo, iris, violet and purple. The greens, yellows, oranges, blue, sky and cyan are secondary only.
  • secondary takes any of the 31 standard Radix scales. Alpha and custom scales are type errors.

Neither prop has a default. An omitted prop adds no class, so the value resolves in order:

  1. the prop;
  2. the nearest Ground scope's defaults, inherited as custom properties;
  3. the system defaults: primary olive, secondary green, action amber.

Primary drives almost everything: text, muted text, rules, hairlines, control edges, the focus ring, faces and soft fills. Secondary drives accents only: section heads on light grounds, link underlines and meaningful icons, selection, the action fill, and static category fills such as status.

Scale variables

A component never names a Radix scale, and never a mode. It reads the scope's steps, which keep the same names in light and dark mode:

VariableHolds
--primary1--primary12The primary scale's 12 steps
--secondary1--secondary12The secondary scale's 12 steps
--action1--action12The scope's action scale, published by Ground; the solid Button reads it as its secondary
--primary-contrast, --secondary-contrast, --action-contrastThe ink for a label on step 9 or 10
--primary-hover, --secondary-hover, --action-hoverThe step a contained fill moves to on hover: step 9's lighter neighbour in a light scope (step 8 for most scales, --amber6, step 5 for yellow, lime, mint and sky), step 10 for purple, indigo, iris, violet and plum, and step 10 in every dark scope

Role variables

Roles name a job, not a step, and resolve per ground and mode.

RoleUsed for
--role-headingSection heads only
--role-mutedSecondary text, at 4.5:1 or better
--role-ruleAny boundary a user must identify: field, table and card borders
--role-hairlineRules where whitespace and type also carry structure
--role-tintDecorative pattern color, never meaning
--role-accentLink underlines, meaningful icons, trails
--role-select, -mark, -edgeChecked and selected states of value controls
--role-select-text, -label, -edge, -hoverSelected states that carry words, such as option pills and labelled filter chips
--role-action, -label, -edgeEvery primary button and submit
--role-action-pressed, -pressed-labelThe pressed primary action: the inverse pair (the ink pill presses to a --primary1 face)
--role-inverseThe label of an ink fill
--role-haloPaper-colored clearance and knockouts
--role-glyphChevrons, arrows and text-button glyphs
--role-status, --role-status-fill, --role-status-textStatus glyph, edge and bar; its fill; the status word
--role-pill, -label, -edgeA solid badge's fill; the ink pill on saturated fields
--role-disabled-edgeThe dotted edge of a disabled control
--role-series-oddThe odd chart series slots: --secondary11 on paper and white, --primary12 elsewhere
--role-groundThe scope's ground color
--role-edgeThe container edge of a card, face or panel, published by Ground: --role-rule on a band, --primary10 on a face on a page ground, --primary12 on a field or light island
--role-seamA band's top and bottom rule: invisible, except on the night band in dark mode

Hover

Hover follows the Land Trust Alliance model [D181]: it changes a fill or an ink, never an edge, a transform or a shadow. It runs for --ds-duration-quick with --ease-out-3, is instant under reduced motion, and never applies to a disabled control.

  • Contained buttons lighten. A solid Button's fill moves to --role-action-hover, and a contained selection fill to --role-select-hover. Label and edge stay, with no underline.
  • Outline buttons tint to --role-soft-hover; where soft fills drop, the label underlines instead.
  • Chevron links change color. A standalone Link and a text Button take --role-link-hover, and the glyph swaps to its next weight.
  • Body links (inline) keep their underline, take --role-link-hover and thicken the underline to --border-size-2.
  • Bare text underlines. A nav Link (bar and utility items, page numbers, toolbar links) and a tab take a --border-size-2 --role-accent underline.
  • List links change color only. kind="nav" list (navigation panels, footers, drawers), muted breadcrumb ancestors and card title links take --role-link-hover.
RoleHolds
--role-action-hoverThe action's lighter neighbour: --amber6 in light scopes, --amber10 in dark ones, --primary11 for the ink pill
--role-select-hoverA selected fill on hover; --primary11 where selection is the inverse pair
--role-link-hoverThe secondary's step 12 on light grounds, step 9 on dark grounds where it is text-safe, and --primary12 on the solid fields and on dark rose and heather
--role-soft-hoverThe outline button's --primary3 fill, or the ground where soft fills drop (the pastels, forest, the solid fields)
--role-soft-hover-faceThe same hover for a part whose face is --role-halo, such as the slider thumb: --primary3, or the unchanged face where soft fills drop

Wherever --role-link-hover is --primary12, an ink-only hover also underlines (--ds-link-hover-line); where soft fills drop, --ds-soft-hover-line underlines the outline button's label. Under forced colors, hover adds an underline to links and text and an outline to buttons.

Text is always --primary12, and the focus ring is a 2 px --primary12 line. Every fill has an edge [D12].

The 16 ground presets

v1 has 16 presets: eight page grounds, the night band and seven fields [D180]. Ground's kind decides where each may go: band (default, full-bleed) takes a page ground or night; field (inset, with a radius and its own --primary12 edge) takes a field; face (a card face, plate or panel) takes a page ground, and night only for the onMedia Button.

PresetFamilyGroundPrimary × secondary; actionMode
paper (default)page groundlight base (--orange2)olive × green; amberfollows the page
whitepage groundlight base (--olive1)olive × green; amberfollows the page
tidepage groundpastel (--blue3)slate × blue; amberfollows the page
meadowpage groundpastel (--green3)sage × green; amberfollows the page
pollenpage groundpastel (--yellow3)sand × yellow; amberfollows the page
apricotpage groundpastel (--orange3)sand × orange; amberfollows the page
rosepage groundpastel (--red3)mauve × red; amberfollows the page
heatherpage groundpastel (--purple3)mauve × purple; amberfollows the page
nightband (footer and media hero only)deep baseslate × green; amberalways dark
forestfielddeep tintedsage × amber; amberalways dark
leaffieldsolidolive × green; inkalways light
amberfieldsolidolive × amber; inkalways light
clayfieldsolidolive × orange; inkalways light
pinkfieldsolidolive × pink; inkalways light
royalfieldsolidslate × indigo; amberalways dark
brickfieldsolidmauve × red; amberalways dark

Page grounds paint the same step in both modes, so a pastel is very light in light mode and a rich near-black in dark mode. They hold reading and data; a page takes at most one pastel, with paper and white as its secondary bands. Fields hold media, actions and short content, inset with page ground around them, so two fields never touch. The solid fields carry one ink and no muted tier. Each page ground has a companion field for inverse placements: forest for paper, white, meadow and pollen; royal for tide and heather; brick for apricot and rose. Inside tinted or solid scopes, override primary and secondary only with a pairing the §2 matrix verifies.

sand, spruce and soil are deferred and lichen is retired; none is a preset, and passing one is a type error.

Full specification: DESIGN-SYSTEM.md §1.4 (the ink and ground model), §1.5.3 (role map) and §2.2 (presets and pairings), decisions D176–D181; companion guide §C.