Primitive tokens hold raw values; semantic tokens map them to roles. Themes swap semantics.
Components reference --color-primary, never #3B82F6. Brand theme swaps the mapping.
Split tokens into two layers: primitives hold raw values (blue-500 = #3B82F6) and semantic tokens map them to roles (--color-primary points at blue-500). Components only ever reference the semantic role. Now a rebrand, a dark theme, or a white-label client is one remapping at the semantic layer, not a find-and-replace of a hex value across hundreds of files. This is how a design system ships multiple themes from a single component set.
The layering earns its keep when a system needs to theme, rebrand, or scale across products. A tiny one-off site with a single fixed palette can reference primitives directly without the ceremony. Add the semantic layer when a second theme, a rebrand, or a white-label requirement actually appears, not speculatively before there is anything to swap.
Your product ships under 3 brands. Each has its own color, type, radius.