Docs :: AI Agents
mCSS is built to be easy for AI coding agents (Claude, Cursor, Copilot, etc.) to work with. The docs are available in machine-readable form, and this page includes a rules block you can paste into your project’s agent instructions so generated markup follows mCSS methodology.
Machine-readable docs
Three things exist specifically for agents:
/llms.txt: an index of every docs and components page with one-line descriptions, following the llms.txt convention. Most agent tooling checks for this automatically./llms-full.txt: the entire reference (docs and all components) concatenated into a single markdown file. Point an agent here when it needs the whole framework in one fetch.- Markdown twins: every docs and components page is also served as plain markdown at the same URL but with the
.mdextension. These are a fraction of the size of the HTML pages. Make sure you tell your agent to fetch the.mdURLs, not the HTML.
Add mCSS rules to your agent instructions
Paste the block below into your project’s CLAUDE.md, AGENTS.md, or equivalent. It compresses the conventions that matter most when writing mCSS markup and CSS on top of it.
## mCSS conventions
This project uses mCSS (https://mcss.dev), a CSS framework copied into the repo. There is no npm package: the files are project code, and the framework's defaults are overridden, never edited.Full reference in one fetch: https://mcss.dev/llms-full.txtPer-page docs: append `.md` to any mcss.dev docs or components URL (e.g. https://mcss.dev/components/card.md).
### Mental model: layers from default to deliberate
All framework CSS lives in native cascade layers, declared in `mcss.css` in priority order (later wins): `base, elements, global, components, theme.default, theme.user, external, helpers`. `mcss.css` only declares the `components` and theme slots; the component library fills `components` from a second entry, `mcss.components.css`, imported alongside (skip it in projects that build their own components), and the default theme (`theme.default.css`) fills `theme.default` from YOUR entry, imported right after `mcss.css`: nothing paints without it.
- `base` through `components` are the framework's structure. Never edit these files to restyle; override them from further up the order.- `theme.default` holds the default theme: every design value (raw tokens + UI tokens). Never edit it either; it is what your overrides fall back to.- `theme.user` holds at most one theme of your own: a deliberate opinion about the defaults (copy `theme.starter.css`). A full theme like `theme.wireframe.css` is an entry that composes the default theme and overrides on top; either way, activate exactly one theme entry.- `external` ships empty: a slot to demote third-party CSS you import yourself (`@import url(vendor.css) layer(external);`). It beats the framework but loses to all unlayered project CSS at any specificity, so vendor styles stay easy to override. Fixes to vendor CSS go in unlayered `patch.*` files (the one place allowed to select third-party classes). Vendor styles injected from JS cannot be captured this way; they stay unlayered.- Your own unlayered CSS is more deliberate still: it beats every layer, by design. Never use `!important` to win against the framework.- `helpers` (`help.*` files: spacing, color, typography utilities) are the one exception: every declaration carries `!important`, which inverts the cascade, so they beat even unlayered CSS. Use sparingly. `!important` is banned everywhere else.
The layer order is only the enforced half of the system. mCSS is a methodology (simplified ITCSS) first: selectors stay flat (single class, no specificity stacking) and files are ordered broad to specific everywhere, including unlayered project CSS. `@layer` hard-codes that discipline for the framework's half so it can never fight yours; in your own files, the same flat selectors and deliberate import order make source order the reliable tiebreaker. Don't reason about a mCSS project like arbitrary CSS: a conflict is resolved by putting the rule in the right file, never by escalating specificity.
Inline `style` attributes don't participate in the order at all: they beat every normal declaration in every stylesheet (only a helper's `!important` outranks them). **Never place, size, space, or color anything from a `style` attribute**: a declaration written into markup is one no stylesheet can see, override, or audit, which is the opposite of what the layer order is for. When a value genuinely comes from data, pass it as a custom property and consume it in CSS:
```html<div class="chart" style="--chart-columns: 7"></div>```
### Restyling, in order of preference
1. **Theme token overrides.** A theme is one file that restyles the whole site: `@layer theme.user { :root { ... } }` (self-layered, so it slots correctly however it's loaded). Copy `theme.starter.css` to start one; import it from your CSS entry point after `theme.default.css`, the default theme that carries every design value and that your entry must activate right after `mcss.css` (which never imports themes itself; nothing paints without the default theme). Your theme lands in `theme.user` and beats the default's `theme.default` regardless of import order; anything it doesn't mention falls back to the default theme. Pick the blast radius per override: raw tokens (`--base-*`, `--text`) shift the whole palette or type scale, UI tokens (`--ui-border-color`, `--heading-font`) change every surface that shares the meaning, component tokens (`--bt-border-radius`, `--card-*`) turn one knob.2. **Theme style rules**, only if a token doesn't exist for that value, or for what tokens can't express (pseudo-elements, `nth-child` rhythm, etc.). It's ok to override elements like `body` if there is no other way to reliably set it globally. Theme files are the ONE place allowed to select framework classes from outside: component classes, framework globals like `.a11y-skipLink`, and bare element selectors. **A `body` rule belongs here, not in project CSS**. Make sure you keep the ordering general to specific (same as ITCSS). No `!important` in themes.3. **Unlayered project CSS** for what belongs to your project rather than to the design: page layouts, one-off blocks.
Do not edit framework files.
### Tokens
- Every token lives in the default theme, split in two: `theme.default.tokens.css` holds the scales (palettes, type scale, spacing, radii), `theme.default.ui.css` holds the UI tokens, the public API of every element and component (semantic aliases plus all defaults). Placement is by name: a token named for what it's for (`--heading-*`, `--bt-*`, `--ui-border-color`) is a UI token; a token named for what it is (`--sm1`, `--base-500`) is a raw token. Values prefer another token (a shared-meaning UI token first, else a raw token); hard-coded values only for content (strings, icon URLs), one-off control geometry, or element-relative `em`/`ch` measures.- Grammar: `--component-part-property`, longhand, kebab-case, no abbreviations: `--bt-background-color-hover`, `--notice-border-width`.- Feedback colors come straight from the `--yes-*` / `--no-*` / `--maybe-*` palettes; there is no separate success/danger/warning alias tier.- The same discipline applies to your own CSS: **no raw color and no raw type size in a `component.*.css` file.** If the theme doesn't name the value you need, add a token to the theme and use that. A `#8a5500` or a `1.0625rem` sitting in a component is a design decision nobody can find, and the second use of it will be a slightly different number.
### Organizing project CSS: one block per file
Name each file for the block it holds, and hold one block in it. `component.card.css` is `.card`, its elements, its modifiers, and its media queries, nothing else. A file carrying a second block is a file you cannot delete when that block dies; a block with no file of its own is a block nobody can find.
- A container's items are elements, not blocks: `.steps_step` lives in `component.steps.css` with the rest of `.steps`. Something with a life of its own outside the container (`.card` in a `.cardGrid`) is its own block, with its own file.- A nested component starts its own name, so it gets its own file.- `global.*` files follow the same rule: one scaffold, one utility, one role family per file. A `global.layout.css` holding the page shell, a section pattern, and nine typography classes is three files.
The import list in the entry file is then also the list of blocks in the project, in build order, which makes an unfamiliar codebase readable from one file.
### Exceptions
Some CSS legitimately crosses block boundaries. An acceptable exception is bounded and named: one predictable file, one clear reason, so you always know where to look. Theme files are one (themes restyle other blocks by design, see above). A print sheet is another: a `global.print.css` holding **every** `@media print` rule in the project, including rules that select other blocks' classes, because a printed page is one design decision about a medium, easier to keep coherent in one place than spread across every component it touches. Group a print sheet by intent rather than by component: the sheet, what paper cannot use, ink instead of tint, where the page may break.
**Media queries about conditions never get this kind of exception.** `@media (forced-colors: active)`, `prefers-reduced-motion`, and `prefers-color-scheme` stay in the file of the block they concern: those are per-block statements about how one component survives a condition.
### Class naming (BEM-like, different separators)
- Block: `.componentName` (camelCase for multi-word names)- Element: `.componentName_element` (underscore marks hierarchy inside one block; chains may nest as deep as the block's structure needs)- Modifier: `.componentName-modifier` (hyphen), for build-time variants chosen in markup- State: `.is-*` (`.is-active`, `.is-open`), only for things that change at runtime, always scoped inside the block (`.avatar.is-online`)- Prefer styling an existing ARIA attribute over inventing a state class: `[aria-current]`, `[aria-expanded="true"]`, `[aria-disabled="true"]`- A nested component starts its own block: `.themeToggle_text`, never `.header_nav_themeToggle_text`- Inside a component's own CSS, bare HTML element selectors are fine (and recommended) instead of a class for every element.- Modifiers should override local custom properties declared on the block, not redeclare CSS directly. Declare property defaults on the block (never inside an `.is-*` state, which compiles to a two-class selector that would beat single-class modifiers); states only consume the properties.
### Never couple classes across components (CRITICAL)
A selector may only contain classes from its own block. Never write a selector that reaches into another component: not its block, not its elements. Instead, mix your own block's classes onto the component's markup and style those:
```html<article class="card pricing_planCard"> <h3 class="card_title pricing_planTitle">Pro</h3></article>```
```css/* Don't: couple your block to the card's classes */.pricing .card { border-color: var(--primary-500);}.pricing .card_title { color: var(--primary-500);}
/* Do: style the classes you mixed on */.pricing_planTitle { color: var(--primary-500);}
/* Do: or turn the component's own token knobs from your class */.pricing_planCard { --card-border-color: var(--primary-500);}```
When the markup is rendered by a component file (Astro, JSX) instead of HTML you type yourself, its `<part>Class` props (`titleClass`, `iconClass`, ...) mix your class onto the internal part the same way. If the token or `<part>Class` prop you need doesn't exist, don't reach in with a selector and don't edit the framework file: override what you can through mixed classes or your theme, and past that, replace the component with a site component of your own.
Bare HTML tags, `.is-*` states, and ARIA attribute selectors are fine inside your own block. Selectors only cross block boundaries in the bounded exceptions described above (theme files, a print sheet).
### Globals lose to components, and that is the point
`global.*` files import before `component.*` files, so a component always wins a specificity tie. That ordering is deliberate: a global is a default, and a component refining it is the architecture working, not a conflict to be resolved.
Which gives you a diagnostic. **A "global" that only works if it beats components is not a global: it is a helper.** mCSS puts helpers in `help.*`, in the `helpers` layer, with `!important`, precisely because a thing that must outrank every block has to sit above every block. If you find yourself moving a `global.*` import to the end of the entry file so it stops losing, stop: either use a helper, or the thing is the wrong shape. Do not hand-simulate the helpers layer with source order.
Spacing is where this goes wrong most often:
- **A class whose only job is to set a margin is a helper**, whatever you called it. One declaration, no structure, no semantics, applied per element from the markup: that is `.mt-sm3` with extra steps.- **Spacing between blocks is usually a property of the container.** Give the container the step and let it declare the value; the markup then carries no spacing at all, and a block that needs a different step says so in its own file:
```css .panel { --panel-flow: var(--sm3);
> * + * { margin-top: var(--panel-flow); } } ```
- **A margin reset names its sides.** `margin: 0` on a block that lives in such a container silently claims the container's step as well, and nothing about the declaration tells you it did. Write `margin-block-end: 0; margin-inline: 0` unless overriding the step is what you actually mean, and if it is, say so in a comment, because the next reader cannot tell the two apart.
### Transitions
Never `transition: all`; list the properties that actually animate.MCP and tooling
There is no mCSS MCP server yet. For now, llms-full.txt plus the rules block above is the recommended setup. If your agent supports fetching URLs at runtime, the markdown twins are the cheapest way to pull a single component’s markup reference into context.