The style pipeline & recipes

How token ids inside a style spec become var() strings, and how the data-only recipe layer expresses variants without a runtime.

FDS keeps CSS compilers token-agnostic: authors write bare token ids as values, and a resolution pass rewrites them into var() strings before any CSS is generated. The compiler never learns what a token is.

import { resolveStyleTokens, hasToken } from 'flexa-design-system';

resolveStyleTokens(
  {
    '.btn': {
      background: 'color.primary',
      padding: 'space.3 space.6',   // multi-value works too
      'border-radius': 'c.button.radius',
    },
  },
  hasToken,
);
// → { '.btn': { background: 'var(--fx-color-primary)', … } }

Values that aren't token ids (#fff, 1.5rem, url(img.png)) pass through untouched. The gate for typos is separate:

import { findUnknownStyleTokens } from 'flexa-design-system';

findUnknownStyleTokens({ '.x': { color: 'color.primry' } });
// → ['.x.color: color.primry'] — reserved namespace, unknown token → reject

This is the machine gate that makes the system safe for generated styles: an AI (or a marketplace vendor) can only reference tokens that exist. Off-system ids are rejected at validate time, not discovered in production.

Recipes: variants as data

A recipe is a data-only variant model (think CVA/vanilla-extract, minus the runtime): a base style fragment, per-option variants, optional compound fragments for option combinations, and default selections. A pure function merges the fragments for a node's chosen props into one style spec, which then flows through the same token resolution above.

{
  "base":     { ".btn": { "border-radius": "c.button.radius" } },
  "variants": {
    "tone": {
      "primary": { ".btn": { "background": "color.primary" } },
      "danger":  { ".btn": { "background": "color.danger" } }
    },
    "kind": {
      "solid":   {},
      "outline": { ".btn": { "background": "transparent" } }
    }
  },
  "compound": [{
    "when":  { "kind": "outline", "tone": "danger" },
    "style": { ".btn": { "color": "color.danger" } }
  }],
  "default": { "tone": "primary", "kind": "solid" }
}

The layering model

In Flexa Builder the final CSS for a node is a deterministic cascade of specs, each resolved through the same pipeline: manifest style < recipe < global component styles < per-node overrides. Every layer speaks tokens, so a theme swap restyles all four at once.