Utilities
Utilities are generated from your tokens, so .my-mt-m is a fluid margin that scales with the viewport - not a fixed pixel step. Two coverage levels, chosen in the builder:
Lean (default - smallest CSS)
- Spacing:
mt/mb/my/pt/pb/py/px/gap-{3xs…3xl},m-0,p-0 - Colour:
text-{palette}-{variant},bg-{palette}-{variant} - Type:
fontSize--step-*,lh-*,letter-spacing-*,font-heading/body/mono, alignment, weight - Grid & flex:
col-1…12,flex,flex-col,items-center,justify-between/center,wrap - Visibility:
hide-below-{bp},hide-above-{bp},visually-hidden
Extended (opt-in)
- Display:
block,inline-block,inline-flex,d-grid,hidden - Position & layers:
relative/absolute/fixed/sticky,inset-0,z-{tooltip…toast} - Flex detail:
flex-1,grow,shrink-0, fullitems-*/justify-*/self-* - Sizing:
w-full,h-full,min-h-screen,max-w-prose - Spacing completion: all-sides
m-*/p-*, logicalms/me/ps/pe-*,mx-auto - Decoration:
rounded-*,border,shadow-s/m/l,opacity-*,overflow-*,truncate - Responsive grid spans:
col-6-from-mdreads “6 columns frommdup” (mobile-first). Plain hyphens - no escaping needed in querySelector, SCSS or template engines. In extended mode the grid keeps its columns at every viewport - combinecol-12 col-6-from-mdfor full-width-on-phones.
Why no hover:/dark: variants?
Components own their states - buttons already know how to hover, and every colour token already re-themes under [data-theme='dark']. Keeping state out of the utility layer is what keeps your CSS at a few KB instead of a few hundred.