---
title: "Cascade layers"
description: "Where Systhema's CSS sits in the cascade, why Tailwind utilities beat component classes, and how @layer app overrides both."
requested_language: nl
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/nl/next/styling/cascade-layers
version: unreleased (main)
docs_index: https://docs.systhema.app/nl/next/llms.txt
---
> This page isn't translated yet. Showing English.


Systhema's stylesheet is ordered with CSS cascade layers, so you can predict which rule wins without raising specificity: a Tailwind utility beats a Systhema component class, and a rule in your `app` layer beats both.

## Layer order

The Tailwind entry declares these top-level layers, in this order (a later layer wins):

```text
theme, base, components, utilities, app
```

- `theme`, `base`, `components` and `utilities` are Tailwind's layers.
- `app` is empty. It is reserved for your project's overrides.

Inside `utilities`, Systhema's component classes (`.button-primary`, `.card-default`, `.accordion-title`, the text styles, `gap-*` and the other token utilities) live in a named sub-layer, `utilities.systhema`. Tailwind's own utilities are emitted directly in `utilities`, outside any sub-layer:

```text
utilities
├─ utilities.systhema   Systhema component classes and token utilities
└─ (no sub-layer)       Tailwind utilities: text-xl, p-4, rounded-none
app                     your overrides
```

A rule that sits directly in a layer beats every rule in that layer's sub-layers, whatever their specificity. That gives the familiar order: Tailwind utilities beat Systhema's classes, and `app` beats everything.

## Overriding a component with a utility

Because of that order, a Tailwind utility on a component overrides one property and keeps the rest of the component's styles:

```tsx preview title="Utilities over a component class"
import { Button } from '@systhemaui/next'

export default function Demo() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      <Button.button variant="primary">Default</Button.button>
      <Button.button variant="primary" className="rounded-none">
        rounded-none
      </Button.button>
      <Button.button variant="primary" className="rounded-full px-8">
        rounded-full px-8
      </Button.button>
    </div>
  )
}
```

The same goes for the token utilities: `text-h2 font-normal` is an h2 at regular weight, and `gap-md gap-4` resolves to `gap-4`.

## Writing project overrides

For overrides that are more than a utility or two, write CSS in the `app` layer. It wins over Tailwind's utilities and every Systhema class, and keeps your rules in one predictable place:

```css title="app/globals.css"
@import '@systhemaui/core/tailwind';

@layer app {
  /* Put the accordion icon before the title from md up, on this project only. */
  .accordion-title {
    @variant md {
      @apply flex-row-reverse justify-end;
    }
  }
}
```

Rules outside any layer would win too, because unlayered CSS beats every layer, but they also beat Tailwind utilities you add in markup later. Keeping overrides in `app` leaves the utilities in charge.

## Overriding `!important` rules

`!important` reverses the layer order: an `!important` declaration in an earlier layer beats one in a later layer, and an unlayered `!important` loses to every layered one. A few Systhema rules carry `!important` (the scroll-reveal states, for example), and they sit in `base.systhema`, so an `!important` in `@layer app` cannot beat them. To out-rank one, declare an override layer before the Systhema import, which makes it the earliest layer:

```css title="app/globals.css"
@layer overrides;
@import '@systhemaui/core/tailwind';

@layer overrides {
  .aos:not(.animated) {
    opacity: 1 !important;
  }
}
```

## Components that borrow another block's classes

Some component rules take their type scale, or whole component styles, by applying another Systhema class instead of repeating its declarations: `.form-label` applies `text-form-label`, and formatted rich text (`.richtext.is-formatted`) applies `text-h1` to `text-h6`, `text-body`, `link`, `quote`, `separator`, `list-bullet` and `list-number`.

Those bindings follow the flag of the block that owns the class, not the block that borrows it. Turning `blocks.link` off while keeping `blocks.richtext` on does not break your build: the link binding is skipped, and links in formatted rich text fall back to your own link styles. If your tokens do not define a text style, its binding is skipped the same way. Formatted rich text looks its best with `typography`, `link`, `quote`, `separator` and `list` all on, which is the default. See [Component CSS blocks](https://docs.systhema.app/nl/next/styling/blocks.md).

Rich-text block margins apply only to Systhema's `.columns`, `.stack`, `.card-<type>` and `.accordion-<type>` classes. A project class whose name merely contains `card` or `accordion` does not get them; use a Systhema block class for the doubled rhythm, or add a margin rule of your own.

## Related

- [Tailwind integration](https://docs.systhema.app/nl/next/styling/tailwind.md)
- [Component CSS blocks](https://docs.systhema.app/nl/next/styling/blocks.md)
- [Spacing model](https://docs.systhema.app/nl/next/concepts/spacing-model.md)
