{% 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:
```html
{% extends "base.html" %}
{% block extra_head %}
<link rel="stylesheet" href="{{ static_url('/static/css/feed.css') }}">
{% endblock %}
{% block content %}
<h1 class="sr-only">Feed</h1>
<div class="feed-layout"> {# exactly one layout container #}
<aside class="sidebar-card"> ... </aside>
<div class="feed-main"> ... </div>
<aside class="feed-right"> ... </aside>
</div>
{% endblock %}
```
The header, breadcrumb, `` 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 ``, ``, or ``, 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:
```python
seo_ctx = list_page_seo(
request,
title="Projects",
breadcrumbs=[{"name": "Home", "url": "/feed"}, {"name": "Projects", "url": "/projects"}],
)
```
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 `` (`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 `
Anatomy of a page (what base.html owns vs what the page supplies)
DevPlace · Home Posts News Gists Projectsbase.html: .topnav (fixed)
Home / Projectsbase.html: .breadcrumb (clears the nav)
Your content, inside one layout container.page: block content, inside .page