system.cssthe engine GitHub

State belongs in `data-ui-*`, not `data-*`

State belongs in data-ui-*, not data-*

Datastar owns the data-* space. Put your styling state hooks under the framework's existing data-ui-* namespace (it already uses data-ui-theme/size/motion and .tag[data-ui-state]). This avoids any collision with Datastar and makes selectors self-documenting:

css
.cal .ngrid > button[aria-current="date"]    { outline: 2px dashed var(--focus); }
.cal .ngrid > button[data-ui-selected] { outline: 2px solid var(--focus); }
.cal .ngrid > button[data-ui-adjacent] { --bg: 0.1; }
html
<button data-attr:aria-current="cellIsToday($cal.v,i) ? 'date' : 'false'"
        data-attr:data-ui-selected="cellIso($cal.v,i) === $cal.sel"
        data-attr:data-ui-adjacent="!cellInMonth($cal.v,i)">…</button>

Classes are identity; data-ui-* (or ARIA) is state. A class says what the element is — a layout primitive or component (.card, .column, .ngrid, .tag), authored once, never toggled. A data-ui-* attribute says what state it's in, toggled at runtime by data-attr. Keep them visibly separate: class="column" (it's a column) carrying data-ui-selected (it's selected).

If the element already carries ARIA state, style off that — don't add a redundant flag. Selection grids set aria-pressed/aria-checked; a combobox option sets aria-selected. Style &[aria-pressed="true"] directly so the accessible state and its look share one source of truth and one binding. Reserve data-ui-* for state with no ARIA equivalent — a calendar's adjacent (out-of-month) day, a range's band / preview / endpoints. (A calendar's today is a real ARIA fact, aria-current="date", so it stays ARIA.) Two house reservations on top of that rule: data-ui-state="active" is the ENGINE's painted lens-control state (--bg 1 / --fg −1 — an applied sort/filter/scope is a condition ARIA has no word for), and data-ui-state="on|off" is the legend-toggle pair. Never stamp an ARIA state AND a data-ui-* flag for the same fact — one source of truth, one binding.

data-class (reactively toggling a class) is still fine for genuinely class-shaped things — toggling a layout primitive, or the container-band .medium/.column reveal. The rule is only that visual state lives in data-ui-*/ARIA, not that every reactive toggle is an attribute.

Where component CSS lives

Wrap each component's rules in @layer components (with a comment banner) and nest the state inside the structural class, so an element and its states read as one block:

css
@layer components {
  /* calendar — standalone month surface */
  .cal .ngrid > button {
    aspect-ratio: 1; display: grid; place-items: center; --bg: 0.3;
    & > b               { --type: -1; --fg: -0.9; }
    &[data-ui-adjacent] { --bg: 0.1; & > b { --fg: -0.6; } }
    &[aria-current="date"]    { outline: 2px dashed var(--focus); }
    &[data-ui-selected] { outline: 2px solid var(--focus); }
  }
}

Your components then become genuine peers of .card/.tag in the same layer, so the cascade stays predictable instead of "app CSS wins by being unlayered." The framework declares the spine up front (@layer reset, core.color, core.type, core.layout, theme, base, components, utility, media, skin, view-transitions;), so an appended @layer components {} block joins that layer after the framework's components — it doesn't become a new top layer. Do not put component rules in project (or leave them unlayered): they would out-cascade the media layer and break the revert-layer gates (.small/.medium/.c-*). Reactive paints are unaffected: data-style:--bg and inline style="--bg:…" are inline styles, which beat any layer.