AmoleoFamily

Layout Components

Live — enforced by check-lockup.mjs

Amoleo Pets Connections Rissbrook Accounts

Simulated on a page that isn't any one product's own site (all four render as cross-links). Order is fixed — oldest first, Accounts last, no status label. Separators are aria-hidden.

Non-Live — registered, no footer requires this yet

Amoleo Todo Editions Upnext Collections Reviews Worldbook Health

Not a real footer anyone renders — a preview of the order these would join in, once promoted (node tools/promote-to-lockup.mjs). See Product Order.

Live — mobile (≤560px)

A genuinely different layout below 560px, not the row above just narrower — .family-mark-wrap switches to display:block and each name becomes its own full-width, thumb-sized row.

Amoleo
·Pets
·Connections
·Rissbrook
·Accounts

Rows are 44px, the WCAG 2.2 AA target size — not the 40px the Website currently ships (the spec's own note: the Website is the one that should change, not the target). “Amoleo” gets its own row first, same order otherwise.

Compact — for space-constrained pages

Connections' SiteFooter compact prop is the reference — a page where something else (a map, a canvas, an editor) genuinely needs the vertical space back, not a default and not a reaction to the full footer merely looking big.

Amoleo Pets Connections Rissbrook Accounts

TMDB attribution notice (required, never dropped) · © Amoleo. All rights reserved.

Allowed to drop: supplementary prose only — a data-sources sentence, extra attribution. Never drops: the lockup in full (all products, correct order, aria-hidden separators), any required third-party notice, or the copyright line. The lockup is reordered first via order: -1, not moved in the document — single line above ~1370px, folding to lockup-then-(notice+copyright) from there down to the 1025px floor shown above.

Lockup adopted

Whether the repo's own live footer actually ships the current-shape lockup — repos.json's adopted field, separate from being listed in lockup.json at all.

RepoAdopted
Amoleo-WebsiteYes
Amoleo-RissbrookYes
Amoleo-PetsYes
Amoleo-ConnectionsYes
Amoleo-AccountsYes
Amoleo-Todo
Amoleo-Editions
Amoleo-Upnext
Amoleo-Collections
Amoleo-Communications
Amoleo-Reviews
Amoleo-Images
Amoleo-Registry
Amoleo-Recommendations
Amoleo-Worldbook
Amoleo-Health

Family footer — the shared lockup

The footer lockup carried by every Amoleo site. It lives here, in the umbrella workspace, because it belongs to no single app — it began as a note inside Amoleo-Pets, where it was gitignored and so untracked, which is the one place a cross-repo spec should not be.

Amoleo-Website is the reference implementation. Where this document and that code disagree, the code is right and this should be corrected.

The wordmark's own mechanics — size, weight, alignment, colour rule, link behaviour — live in docs/family-wordmark.md, not here. This doc covers what's specific to the footer: the lockup's structure, order, per-product colour values, and the compact variant. Where the two used to say the same thing twice, the wordmark doc is now the one copy.

The literal CSS in §3 and §6 now lives in tools/family-css/components/footer-lockup.css, compiled into family-css/base.css and copied verbatim into every wired repo — see docs/family-css-system.md. This doc is still the record of why; that file is the one copy of the literal rules.

Two checkers enforce this document across all five repos, from machine-readable copies of what it says: tools/tokens/base.tokens.json for the colours in §2, and tools/lockup.json for the order, hosts and structure in §1 and §5. Change a value in the JSON and in the prose in the same commit. Run both after touching brand CSS or a footer anywhere:

node tools/check-brand.mjs
node tools/check-lockup.mjs

check-lockup --strict also fails on the repos still shipping the two-name version, which §0 lists.

The goal: one lockup, five names —

Amoleo · Pets · Connections · Rissbrook · Accounts

One "Amoleo" shared rather than repeated, each product name in its own colour, each linking to its own site. The site you're currently in is not a link, because there's nowhere for it to go. On a phone the rows stack full-width so each is a thumb-sized tap target.

The family name is the one part that never varies. "Amoleo" is the same neutral ink on every site — see §2 — and only the product name after it carries colour.

The point of the exercise: a bare Amoleo · Pets link next to a copyright line read as though the copyright belonged to Pets. Separating the family lockup from the copyright fixes that, and gives every app a visible relationship to the others.


0. Status — who ships what

Repo Site Ships the lockup?
Amoleo-Website www.amoleo.com Five names.
Amoleo-Pets pets.amoleo.com Five names. 4 Aug 2026
Amoleo-Connections connections.amoleo.com Five names. 4 Aug 2026
Amoleo-Rissbrook www.rissbrook.co.uk Five names, plus the header wordmark. 1 Aug 2026
Amoleo-Accounts accounts.amoleo.com Five names. 27 Aug 2026

All five apps now ship the five-name lockup (see Amoleo-Family/CLAUDE.md — commits stayed per-repo, one per app).

Two things Rissbrook established that the others should follow rather than re-decide:

Pets established a third, 5 August 2026:

1. The apps, in order

Order is fixed across every site — oldest first, with Accounts last as the infrastructure the others will sit on.

key Name href Accent
pets Pets https://pets.amoleo.com/ terracotta #D9603F
connections Connections https://connections.amoleo.com/ cyan-blue
rissbrook Rissbrook https://www.rissbrook.co.uk/ teal #2F7994
accounts Accounts https://accounts.amoleo.com/ slate grey #6E7178

Pets' accent is #D9603F as of 6 August 2026, superseding #c45032. The new value matches what pets.amoleo.com itself actually ships — #c45032 was the family's own approximation of Pets' terracotta, not a colour lifted from the live site, and the two had drifted apart. Amoleo-Pets's own App.css already carries #D9603F; the family's token source (then brand-tokens.json, now tools/tokens/base.tokens.json — see docs/family-css-system.md) was updated in the same move. Rissbrook and Connections still carry the old value and will report as diverging until they're updated — same situation as the Rissbrook teal swap below, and the same fix: update the token, not override it locally.

One side effect worth knowing about, not yet acted on: the Website's --brand-pets-ink (family-wordmark.md §7) — a deliberately different, AA-nudged terracotta used only for its product-heading text — has a dark value of #d9603f, which is now identical to the new --brand-pets itself. The exception isn't wrong, but half of what it was compensating for may now be moot; worth a look next time that heading is touched, not urgent on its own.

Accounts carried no fixed colour until 4 August 2026 — it took each site's own muted-text colour (--muted / --text-light) back when it was pure unshipped infrastructure rather than a product with its own identity. It now has a real, boring, fixed grey like every other product's accent, for the same reason as the rest of this section: a colour that changes per site is not a family colour.

Todo has a colour (#8A6D1A, olive gold) but is not in the lockup yet. It is recorded in tools/tokens/base.tokens.json as --brand-todo so it exists when Todo ships, but adding a fifth product to the lockup is its own decision — order, and whether it follows Accounts' "linked before it resolves" precedent — not a side effect of picking its colour.

Accounts is linked even though the host does not resolve yet, and carries no "in development" label. The family reads as four products rather than three and a placeholder, and the link needs no revisiting when the host comes up. The trade is a dead link until then — accepted deliberately, not overlooked.

A product is never named bare. In the footer it is the full Amoleo · Pets. In body copy the short form is allowed — "Visit · Pets" — but the separator is not optional, because it is what ties the name to the family. "Visit Pets" is the thing this rule exists to prevent.

Inline mentions borrow the wordmark's uppercase, 0.10em letterspacing and weight, but not its sizing: they sit at the size of the words either side of them, not at 0.6em. They must also be ordinary inline text — the wordmark proper is display: flex, and nesting it inside an inline-flex link in a narrow column breaks the verb, the name and the arrow onto three separate lines.

The separator takes the app's accent; the name itself inherits the link colour, so the link still reads as a link and so the name is not held to whatever contrast the accent happens to have at body size.

Rissbrook's accent is #2F7994 as of 5 August 2026, superseding #183D4A (itself settled 1 August 2026, superseding the provisional #2f6b4f). All three are from Robert Bickley's own our-family-blue.css — this is still his palette, not a hue assigned to fill a gap — but #183D4A (his "dk teal", the background of every page he wrote and the colour of every heading, recorded as Amoleo-Rissbrook's ADR-008) turned out to measure 1.63:1 against the family's dark background: it fails WCAG AA at every text size, not a size-dependent problem the footer's larger type could fix. See "History" in §2 below for how that got missed the first time.

#2F7994 is "Side Bar Header" from the same stylesheet — not invented, still something he actually used, just a different rule in the same file — and it's the one colour in his blue palette that clears the WCAG large-text bar (3:1) on both the family's light and dark backgrounds at once, which is what lets it stay one fixed value rather than needing a per-theme override the way #183D4A would have. Two other candidates from the same palette were checked and rejected: "Header Bar" #CBDDE4 clears dark beautifully but fails light at 1.31:1 (Rissbrook's own site is light-only, so that's not a secondary context — it's the primary one); "Side Bar" rgb(99,155,175) clears dark but just misses light at 2.87:1.

It sits at hue ~197, close to Connections' ~195 — the two are separated by lightness and saturation rather than hue, which is a weaker distinction than the other pairs have. Accepted: provenance beats palette spacing here, and no site shows the two names in isolation from the rest of the lockup.

Amoleo-Website carried #183D4A from 1 August 2026 (along with its OG card) until the 5 August fix. Pets and Connections never carried a Rissbrook colour before going to five names; both picked up #183D4A as part of that move (4 August 2026) and need the same swap to #2F7994 in their own repos — check-brand.mjs will report them as diverging from the family's token source until they do.

2. The colours

Every product's accent is one fixed value, not a light/dark pair — decided 4 August 2026. --brand-amoleo is the one exception, because it is genuinely two different inks (near-black on light, white on dark), not a product accent that happens to need adjusting per theme.

:root, [data-theme="dark"] {
  --brand-amoleo:      #1c1c2e;  /* dark; #ffffff in [data-theme="dark"] — the one exception, see above */
  --brand-pets:        #D9603F;  /* was #c45032 until 6 Aug 2026 — see §1 */
  --brand-connections: #0b6e8f;
  --brand-rissbrook:   #2f7994;  /* his "Side Bar Header" — see §1 */
  --brand-accounts:    #6e7178;  /* "slate grey" — see §1 */
  --brand-todo:        #8a6d1a;  /* "olive gold" — not shipped yet, see §1 */
}

Until 4 August 2026, Connections and Rissbrook each had a second, lighter value for [data-theme="dark"] (#3fb6dc, #98bdca), because their light values don't carry enough contrast on a dark ground on their own. Rather than keep inventing a second hex per colour per theme, the footer's type got bigger and bolder instead (§6) — large enough to clear WCAG's large-text contrast bar (3:1) instead of the normal-text one (4.5:1). That policy holds for Pets, Connections and Accounts, each of which clears 3:1 against both a white and a near-black background at this size. It did not, in fact, hold for the #183D4A Rissbrook shipped with on 4 August — see "History" below — which is why Rissbrook's value changed again on 5 August rather than the policy being reopened. The theme accommodates the colour; the colour doesn't change per theme, and now genuinely doesn't for all four. This is the approach Pets' --brand-pets used from the start — a single terracotta, unapologetically the one colour that fails the old 4.5:1 bar in dark mode at the old, smaller size — generalised to the rest of the family rather than kept as its one exception.

"Amoleo" takes --brand-amoleo, not the site's strong text colour — the wordmark doc's colour rule (§4), stated here because of what happened the one time a repo didn't follow it. This is the one rule the lockup cannot bend, because the family name is the part that has to look identical on five sites for the lockup to read as one mark. It matters most where an app's own brand colour is also its text colour: Rissbrook carried --text-strong: #183D4A and so rendered AMOLEO and RISSBROOK in the same teal, losing the two-tone step and tinting the shared half of the mark with a colour that belongs to one site. Fixed 1 August 2026 (Luke).

The values are the Website's existing ink, so nothing moves there. Pets and Connections both now define the token rather than leaving the wordmark on --text-strong; in Pets in particular that would have tied the family name to whichever of the nine cat themes is active.

History: Rissbrook needed a second Dark value, then needed a new value entirely. #183D4A is 11.9:1 on white and 1.63:1 on #101013 — unreadable on a dark ground, and that number does not change with font size: contrast ratio is fixed by the two colours involved, only the required bar changes with size (4.5:1 normal text, 3:1 large text). Until 4 August 2026 [data-theme="dark"] carried #98bdca instead, his palest teal, 9.5:1 on #101013, specifically to work around this.

The 4 August single-colour policy got this one wrong. It retired #98bdca on the reasoning that the footer's larger, bolder type (§6) was "what makes #183D4A itself work on dark — 5.9:1 at the new size, comfortably past the 3:1 large-text bar." That 5.9:1 figure was never real — recomputing it directly gives 1.63:1, the same number as above, because a type-size increase cannot change a fixed pair of colours' contrast ratio, only which bar applies to it. #183D4A fails even the loosened 3:1 large-text bar, so the footer was shipping unreadable Rissbrook text on every dark-themed page in the family between 4 and 5 August. Fixed by replacing the value itself, #2F7994, rather than by retrying the type-size argument — see above. Rissbrook's own site is light-only (Luke, 1 Aug 2026), so none of this ever affected it directly; it existed for the Website, Pets and Connections.

History: Pets' terracotta in Dark. #c45032 on #101013 was 4.11:1. At the lockup's old 7.8px (13px × 0.6em) that failed WCAG AA for normal text — the one colour in the lockup that did, flagged 31 July 2026. The fix that shipped 4 August 2026 wasn't a lightened Dark value; it was the same type-size increase that resolved Connections and Rissbrook — 4.11:1 clears the 3:1 large-text bar the new size qualifies for, so the colour didn't need to change at all then.

#D9603F (6 August 2026) shifts the numbers rather than removing the question. It's 3.69:1 on white and 5.15:1 on #101013 — lighter and more saturated than #c45032, so the trade flips: worse on a light ground, better on a dark one. Both figures still clear the 3:1 large-text bar the footer's 19px bold qualifies for; neither clears 4.5:1 normal-text on its own (the white figure isn't close). Same policy as the rest of §2 — the type size is what makes this colour work at lockup scale, not the hex — but it's worth re-checking anywhere Pets' terracotta renders at body text size against a light background, since that combination has never cleared AA at either value.

One note per repo:

3. Two existing rules have to accept a per-app colour

.brand-wordmark .brand-dot and .brand-wordmark .brand-suffix currently hard-code a single accent. They need a variable a wrapper can override, falling back to exactly what they do now — so nothing else changes:

.brand-wordmark .brand-dot    { color: var(--wordmark-accent, var(--accent)); }
.brand-wordmark .brand-suffix { color: var(--wordmark-accent, var(--accent)); }

In Pets the fallback is var(--secondary) rather than var(--accent). Leave every other property in those rules alone.

The rule they hang off takes the family colour rather than the site's:

.brand-wordmark { color: var(--brand-amoleo); }

4. The component (React — Pets, Connections)

client/src/components/FamilyMark.jsx. Identical in every app apart from the current default.

/**
 * The family as one lockup: Amoleo · Pets · Connections · Rissbrook · Accounts.
 *
 * One "Amoleo" shared rather than repeated, each product name in its own colour
 * — which is what makes it read as a family rather than a list of links. The
 * separator takes its name's colour too, so each dot-and-word is one unit, and
 * it sits inside the link so that when these stack on a phone the whole row is
 * the tap target rather than a four-character word.
 *
 * The site you're already in isn't a link. There's nowhere for it to go. Every
 * other name is, including Accounts, whose host does not resolve yet.
 */
const APPS = [
  { key: 'pets',        name: 'Pets',        href: 'https://pets.amoleo.com/' },
  { key: 'connections', name: 'Connections', href: 'https://connections.amoleo.com/' },
  { key: 'rissbrook',   name: 'Rissbrook',   href: 'https://www.rissbrook.co.uk/' },
  { key: 'accounts',    name: 'Accounts',    href: 'https://accounts.amoleo.com/' },
];

export default function FamilyMark({ current = 'pets' }) {
  return (
    <div className="brand-wordmark family-mark">
      <a className="family-name" href="https://www.amoleo.com" target="_blank" rel="noreferrer">
        Amoleo
      </a>

      {APPS.map((app) => {
        const inner = (
          // Grouped so the dot and suffix shift together as one unit on the
          // mobile stacked rows (§6's max-width: 560px block) — the row
          // itself stays centred, only this pair nudges left within it.
          <span className="family-link-pair">
            <span className="brand-dot" aria-hidden="true">·</span>
            <span className="brand-suffix">{app.name}</span>
          </span>
        );
        const linked = app.href && app.key !== current;
        return (
          <span key={app.key} className={`family-app ${app.key}`}>
            {linked
              ? (
                <a className="family-link" href={app.href} target="_blank" rel="noreferrer">
                  {inner}
                </a>
              )
              : <span className="family-link">{inner}</span>}
          </span>
        );
      })}
    </div>
  );
}

On www.amoleo.com there is no current app — pass current={null} so all four products link out, and drop the href from .family-name instead, since that is the page you are already on.

5. The markup (static — Website, Rissbrook)

Same classes, same structure, no framework. aria-hidden on the separators matters: without it a screen reader reads "Amoleo middot Pets middot Connections" as one run-on string.

<div class="family-mark-wrap">
  <div class="brand-wordmark family-mark">
    <span class="family-name">Amoleo</span>

    <span class="family-app pets">
      <a class="family-link" href="https://pets.amoleo.com/">
        <span class="family-link-pair">
          <span class="brand-dot" aria-hidden="true">·</span>
          <span class="brand-suffix">Pets</span>
        </span>
      </a>
    </span>

    <span class="family-app connections">
      <a class="family-link" href="https://connections.amoleo.com/">
        <span class="family-link-pair">
          <span class="brand-dot" aria-hidden="true">·</span>
          <span class="brand-suffix">Connections</span>
        </span>
      </a>
    </span>

    <span class="family-app rissbrook">
      <a class="family-link" href="https://www.rissbrook.co.uk/">
        <span class="family-link-pair">
          <span class="brand-dot" aria-hidden="true">·</span>
          <span class="brand-suffix">Rissbrook</span>
        </span>
      </a>
    </span>

    <span class="family-app accounts">
      <a class="family-link" href="https://accounts.amoleo.com/">
        <span class="family-link-pair">
          <span class="brand-dot" aria-hidden="true">·</span>
          <span class="brand-suffix">Accounts</span>
        </span>
      </a>
    </span>
  </div>
</div>

The .family-link-pair wrapper exists for one reason: the mobile nudge in §6. It has no purpose above the 560px breakpoint — the dot and suffix could sit directly inside .family-link there, same as before — but adding the wrapper only below the breakpoint would mean two different markup shapes for the same component depending on viewport, which no CSS rule can express on its own (the DOM is the DOM at every width). One wrapper, present always, moved only in the one context that needs it. Originated in Amoleo-Pets; the Website carries it too now (5 August 2026). Not yet in Rissbrook or Connections markup — see §6.

6. The CSS

24px/19px bold is the wordmark's base size (family-wordmark.md §2) — the footer sits at the floor, not above it. Sized up from 13px/7.8px on 4 August 2026, because at that size several of the family's own colours failed WCAG AA on a dark ground (§2 above). See family-wordmark.md §2–3 for why the size lives there as a reference rather than restated per context, and §5 for the alignment fix (no manual top offset — flexbox's own centering is enough).

Both lines below are explicit, not left to inherit the base rule's em values — this is what Amoleo-Website (the reference implementation, along with Rissbrook and Connections) actually ships, and it's load-bearing, not tidiness:

.family-mark { font-size: 24px; flex-wrap: nowrap; justify-content: center; white-space: nowrap; }
.family-app, .family-link { display: inline-flex; align-items: center; }
.family-mark .brand-suffix { font-size: 19px; font-weight: 700; top: 0; }
.family-mark .brand-dot { font-size: 19px; }

.family-mark .pets        { --wordmark-accent: var(--brand-pets); }
.family-mark .connections { --wordmark-accent: var(--brand-connections); }
.family-mark .rissbrook   { --wordmark-accent: var(--brand-rissbrook); }
.family-mark .accounts    { --wordmark-accent: var(--brand-accounts); }

/* Self-link vs. cross-link — family-wordmark.md §6. The product names are
   cross-links: the underline goes directly on .brand-suffix, never on the
   <a> — putting it on the <a> and excluding the dot looked right but
   wasn't (the dot has no size override so an ancestor-sized line sits at
   the wrong height, and some browsers leak a stray fragment under the
   dot's margin even with it excluded). Decorating the suffix directly also
   makes the underline's colour follow the product's own accent for free,
   instead of the page's generic link colour. */
.family-mark a { text-decoration: none; }
.family-mark a:hover .brand-suffix { text-decoration: underline; }
/* The family name is a self-link too (it links to amoleo.com), but not a
   zero-decoration one the way the header logo is — changed 5 Aug 2026. It
   sits in a row with four underline-on-hover cross-links; a link that
   behaves differently from its immediate neighbours for no visible reason
   is the same WCAG 2.1 SC 1.4.1 (Use of Color) territory the cross-link
   rule above is already addressing, so the family name gets the identical
   hover treatment. Set directly on the <a> (not a child span, the way
   .brand-suffix is) because family-name wraps no separate element to
   decorate instead, and there's no dot or sibling here for a line to leak
   onto. color: inherit already pulls --brand-amoleo from .family-mark, so
   the underline defaults to that same colour with nothing extra to write.
   At rest it's undecorated, same as the rest of the lockup — only the
   hover state differs from the header logo. See family-wordmark.md §6. */
.family-mark a.family-name:hover { text-decoration: underline; }

/* On a phone they stack into rows you can hit with a thumb. */
@media (max-width: 560px) {
  /* Without this the rows are about 100px wide: the wrapper centres its
     content, so it is only as wide as the words, and width:100% of that is
     100% of nothing much. */
  .family-mark-wrap { display: block; }
  .family-mark {
    width: 100%;
    flex-direction: column;
    align-items: stretch;
    white-space: normal;
    gap: 2px;
  }
  .family-mark .family-name,
  .family-mark .family-link {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 40px;
    padding: 2px 8px;
    border-radius: var(--radius-sm);
  }
  .family-mark .family-name:hover,
  .family-mark a.family-link:hover { background: var(--border); text-decoration: none; }

  /* Nudges the dot+suffix pair 1em left within its own centred row — the
     row itself (and the "Amoleo" row above it) stays put; only this pair
     moves. Approved as a visual mockup, not derived from a design token —
     centring the literal string "· Pets" isn't the same as centring the
     word a reader's eye lands on, because the leading dot and its margin
     add width the reader doesn't register as part of the name. Shifting
     the pair left compensates. Originated in Amoleo-Pets, 5 Aug 2026. */
  .family-mark .family-link-pair {
    margin-left: -1em;
  }
}

In Pets, --radius-sm and --border both exist; in Connections --border is --panel-2. Check the token exists before pasting.

The compact variant — for space-constrained pages

Some pages can't afford the full footer's height — a page built around a map or a canvas is a fixed screen height with the content taking whatever the footer leaves it, so every row the footer adds is a row taken from the thing the page is actually for. Connections' SiteFooter component is the existing example: a compact prop that drops the optional elaboration and nothing else.

What compact is allowed to drop: supplementary prose — a sentence explaining where data comes from, a longer attribution, anything that exists to inform rather than to satisfy an obligation. Connections drops "Built on data from TMDB, Wikidata, Wikipedia and Fandom wikis" in compact mode; the required TMDB notice itself (with the logo) stays in every mode, because that one isn't optional — a third party's terms, not the family's choice.

What compact must never drop: the lockup itself, in full — all products, correct order, family-mark-wrap, aria-hidden separators — and the copyright line. Compact shortens the footer; it does not exempt a page from carrying the lockup. A page that needs more room than compact still gives back is a page whose layout problem is not the footer's to solve.

The lockup wraps against the small print as a unit, not against itself. Reordering the lockup in front with order: -1 — not moving it in the document, order has no effect on the full non-compact footer's block layout — leaves the TMDB notice and copyright adjacent to each other in the resulting visual sequence (lockup, notice, copyright), so flex-wrap only ever breaks between the lockup and the small print, never mid-print. Above roughly 1370px window width (the widest that fits all three side by side, given 24px/19px suffixes and the required TMDB text) it's a single line; from there down to the 1025px floor it folds to two — lockup on top, notice and copyright together underneath.

A first attempt at this fix — 4 August 2026, same day as the type-size increase that made it necessary — forced the lockup onto its own line unconditionally with flex-basis: 100%. That fixed the internal-wrap problem it was written for but cost the compact footer its single-line case entirely: three lines on every screen, wide or not, which is the opposite of what compact exists for.

.site-footer.compact { display: flex; flex-wrap: wrap; /* ...gap, alignment... */ }
.site-footer.compact .footer-family { order: -1; }

When to reach for it: a page where another element genuinely needs the vertical space back — a map, a canvas, an editor. Not a default, and not a reaction to the footer merely looking big; the full footer is correct everywhere else, including a product's own marketing/landing page (Amoleo · Connections' Landing.jsx uses the full footer deliberately — see docs/family-header.md, "Two states, not three" — because that page is making a case and can afford the fuller footer, the opposite situation from the pages compact exists for).

6.1 Below the fold-to-one-line width — a second, later pass

Everything above describes compact at ≥1025px. Compact's own narrow-width behaviour was added later (6 Aug 2026, in the same pass that trimmed the compact footer's height generally) — before that, compact had no special treatment below 1025px at all and just inherited the shared file's own ≤560px stacking rule, the one thing compact exists to avoid. Connections' SiteFooter/styles.css is still the only implementation, but this is now promoted into the shared footer-lockup.css itself rather than waiting for a second one — the rules below target .site-footer.compact's top-level rows generically (> *, > p, .family-mark-wrap) rather than Connections' own row class names (.tmdb-notice, .footer-family), so they don't assume any repo-specific content and reach a future repo's own compact footer without it needing to reinvent this pass.

The lockup becomes a horizontally swipeable strip, not a taller stack. overflow-x: auto plus scroll-snap-type: x proximity on .family-mark itself, with a mask-image fading both edges so the next name visibly peeks in — that peek is what actually signals "more here, swipe" rather than a static arrow doing the same job. Tried first: a collapse-behind-a-caret control (tap "Amoleo" to reveal the rest). Reverted the same session — a toggle read as one more thing to puzzle out, where a swipeable row invites the gesture on its own. Neither the font-size nor the tap-target height of the product names changes in either state; only the layout around them does.

Real height cuts, not just the layout change — measured 147.4px → ~120px on a 375px phone, none of it from shrinking the family links: the footer's own 20px top/bottom padding (never had a compact-specific reduction below 1025px) down to 8px below it; the 10px/10px/6px gaps between the three rows (also only ever zeroed at ≥1025px) down to 0 via .site-footer.compact > *; the family row's own 4px vertical padding down to 0; and any prose row's line-height — inherited from primitives.css's body default, 1.65, sized for reading prose rather than a caption sandwiched between two other rows — down to 1.35 via .site-footer.compact > p (a single shared value, not Connections' own original 1.3/1.4 split by content class, once this promoted — a repo's own notice text, whatever it says, gets the same treatment for free). Each of these is whitespace around a row, not a change to the row's own content — the distinction that made "reduce the gaps above and below the family links, don't reduce the links" a coherent instruction to give and follow.

A real alignment correction lives here too, distinct from the plain footer's -1.2px. .family-mark sits one flex layer deeper at ≥1025px — a flex item inside .site-footer.compact's own flex-wrap row — which shifts the dot/suffix pair's sub-pixel rounding: measured a real 0.81px residual on top of the shared correction, closed with an additional -2px scoped to .site-footer.compact .family-mark. See docs/family-wordmark.md §5 — nesting the mark inside another flex context is now documented there as its own reason to re-measure, found here.

7. Where it goes

Replace the single copyright line —

<span>© {new Date().getFullYear()} Amoleo · Pets. All rights reserved.</span>

— with the lockup and a copyright of its own. Keeping them separate is the whole point; merged, the copyright reads as belonging to one app:

<div className="family-mark-wrap"><FamilyMark current="pets" /></div>
<span>© {new Date().getFullYear()} <span className="brand-wordmark inline-mark">Amoleo</span>. All rights reserved.</span>

The copyright's "Amoleo" carries the wordmark, not bare text — the same .brand-wordmark.inline-mark construct as any other mention of "Amoleo" in running prose (family-wordmark.md §9), sized off the footer's own small copyright text rather than the lockup's 24px. It's still --brand-amoleo, still uppercase/tracked/800-weight, just at 0.85em of whatever the copyright line's own font-size is instead of a fixed pixel value — the lockup above it is the one part of the footer that gets an absolute size (§6); the copyright line is running text, so it scales the way any other inline mention does. It is not a link on any site, including the site's own — there's a separate self-link for that already, in the lockup (§6 of family-wordmark.md) — bare "Amoleo" here, wordmarked but inert.

Shipped on Amoleo-Website 5 August 2026; Pets, Connections and Rissbrook still have the plain-text version and haven't been asked to change it yet — this isn't check-lockup.mjs-enforced the way the five-name lockup itself is, so it won't show as a failure until it's actually rolled out repo by repo.

8. Three things that will otherwise cost an hour

9. What to check afterwards

Generated from docs/family-footer.md + tools/lockup.json + tools/repos.json. Edit there and re-run npm run build in docs-site-src/ — never hand-edit a page.