Layout Components
Header
Not a shared component (unlike the footer) — most of the header still differs per repo (nav links, session controls, or nothing at all). Four distinct shapes, by auth state and width, share the wordmark sizing rules below.
Family header — shared rules, and (as of 6 Aug 2026) one shared component
Each site's header content still does a different job — the Website has marketing nav, Pets and Connections have session controls because they're logged-in apps, Rissbrook has neither. Forcing identical content onto all four would mean inventing UI that has no purpose on the sites that don't need it — a login button on Rissbrook, marketing nav on Pets — and that part hasn't changed.
What has changed: both the Pre-Auth Header and the Post-Auth Header are now literal shared components, the same way the footer lockup is — §1.1 and §1.2 below.
The Pre-Auth Header took building it against a real second implementation (Website, 6 August 2026) to find that the shape genuinely doesn't vary — a centred wordmark with nav beneath it on desktop, a sticky compact bar with a burger on mobile — only the specific nav/login content placed inside it does.
The Post-Auth Header was promoted on different grounds, 6 Aug 2026, on
the same day as its first real implementation (Connections' App.jsx)
rather than waiting for a second one to confirm the shape. Its session
actions used to just wrap onto extra lines at narrow widths, which still
measured a real page-width overflow — the fix reuses the Pre-Auth
burger/drawer CSS directly (.family-header-burger/
.family-header-drawer/.family-header-drawer-backdrop — §1.1, §6)
rather than inventing new mechanics, and the wordmark sizing is the exact
28px/22px pairing the Pre-Auth mobile bar already establishes — nothing
about the shape was actually new or Connections-specific, only the
application of an already-shared pattern to a header that happens to
show session controls instead of a login link. Pets is the next repo
expected to adopt .family-header-postauth (§2's table below), not yet
done — the class name and CSS exist regardless, the same as any other
component in this system a repo hasn't wired into yet. Same idea as
tools/tokens/*.tokens.json — the values are shared, what wraps them
usually waits for a second implementation to prove the shape, except
where — as here — the shape was already proven by something else first.
Decided 4 August 2026, in the same pass as the footer's type-size increase —
see docs/family-wordmark.md §2 for why the wordmark grew from 13px/7.8px
in the first place. This doc is the direct consequence: once the footer
wordmark got bigger, "the footer is never bigger than the header" meant the
header had to grow to match.
The wordmark's own mechanics — weight, tracking, colour rule, alignment,
the two link behaviours — live in
docs/family-wordmark.md, not here. What follows is
only what's specific to the header: its size relative to the wordmark's
base, and that it always links to the current site's own root.
1. The wordmark
+4px name / +3px suffix over the wordmark's base — 24px/19px base
(family-wordmark.md §2) becomes 28px/22px in the header. Expressed as
an offset, not a restated absolute number, so that if the base ever changes
this changes with it rather than quietly drifting out of the relationship —
same reasoning as --brand-* tokens living in one JSON file. Left-most
element in the header, always.
This is why the header changed at all: the footer's size increase (needed
so every product's accent could be one fixed colour, no dark variant —
family-footer.md §2) would otherwise have left the footer wordmark bigger
than the header's, which reads backwards — the header is the primary mark,
the footer a recap of it, and the recap was not supposed to outsize the
thing it's recapping. Matching them exactly was tried in an earlier draft of
this doc and was wrong: "never bigger than" means the footer has a ceiling,
not that the two have to be identical. The footer sits at its floor; the
header sits above it.
Always the self-link case (family-wordmark.md §6) — the header
wordmark links to the root of the current site (/, not amoleo.com;
each product links to its own home), plain text with nowhere to link to on
the home page itself, no decoration in any state. Rissbrook's header
already does exactly this (Header.astro); the rest of the family adopts
it rather than each inventing its own version.
Two states, not three — and Connections is the reference
Corrected 4 Aug 2026: the login/register form is not its own state. It's part of Pre-Auth, embedded in it — Connections already builds it exactly this way, and Connections is the pattern the rest of the family adopts, the same role the Website plays for the footer.
Renamed 6 August 2026: "App-shell" is now Post-Auth Header, and "Pre-auth" is now Pre-Auth Header — the user's own names, adopted throughout this doc since they say plainly which side of authentication each one belongs to, which "app shell" didn't (Website and Rissbrook have no login at all, so calling their permanent header "app shell" alongside Pets/Connections' post-login one was always a slight misnomer).
The auth card's own mechanics — its structure, states and colour rule —
now live in docs/family-auth-box.md, not here,
split out the same way the wordmark's own mechanics were split into
family-wordmark.md. What follows is only what's specific to placing that
card inside a page: where it sits relative to the header, and how its
wordmark scales between the two states.
- Post-Auth Header — logged in. Wordmark left-aligned, 28px/22px, per the rule above.
- Pre-Auth Header — everything before you're signed in: the marketing
content and the login/register form, one state, not two screens.
Modelled on Connections' actual implementation:
- Desktop:
.family-header(hero, wordmark much bigger than Post-Auth — +12px name / +3px suffix over the wordmark's base, i.e. 36px/22px, matching what Pets already does on its own auth screen) sits above the pitch;.landing-authholds the login/register.auth-card, centered in the page, under the hero — not a separate screen, not a modal. - Mobile: the hero and in-page form (
.family-header,.landing-auth) disappear entirely. A compact sticky.family-header-bartakes over — wordmark at the standard Post-Auth size (28px/22px, not the hero size, and not Connections' pre-6-Aug 15px, which was smaller than the family now allows anywhere), with a "Sign in" toggle at the right edge. Tapping it drops down.family-header-panel, the same.auth-cardform, as a sticky pop-down panel rather than a page navigation. (Renamed onto these shared class names 6 Aug 2026 — was.landing-header/.landing-bar/.landing-bar-panel, matching the shared component's own names now that Connections is wired into it, family-css-system.md.)
- Desktop:
Website and Rissbrook show the Pre-Auth Header permanently — neither ever authenticates anyone, so neither ever switches to Post-Auth. Not "N/A" the way an earlier version of this table put it: Website is the one repo that shows nothing else, which is exactly why it's the shared component's reference implementation for this state (§1.1 below) rather than an exception to it.
| Repo | Has a Pre-Auth state? | Matches the Connections pattern? |
|---|---|---|
| Website | Yes — permanent, reference for the shared component | Adapted: real nav links Connections has none of; see §1.1 |
| Rissbrook | Yes — permanent, adopted 6 Aug 2026 | Adapted: no nav and no login, so neither element renders — §1.1's "a repo with neither omits both" |
| Connections | Yes | Reference implementation for the auth-card placement |
| Pets | Partial — form only, no hero/pitch, no mobile pop-down | No — recorded as owed work below |
| Accounts | Yes — two shapes on two routes, adopted 27 Aug 2026 | /interaction/:uid (Landing.jsx) matches exactly, per Decision 9; bare / (RootPage.jsx) is Rissbrook's "neither" case instead — no client_id/interaction there for a login control to open (Amoleo-Accounts/docs/Decisions.md #14) |
Decided 4 Aug 2026: Pets moves onto the Connections pattern wholesale — gains the hero/pitch content it currently has none of, and the desktop in-page-form / mobile pop-down-panel structure, rather than its current single centered card at every width. This is a bigger change than header styling (real new content, a new mobile interaction), recorded here as a decision, not implemented as part of this spec.
Connections' login/register component becomes the canonical one — not
just for Connections. Once Accounts ships a hosted sign-in screen, that
screen adopts this same pattern (hero, in-page form on desktop, sticky
pop-down on mobile) rather than inventing its own or copying Pets' single
centered card. Recorded as a decision in
Amoleo-Accounts/docs/Decisions.md — see that file for the reasoning
against the alternative (Pets' pattern, or something bespoke to Accounts).
1.1 The Pre-Auth Header is now a literal shared component
Unlike the rest of this doc — values and decisions a repo's own markup
follows, not a file it copies — the Pre-Auth Header is, as of 6 August
2026, one shared component:
tools/family-css/components/header.css,
compiled into family-css/base.css and copied verbatim into every wired
repo. See docs/family-css-system.md. This
reverses what this doc originally said ("the header is not one component
copied into every repo") for this one state, on the reasoning that the
shape — a centred wordmark on desktop with nav beneath it, a sticky
compact bar with a burger on mobile — doesn't actually vary by repo, only
the specific nav/login content inside it does, the same relationship the
footer lockup already has to --brand-*.
.family-header / .family-header-brand / .family-header-nav
(desktop, >768px) — centred, not sticky, 36px wordmark, a small muted
nav row beneath it. Matches Connections' own .family-header exactly (the
same class, not just the same shape — Connections renders onto it
directly rather than a repo-specific name), plus the nav row Connections
doesn't need (it has none) but Website does — nav links don't disappear
from this state, they sit secondary to the mark rather than gone.
.family-header-bar / .family-header-bar-brand / .family-header-login
/ .family-header-burger / .family-header-drawer /
.family-header-drawer-backdrop (mobile, ≤768px) — sticky, 28px
wordmark left. What the bar holds, and its shape, depends on what a repo
actually has:
- Burger only, no login (the Website): one 64px row — wordmark left,
burger right,
justify-content: space-between— the original single-row shape. - A login control present (Connections, and any future repo with
auth): the bar stacks into two rows instead — wordmark on its own
row,
.family-header-loginfull-width on the row below. Found live 6 Aug 2026 wiring Connections in: "AMOLEO · CONNECTIONS" plus a sign-in control sharing one 64px row measured 102px over budget on a 375px phone — dropping the product name to make room was considered and rejected, the name has to stay everywhere. The CSS switch is.family-header-bar:has(.family-header-burger):not(:has(.family-header-login))forcing the single-row shape back on for the burger-only case; a repo with both a burger and a login (nav plus auth, not built anywhere yet) still gets the two-row stack, since the login control is what needs the room, regardless of whether a burger is also present. - A repo with neither omits both elements from its markup rather than rendering either empty.
.family-header-login is an accent-coloured outline, not a filled
pill — changed from an early solid background: var(--accent) version
matching Connections' own then-current .landing-bar-toggle exactly,
because that filled shape read as too heavy sitting alone on its own row
directly under the wordmark, once the two-row stack replaced the
single-row layout it was designed for. The outline (border: 1px solid var(--accent); background: transparent; color: var(--accent)) keeps the
accent colour — still the bar's one call to action — without a solid
block competing with the wordmark for visual weight. A fully neutral
outline (no accent colour at all) was tried and rejected too: it lost the
"this is the actionable thing" signal the colour carries.
Website is the reference implementation for this component — built
6 August 2026, replacing its own .site-header/.header-inner/
.site-brand, including the burger/drawer mobile nav §6 already called
for but no repo had actually shipped yet (tools/header.json's
Amoleo-Website.adopted was false for exactly this reason, now true).
Connections is the reference for the login-control shape and the two-row
stack specifically, added 6 Aug 2026. Where this section and the code
disagree, the code is right — same rule family-footer.md already states
for the Website and the footer lockup.
- 64px minimum height for the single-row (burger-only) shape. The two-row shape has no fixed minimum — its height is two rows' worth of content plus the bar's own padding and inter-row gap, which varies with how tall the login control's own font/padding render.
- 44×44px minimum tap target on every interactive control (button,
burger, login) — the same WCAG 2.2 AA target size the footer's stacked
rows already use. Pets' old
--header-control-height: 30pxno longer fits a 28px wordmark comfortably and is retired in favour of this.
1.2 The Post-Auth Header is now a literal shared component too
.family-header-postauth — 28px/22px wordmark left, an optional
.tagline beneath it, .family-header-actions right (a "signed in as…"
label plus button-styled actions). Sticky is still a per-repo decision
(§3), not part of this shape.
.family-header-actions.wide-only — the desktop inline row, hidden
below 768px in favour of a duplicate copy inside the shared
.family-header-drawer, opened by the same .family-header-burger the
Pre-Auth Header uses. .wide-only/.narrow-only are generic
visibility-swap utilities in primitives.css now, not specific to either
header — Connections also uses .narrow-only on an unrelated drag
handle.
The wordmark shrinks specifically when a burger is present and the 28px/22px pairing doesn't fit beside it — 22px/17px, with its own measured correction, distinct from the standard pairing's. Measured against a real overflow (16.9px past the edge of a 375px phone, "AMOLEO · CONNECTIONS" needing 347.9px of the 293px actually available once padding, gap and the 44px burger are accounted for) — a header with no burger (PublicBoard.jsx's lighter, session-free variant) keeps the standard size, since there's nothing to make room for.
No nav content, ever — a Post-Auth Header's burger, where one exists, opens the drawer to show more of the same session actions, not navigation (§6's nav-collapse table is a different, Pre-Auth-only concern). A repo with genuine in-app navigation to collapse on a phone would need a third pattern; none of the family's apps have needed one yet.
3. Sticky — a per-repo decision, not a shared rule
Website is the one entry that needs two answers, not one — its
Pre-Auth Header has two structures at different widths (§1.1), and they
disagree: the desktop .family-header is deliberately not sticky
(matching Connections' own .family-header), while the mobile
.family-header-bar is (matching Connections' own .family-header-bar).
This isn't a contradiction to reconcile — it's the shared component's own
fixed behaviour, not a per-repo choice the way the table below covers for a
single-structure Post-Auth Header.
| Repo | Sticky | Why |
|---|---|---|
| Website | Desktop: no. Mobile: yes. | Pre-Auth Header's own fixed shape (§1.1) — not a per-repo choice here |
| Pets | Yes | Post-Auth Header — the header's controls stay reachable while scrolling a long pet list |
| Connections | No | Was already not sticky; unchanged |
This table is Post-Auth Header stickiness specifically — a genuine
per-repo choice check-brand.mjs-style tooling should not enforce
identically, which is why it's recorded here rather than left to drift
toward whatever the rest of the family happens to do. Rissbrook doesn't
belong in it: it has no Post-Auth Header at all (§1, "Two states, not
three" — Rissbrook never authenticates anyone), and its Pre-Auth Header's
stickiness is fixed by the shared component itself (§1.1: desktop not
sticky, mobile sticky), the same as Website's row above, not a choice
recorded per repo. An earlier version of this doc had Rissbrook's header
"deliberately non-sticky, reversed by decision" here as if it were a
Post-Auth-style per-repo choice — that was true of its old bespoke
.site-header (unconditionally sticky at every width, changed 4 Aug
2026), retired 6 Aug 2026 when Rissbrook adopted the shared Pre-Auth
Header component (§1.1) in place of that bespoke markup.
4. Links vs. buttons
The rule, not invented fresh — Connections' header already drew this line correctly and the rest of the family adopts it:
- Navigates (a URL, an anchor, a section of the same page) → plain text
link. No background, no border. Colour shifts on hover; nothing else
does. (Website's
.site-header nav a—--muted→--text-strong— is the reference.) - Performs an action (sign out, submit, toggle a panel) → bordered
pill button. Padding, 1px border, background fill,
border-radius. (Connections'button.secondaryis the reference.)
Both take each site's own theme tokens — this is one shared shape, themed per site, not one neutral colour painted over every app. The relationship is the same one the footer's product colours already have to the wordmark: shared structure, local colour.
The wordmark itself is the one exception to this rule — it's an <a>
that navigates, but isn't styled as a link. See §1.
5. Login / session control
- Always the right-most element in the header, on any site that has one at all.
- One shared visual definition — same padding, radius, border weight, font-size as the button rule above — across every site that has it. Only the colour (site's own accent) and the label differ ("Sign in" logged out; the user's name + a sign-out action logged in).
- Absent entirely on Website and Rissbrook. Neither has a login system. Nothing renders in its place — not a disabled button, not a placeholder. This stops being true only once Accounts ships SSO across the family.
- Below 768px, when the session controls no longer fit beside the
wordmark, they move behind a burger —
.family-header-postauth, §1.2. Username, Settings and Sign-out used to wrap onto extra lines at narrow widths on Connections'App.jsx(where this shipped first, 6 Aug 2026), which still measured a real page-width overflow on a 375px phone. A.family-header-actions.wide-onlyinline row (desktop) and a duplicate copy inside the shared.family-header-drawer(mobile) — the same duplicated-not-moved idiom §6's Pre-Auth nav already uses, and the same shared drawer CSS, just holding session actions instead of nav links.
6. Mobile nav — burger, off-canvas, one breakpoint
Only a site with actual nav content to collapse gets a burger. A wordmark-only header (Rissbrook) or a header with no navigational links (Connections' session buttons don't count — see §4, they're actions, not navigation) gets no burger and no mobile menu at all; there is nothing to hide.
| Repo | Burger? | What it collapses |
|---|---|---|
| Website | Yes — shipped 6 Aug 2026 | Work, Luke Bickley (its two nav links), via .family-header-drawer — see §1.1 |
| Pets | Yes | Its session/header-right controls |
| Connections | No | No nav links exist in the header to collapse — but see §5 for a different burger, in its Post-Auth header, collapsing session actions instead of nav |
| Rissbrook | No | No nav links exist — .family-header-bar's default single-child layout already reads as one clean row with neither a burger nor a login control rendered, per §1.1 |
Pets' row above no longer matches this table's own note below it as of
6 August 2026 — while building Website's version, Pets turned out to
already have .header-drawer/.header-drawer-backdrop
(client/src/App.css, ~line 659–719): a fixed, translateX-based
off-canvas panel with a backdrop, strikingly close to this spec already,
not the in-place max-height expansion the note below still describes.
Left as found — reconciling which parts of Pets' implementation are
current and which are stale is Pets' own wiring pass into this system
(docs/family-css-system.md §5), not established by reading the CSS once
in passing here.
Where a burger exists:
- Breakpoint:
max-width: 768px, everywhere. 768px itself is still mobile (burger visible); the switch to full nav happens at 769px. Pets' existing value; Connections moves from 780px to match. - Icon sits at the right edge — the same corner the login/session control occupies, so that corner has one consistent job at every width. Where both exist, the login control stays visible and the burger sits beside it; the burger never replaces or hides the login control.
- Opens an off-canvas panel sliding in from the right, backdrop behind
it, ~280px wide. Not a downward
max-heightreveal. This is a real behaviour change for Pets, whose burger currently expands.header-rightin place rather than opening a panel — it moves onto the same mechanism its own pet-list sidebar (.panel/.panel-open) already uses, so the app isn't carrying two different off-canvas patterns. - The login/session control is never hidden inside the drawer. The burger only ever hides secondary nav links; the single most important control stays reachable at every width.
7. What to check afterwards
- A Post-Auth Header's wordmark is 28px/22px bold — bigger than the
footer's 24px/19px, never equal to it — left-most, same colour rule as
the footer (
--brand-amoleofor the family name, the site's own token for the suffix). A Pre-Auth Header's desktop wordmark is 36px/22px instead (§1.1) — its own mobile bar drops to the same 28px/22px a Post-Auth Header uses. - The wordmark links to
/on every page except the home page, where it's plain text. In no state does it show an underline or a hover/focus background — only the standard:focus-visiblering for keyboard users. - Header bar is at least 64px tall on every repo; every button/burger/login control measures at least 44×44px.
- A link never has a background or border; a button/action always does, in the site's own theme colours.
- The login/session control (where one exists) is the right-most element, and identical in shape (not colour) across Pets and Connections.
- Below 768px, Website and Pets show a burger that opens a slide-in panel
from the right with a backdrop; Connections and Rissbrook show no burger
at any width. On Website specifically, the desktop centred header
(
.family-header) disappears entirely below 768px — it doesn't shrink or reflow,.family-header-barreplaces it outright (§1.1). - Rissbrook's desktop
.family-headeris not sticky, matching Website and Connections; its mobile.family-header-baris sticky, matching every other adopted repo — the Pre-Auth Header's own fixed shape (§1.1), not a per-repo choice, now that Rissbrook adopted the shared component (6 Aug- in place of its old unconditionally-sticky bespoke header.
Generated from docs/family-header.md + tools/header.json + tools/family-css/components/header.css. Edit there and re-run npm run build in docs-site-src/ — never hand-edit a page.