> ## Documentation Index
> Fetch the complete documentation index at: https://invoca-5bd45748-mintlify-6c3474a6.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Layout & grid

> Breakpoints, the grid, and what Titan does and does not decide about page structure.

## What it governs

Where things sit on the page and how that changes with viewport width. Two mechanisms —
breakpoints and a 12-column grid — and no tokens of its own.

## Vocabulary

| Axis          | Values             | Means                    |
| ------------- | ------------------ | ------------------------ |
| **attribute** | `tablet` `desktop` | The named viewport bands |
| **size**      | `min` `max`        | Which bound of the band  |

<Note>
  **Sourced from Invoca's design-token naming specification**, confirmed by its owner as the
  baseline the design language is being built on. This is the vocabulary of record — not
  inferred from token names.
</Note>

## Breakpoints

Breakpoints are **min-width**: a rule at `md` applies at 900px *and above*. Titan is a
desktop-first internal product, so in practice most surfaces live at `lg` and `xl`, and
`xs`/`sm` are rarely exercised. The values are in
[Token reference](#token-reference) below — see
[Open issues](/invoca-design-system/foundations/layout-and-grid/open-issues) for how they
were arrived at and how they relate to the naming specification.

## The grid

A 12-column flexbox grid, driven by per-breakpoint span props.

```jsx theme={null}
<Grid container spacing={2}>
  <Grid size={{ xs: 12, md: 6, lg: 4 }}>…</Grid>
  <Grid size={{ xs: 12, md: 6, lg: 8 }}>…</Grid>
</Grid>
```

<Warning>
  **The grid's `spacing` prop is not the Titan spacing scale.** It uses a separate 8px
  multiplier, so `spacing={2}` resolves to 16px — the same number as `spacing-5`, by
  coincidence, through a mechanism that maps to no step on the Titan scale and will not
  track it if the scale ever changes.

  Set gaps from a `spacing-*` token instead:

  ```jsx theme={null}
  <Box sx={{ display: 'grid', gap: 'var(--titan-tokens-spacing-5)' }}>
  ```

  See [TITAN-LAY-03](#constraints).
</Warning>

## Choosing a layout approach

| You need…                                                    | Use                                        | Not                                                                    |
| ------------------------------------------------------------ | ------------------------------------------ | ---------------------------------------------------------------------- |
| A row of items that wrap by viewport width                   | `Grid` with per-breakpoint spans           | A flex row with fixed widths — it will not reflow                      |
| Evenly spaced items in one direction                         | `Stack` (`Components/Stack`)               | `Grid` — a 12-column grid for a single row is overhead with no benefit |
| A page split into a fixed sidebar and a fluid main region    | CSS grid with a fixed track and `1fr`      | `Grid` spans — a 12-column split cannot express "280px and the rest"   |
| A card that reflows its own contents independent of viewport | A container query                          | A breakpoint — the viewport does not tell you how wide the card is     |
| Spacing between grid items                                   | `gap` with `var(--titan-tokens-spacing-N)` | `Grid`'s `spacing` prop — it is not the Titan scale                    |

## Token reference

<Snippet file="generated/tokens/layout.mdx" />

Titan defines no grid specification — no columns-per-breakpoint table, no gutter scale, no
page margin scale. See [TITAN-DIV-08](/invoca-design-system/foundations/divergences#titan-div-08).

<Note>
  **There are no layout tokens.** Breakpoints are not part of the token surface, so they are
  not reachable via `$token`, `theme.vars.tokens[…]`, or `var(--titan-tokens-…)`. Nothing
  about layout is currently expressible as a token.
</Note>

## Constraints

| ID               | Constraint                                                                                       | Rationale                                                                                                                                                       |
| ---------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **TITAN-LAY-01** | Layout responds at the defined breakpoints. Never a hardcoded media query.                       | A literal `@media (min-width: 900px)` is invisible to the audit and silently diverges the moment a breakpoint moves.                                            |
| **TITAN-LAY-02** | Layout adapts at the defined breakpoints only. No custom intermediate values.                    | Each additional breakpoint multiplies the states every component must be verified in. Five is already more than most components are checked against.            |
| **TITAN-LAY-03** | Grid gutters and gaps come from a `spacing-*` token via `gap`, not from `Grid`'s `spacing` prop. | `spacing` resolves through a separate 8px multiplier that maps to no step on the Titan scale.                                                                   |
| **TITAN-LAY-04** | Content reflows to a single column at `xs`. Never horizontal scrolling.                          | [WCAG 2.2 Reflow (AA)](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html) requires content to work at 320px equivalent without two-dimensional scrolling. |
| **TITAN-LAY-05** | A component that must adapt to its container, not the viewport, uses a container query.          | A card in a sidebar and the same card in a main region are the same viewport and different widths. Breakpoints cannot express that.                             |
| **TITAN-LAY-06** | Page structure is a [View](/invoca-design-system/views/overview) decision, not a component one.  | A component that assumes its page position cannot be reused. Region layout belongs to the view archetype.                                                       |

## Accessibility

* **Reflow to 320px without horizontal scrolling** is the binding requirement
  ([WCAG 2.2 AA](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html)). It is equivalent
  to a desktop page at 400% zoom, which is how low-vision users actually read — not on a
  phone. A desktop-only product still has to meet it.
* **Visual order must match DOM order.** CSS `order`, `row-reverse`, and grid placement can
  reorder content visually while leaving keyboard and screen-reader order unchanged. The
  result is a focus ring that jumps around the screen. If the visual order is right, fix
  the DOM.
* **Do not hide content at small viewports.** `display: none` at `xs` removes it for
  everyone, including the zoomed desktop user who is not on a phone.
* **Text must survive 200% zoom** without clipping. Fixed-height containers around wrapping
  text are the usual failure.
* Container queries do not change any of the above — they change *which* layout applies, not
  whether it must reflow.

## Known issues

<Card title="Layout & grid: open issues" icon="triangle-exclamation" href="/invoca-design-system/foundations/layout-and-grid/open-issues">
  Divergences, open decisions, and undocumented gaps for Layout & grid.
</Card>

## Related

A generated map of which components consume which foundation does not exist yet.

## Why it works this way

**Titan does not decide page layout, and that is a real position** — though currently an
undocumented one. The system supplies components and the space between them; where regions
sit belongs to the [View](/invoca-design-system/views/overview) tier. That separation is what lets a Button work
identically in a wizard and a dashboard.

The cost is that until Views is written, the most consequential layer of any screen has no
documentation at all. An agent asked to build a settings page makes a View-level decision
first and a Component-level decision last, and today only the second has an answer.

**Breakpoints are inherited because Titan is desktop-first internal software.** Most
surfaces render at `lg` and `xl` on a monitor the user cannot resize much. Spending the
maintenance budget on validating phone breakpoints for a product used at a desk would buy
very little — but that reasoning is inferred from usage, not recorded anywhere.
