The layouts are one system rather than twelve components: a spacing scale, a set of width tokens,
and an axis vocabulary that `Stack`, `Grid` and `Split` express differently. Learn the three and
you can read any of them.

## The spacing scale

Every `spacing`, `gap` and `minHeight` in the layout family takes the same token, so a page's
rhythm is a decision rather than a number typed in each place.

| Token | Steps of 0.25rem | Use it for |
| --- | --- | --- |
| `none` | 0 | A band that must sit flush against what follows |
| `xs` | 1 (0.25rem) | Icon-to-label, inside a chip |
| `sm` | 2 (0.5rem) | Between related lines |
| `md` | 4 (1rem) | The default gap between siblings |
| `lg` | 6 (1.5rem) | Between groups inside a band |
| `xl` | 8 (2rem) | Between bands |
| `2xl` | 12 (3rem) | A band that is meant to feel like a break |

The token names are the API; the numbers are what the theme maps them to. A product that wants a
tighter or looser page changes the scale once, not every call site.

## Width

A width is one of five tokens, and it is a maximum rather than a fixed size: content narrower than
the token still sits at its natural width, centred or aligned by its parent.

| Token | Behaviour |
| --- | --- |
| `sm`, `md`, `lg`, `xl` | A maximum width with side gutters, so text does not run to the edge of a wide window |
| `full` | No maximum: the band fills the viewport |

Two props pair with it, and the pairing is what keeps a full-bleed band from being a design dead
end: `contained` says whether the content inside is held to a width at all, and `containerSize`
says which width. A band with `contained={false}` is full-bleed but its *content* may still be
contained, that is what a coloured section with a centred headline is.

## Asking for the width

A *style* is answered by a media query through a class, which is what every component uses. A
*branch* — render a table or cards, a row of actions or an overflow menu — decides which elements
exist, and a class cannot do that. `useBreakpoint()` is how a component asks, and both renderers
export it under that name with the same shape:

```tsx
import { useBreakpoint } from "asheeui";

const { width, breakpoint, isAtLeast } = useBreakpoint();

return isAtLeast("lg") ? <Table rows={rows} /> : <Cards rows={rows} />;
```

`breakpoint` is the largest name the width has reached, or `base` below the smallest, and the
widths are `@asheeui/core`'s `BREAKPOINT` (`sm` 640, `md` 768, `lg` 1024, `xl` 1280) on both
platforms. The platform reads its window's own dimensions; the web measures the window after mount,
so server-rendered markup is the narrow arrangement and hydration never mismatches.

The rule that turns a width into a name is exported as `resolveBreakpoint`, and the state's shape
as `BreakpointState`, so a component that measures its own container can reuse both without
importing a renderer. `useReduceMotion()` follows the same pattern: the reader's motion preference,
under one name on either platform.

## The `as` prop

Every layout component takes `as`, which changes the element it renders without changing what it
does. That is how a page states its structure: `as="header"`, `as="nav"`, `as="main"`,
`as="section"`. The default is always the sensible neutral element, so `as` is for stating meaning
the component cannot infer, not for styling.

## The axis vocabulary

Three components place children along an axis, and they use the same words for the same ideas:

| Idea | `Stack` | `Grid` | `Split` |
| --- | --- | --- | --- |
| How children flow | `direction` (`row`, `column`) | `columns` (`1`…`12`, at `sm`/`md`/`lg` breakpoints) | Two panes, side by side above `stackAt` |
| Space between them | `gap` | `gap` | `gap` |
| Cross-axis alignment | `align` (`start`, `center`, `end`, `stretch`, `baseline`) | `align` (`start`, `center`, `end`, `stretch`) | `align` (`start`, `center`, `stretch`) |
| Main-axis distribution | `justify` (`start`, `center`, `end`, `between`) | | `ratio` (`equal`, `start`, `end`) |
| When it wraps | `wrap` | Always, by column count | At `stackAt` (`sm`, `md`, `lg`, `xl`) |

The distinction worth holding on to: **`Stack` is one-dimensional**, a row or a column of things,
in the order you write them. **`Grid` is two-dimensional**, a fixed number of columns, so the
items that do not fit wrap onto the next line themselves. **`Split` is two things**, a pair that
sits side by side when there is room and stacks when there is not, which is the shape of a
settings panel, a comparison or a table of contents.

## Which one for which job

| The page needs | Use |
| --- | --- |
| A row or column of items with a gap | [Stack](/components/layouts/stack) |
| A wall of cards in equal columns | [Grid](/components/layouts/grid) |
| Something beside something else, stacking on narrow screens | [Split](/components/layouts/split) |
| One thing in the middle of the viewport | [Centered](/components/layouts/centered) |
| A band of a page with a heading and a width | [Section](/components/layouts/section) |
| A maximum width around arbitrary content | [Container](/components/layouts/container) |
| A whole page shell | [Page](/components/layouts/page), [SidebarLayout](/components/layouts/sidebar-layout), [DocsLayout](/components/layouts/docs-layout), [MarketingLayout](/components/layouts/marketing-layout) |

For how the shells assemble a real page, including which one a product should start from, see
[Page compositions](/guides/page-compositions).
