The systemLumos 0.0.1
The cascade
Four layers, in a fixed order. The decision that makes every other style in Lumos predictable.
In CSS, when two rules both apply to an element, the more specific selector wins. That rule is why stylesheets rot: to override something you write a longer selector, then someone overrides that with a longer one still, and eventually the only thing that works is !important.
Lumos does not play that game. Styles are split into four cascade layers, and a later layer beats an earlier one whatever the selectors say. A one-class utility beats a component's twelve-selector rule, every time, without a fight.
The four layers
| Layer | Lives in | Holds |
|---|---|---|
base | base.css | Design tokens, color themes, the reset, text styles |
patterns | patterns.css | Multi-property rules shared between components |
components | Each component's own <style> | The component itself |
utilities | utilities.css | Single-property classes |
The order is declared once, in global.css, before anything is imported:
@layer base, patterns, components, utilities;
@import "./base.css" layer(base);
@import "./patterns.css" layer(patterns);
@import "./utilities.css" layer(utilities);What this buys you
Take a card with a heading. The component sets the heading's margin. You want no margin on this one page. In an ordinary stylesheet you would need a selector at least as specific as the component's. Here you add margin-top-0 and it wins, because utilities are the last layer.
<Heading tag="h3" class="margin-top-0">No space above me</Heading>The same holds in the other direction: a component can safely override a pattern it uses, because componentsCascade layerbasepatternscomponentsutilitiesA later layer wins, whatever the selectors say. comes after patternsCascade layerbasepatternscomponentsutilitiesA later layer wins, whatever the selectors say.. Nobody has to know what anyone else's selectors look like.
Reading it as a hierarchy
- base sets the ground rules: what a heading looks like anywhere on the site.
- patterns name the shapes that repeat: a container, a flex row, a grid.
- components style themselves, and may override any pattern they use.
- utilities are the last word, for the one-off adjustment that belongs to this instance and nothing else.
Anything that does not fit that ladder is usually a sign it belongs one level up: a pattern repeated in four components wants to be a pattern, and four utilities always used together want to be a prop.
Adding your own styles
Write your own component styles inside a layer too, so they slot into the same ladder rather than sitting on top of it. In an Astro component, that means wrapping the <style is:global> block:
<style is:global>
@layer components {
.hero_grid {
display: grid;
gap: var(--space-6);
}
}
</style>