Appearance
Inverse Tokens
The problem
In a light theme (direction "down"), content is pushed to darker tones for contrast. But when a surface's tone crosses below 50 (dark enough to be "dark-mode-like"), dark content on a dark surface loses readability. The same happens in reverse for dark themes.
The solution
Systema generates inverse versions for every content and container entity:
- inv-content -- uses the base direction's hue (so the color character stays the same) but the flipped direction's tone. If normal content goes darker, inv-content goes lighter.
- inv-containers -- same principle applied to container backgrounds.
When to use inversions
| Scenario | Use |
|---|---|
| Light card on a dark surface | inv-containers for the card background |
| White text on a dark button | inv-content for the text color |
| Dark overlay with light UI elements | inv-content on overlays |
| Accessibility mode with forced high contrast | inv tokens naturally provide the opposite contrast direction |
Inverse collection merging
Direct and inverse tokens live in the same Figma variable collection, which keeps the collection count low. Inverse tokens are distinguished by a path prefix:
| Prefix | Meaning |
|---|---|
inv/ | Inverse content |
on-inv/ | Content computed on an inverse container |
inv-on-inv/ | Inverse content on an inverse container |
The standalone inv/ path segment marks inverse content only. Inverse containers are distinguished by an inv-<entity> name segment instead (e.g. inv-containers-0), not an inv/ path prefix.
For example, in the collection color/containers (balanced structure), on surface level 0:
text
enabled/surfaces-0/containers-0/brand -- direct container token
enabled/surfaces-0/inv-containers-0/brand -- inverse container token (same collection)And for content on that surface, in color/content:
text
on-surfaces/surfaces-0/enabled/c-0/brand -- direct content token
on-surfaces/surfaces-0/inv/enabled/c-0/brand -- inverse content token (same collection)Contrast values
Inverse tokens may show different contrast values than their direct counterparts. This is because the flipped tone direction may hit the gamut ceiling (tone 0 or 100) sooner. The preview shows the real measured contrast for both direct and inverse swatches, computed from the actual rendered tones via contrastRatio() in src/lib/hct-engine.ts — Material's Contrast.ratioOfTones() under the WCAG model, or measured APCA Lc under the APCA model (APCA is "coming soon"). The displayed number follows the theme's active contrast model.
Fixed tokens
Fixed tokens are a mode-independent companion to the inverse system. They apply to Frame and top-layer entities only.
fixedEnabledis the master switch and is off by default.- When enabled, a Fixed seed colour and direction override the active mode, so the fixed tokens stay constant regardless of which mode is active.
fixedConfigchooses between inheriting the active settings or using a custom configuration. Custom usesfixedContrastRatiosandfixedColorIdsinstead of the inherited values.- Fixed tokens land in single-mode
color/fixed/{entityName}collections. - Fixed also emits inverse variants under an
invprefix, mirroring the inverse convention above.