Theming
Themes provide palette identity while Natcore's adaptive color tokens keep the same UI working in light and dark schemes.
How themes work
Themes set palette roles like primary, secondary, accent, surface, danger, and success.
Each role can provide 50, 500, and 950 anchors. If a role only provides one color, that color becomes the 500 anchor.
Natcore derives missing 50 and 950 anchors, then interpolates the full shade ramp and matching on-color text values.
Dark-mode tokens point to the opposite side of the light ramp, so contrast flips without new markup.
Component and utility classes use adaptive tokens like color-primary-500, which resolve through the active scheme.
Theme identity
:root[data-theme="citrine-reef"] {
--theme-primary: #087f8c;
--theme-secondary: #f59e0b;
--theme-accent: #ef476f;
--theme-surface-50: #f4fbf7;
--theme-surface-500: #678f82;
--theme-surface-950: #071c18;
--theme-danger: #c2415d;
--theme-success: #26966f;
}Classes like btn-solid/primary and card-soft/surface stay the same when the selected theme changes.
Anchor system
Use this when a brand palette already has intentional light, middle, and dark stops.
:root[data-theme="custom"] {
--theme-primary-50: #eef8ff;
--theme-primary-500: #087f8c;
--theme-primary-950: #061a21;
}Use this when you only know the main role color. Natcore treats it as 500 and derives the outer anchors.
:root[data-theme="custom"] {
--theme-primary: #087f8c;
}
/* Equivalent anchor behavior:
primary-500 uses #087f8c.
primary-50 and primary-950 are derived. */The light anchor. Used for soft fills, subtle surfaces, and the light end of the role ramp.
The center anchor. A bare role variable like --theme-primary resolves here.
The dark anchor. Used for strong contrast, deep fills, and the mirrored side of dark mode.
Light and dark
<html class="scheme-light-dark" data-theme="citrine-reef">
<body>
<button class="btn-solid/primary">
Create project
</button>
</body>
</html>
Always resolves adaptive tokens to the light color ramp.
Always resolves adaptive tokens to the dark color ramp.
Lets the browser resolve light-dark tokens from the user's color scheme.
Adaptive token resolution
@theme {
--color-primary-50: light-dark(
var(--color-light-primary-50),
var(--color-dark-primary-50)
);
--color-dark-primary-50: var(--color-light-primary-950);
}On-color tokens follow the same pattern. A surface can use bg-primary-500 while text uses text-on-primary-500, and both resolve together.
Authoring guidance
Use explicit 50, 500, and 950 anchors for roles where the exact ramp matters. Use a single role color when derived anchors are enough.
Primary should mean primary action across every theme, even when its actual hue changes.
Check light and dark because dark mode uses mirrored shade relationships, not a separate set of component classes.