Name colors by responsibility
A variable such as --surface explains where a color belongs; --purple-900 only describes its appearance. Keep both kinds if you need a palette and semantic layer. For example, a product theme can map its surface to silver and its text to plum without requiring every component to know the exact hexadecimal values.
Define a compact starting set
Begin with background, surface, text, muted text, border, accent and focus colors. Add spacing or radius tokens only when repeated usage justifies them. An enormous token catalog can become as hard to maintain as scattered literals. The first goal is to make a shared button or card express its intent consistently.
Scope variations near their context
Place default tokens on the root, then redefine semantic values on a theme wrapper. A light tool workspace might set --surface:#DDE3E8, --text:#3A0F34 and --accent:#EAAA00. Descendant components can inherit those values. This is more predictable than searching for every dark background class and overriding each one separately.
Remember that inheritance is selective
Custom properties inherit by default, but their effects depend on where they are consumed. If a component hard-codes its label color, changing --text does nothing to that label. Inspect the complete component state: default, hover, focus, disabled and error. A theme is incomplete when only its large background panels follow the token system.
Use fallbacks with a clear purpose
A declaration like color:var(--control-text, var(--text)) provides a useful fallback when a component-specific value is absent. It does not validate whether the supplied value creates a readable contrast. Keep fallback chains short enough to trace. If a custom property contains an invalid value for its destination property, debugging may require inspecting computed styles.
Verify themes as combinations
Review text and background pairs in the actual interface rather than testing each palette swatch in isolation. Check menus, inputs, helper text and code blocks. Temporarily change one semantic token and observe which components update. That experiment quickly reveals hard-coded exceptions and helps keep future visual changes focused instead of spreading into unrelated layout rules.
Further reading
Put the idea to work.
Explore free browser tools for images, text and developer workflows.