This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<divclass="docs-content"data-render>
{% raw %}
# Consistency rules
These are hard, structural rules, not suggestions. They are derived from the **posts / feed page**, the reference implementation and the most structurally and visually correct page in the application. Other pages are refactored to match it; new pages follow these rules from the start.
The header, breadcrumb, content root, and footer are *shared infrastructure*. A page supplies its content and its stylesheet; it never rebuilds the frame.
## The reference skeleton
This is the posts page reduced to its structure. A content page looks like this and nothing else:
The header, breadcrumb, `<mainclass="page">` wrapper, and footer are all supplied by `base.html`. The template above never appears to contain them, and never should.
## Hard rules
### 1. Extend the base template
Every page is `{% extends "base.html" %}`. Page CSS is added only through `{% block extra_head %}`; page JS only through `{% block extra_js %}`. A page never includes its own `<html>`, `<head>`, or `<body>`, and never links `variables.css` / `base.css` / `components.css` (the base already does).
### 2. The header is shared, never re-implemented
The top nav is `base.html`'s `.topnav`. Pages do not build their own header or navigation bar; the active link is derived from the request path inside `base.html`. A page-level toolbar (tabs, filters) lives *inside the content*, like the feed's `.feed-nav` strip, below the breadcrumb, never as a second site header.
### 3. Breadcrumbs are mandatory (this is the most-broken rule)
A page **must** pass at least two breadcrumbs (Home plus the current page) through its SEO context:
This is primarily for SEO and orientation. Clearing the fixed top nav is handled once, globally, by `body { padding-top: var(--nav-height) }`, so a page is never hidden behind the header whether or not it has a breadcrumb. Still supply two or more crumbs on any nested page for navigation and breadcrumb structured data.
### 4. All content lives in the single content root
`base.html` already wraps the `content` block in `<mainclass="page">` (`max-width: 1200px`, centred, `padding: 1rem`). Therefore a page:
- puts everything inside one top-level layout container (a grid like `.feed-layout`, or a single column);
- never adds a second centred / `max-width` wrapper inside `.page`;
- never re-declares the maximum content width.
See [Layout](/docs/styles-layout.html) for the approved layout containers.
### 5. Multi-column structure is grid, and it collapses
Side columns are `<aside>`; the fluid centre column sets `min-width: 0`. The grid collapses to a single fluid column at `1024px` and the right rail is hidden. See [Responsiveness](/docs/styles-responsiveness.html).
### 6. One H1 per page
Each page has exactly one `<h1>`. When the heading is visually redundant (the feed's title), keep it for accessibility with `class="sr-only"` rather than removing it.
### 7. The footer is shared
The footer is `base.html`'s `.site-footer`, rendered from the `footer` block. Pages do not build their own footer. Override the `footer` block only with a deliberate reason (for example, a full-bleed tool page) and document why.
### 8. Cards and surfaces use tokens
Content sits on cards built from tokens: `--bg-card`, a `--border` hairline, `--radius-lg`, `1rem` padding (the shared `.card` recipe). Colours, spacing, radii, shadows, and z-indexes are always tokens, never literals: global tokens are referenced bare (`var(--accent)`, never `var(--accent, #hex)`), accent tints compose `rgba(var(--accent-rgb), α)`, and stacking uses the `--z-*` scale. See [Colors](/docs/styles-colors.html) and [Layout](/docs/styles-layout.html).
## Page author checklist
- [ ] `{% extends "base.html" %}`; CSS via `extra_head`, JS via `extra_js`.
- [ ] Two or more breadcrumbs passed in the SEO context (content clears the nav).
- [ ] Exactly one layout container inside `.page`; no second `max-width` wrapper.
- [ ] Multi-column = grid with `<aside>` rails, fluid column has `min-width: 0`, card-grid tracks are `minmax(0, 1fr)`, collapses at `1024px`.
- [ ] One `<h1>` (use `.sr-only` if visually redundant).
- [ ] No custom header or footer; both come from `base.html`.
- [ ] Only tokens for colour, spacing, radius, shadow, and z-index; no `var()` fallback values.
- [ ] Standard breakpoints only (`1024 / 768 / 480 / 360`).
- [ ] No page-level `prefers-reduced-motion` query unless the page must change content, not just motion (the global `base.css` rule already covers motion).