Foundations
Design System
The family's shared tokens laid out in one place. It is a view of the specs, not a second source: everything below is generated from tools/design-system/tokens.json, which node tools/build-design-system.mjs builds from tools/tokens/*.tokens.json and a small overlay.
Entries tagged not in tools/tokens yet are 10 colours and 1 radius the design system adds that the repo does not define. They are the list to promote into tools/tokens/; until then each is an unreviewed decision.
Brand book
Amoleo is many sites with one brand. Each product is its own codebase, but a visitor should feel they never left. This system holds what is shared; each product's own accent sits on top of it.
Content fundamentals
- UK English and UK conventions: pounds, day-month-year dates, GMT/BST.
- Say what a thing does in concrete terms. A page
h1names a user outcome, not the brand. Claims match shipped behaviour: if the product sends a "warning", the page says warning, not "notification". - Label example data plainly ("Example data, not your account"). Never show screenshots of features that do not exist.
- No "coming soon" or status labels beside a live product, Accounts in particular.
- Plain system voice for errors: say what happened and what to do next. Colour is never the only signal.
Visual foundations
- Canvas. Amoleo Dark is the default theme; Amoleo Light is applied only by an explicit signal. Pages sit
panelonbgwith a 1pxborder. - Colour. Product colour is an identity signal, not a background: use
accentfor primary actions, links, focus rings, selected states, icons and the wordmark suffix. Never fill ordinary cards with it. Set the product withdata-product. - Text. Body copy in
text, headings intext-strong, secondary inmuted. The AMOLEO half of the wordmark isbrand-amoleoand nothing else. - Type. One system-ui stack. Body is 17px at 1.65; prose never drops below 16px on public pages. Headings 24px (h2) and 18px (h3); a root h1 reaches 42px, a profile identity name 36 to 56px. Keep long copy to roughly 46 to 60 characters a line.
- Shape. Cards and modules use
radius-card(16px); hero and identity surfaces 20 to 28px (radius-lg); pills (radius-full) are for buttons, tabs, badges and chips, not containers. Inputs and small controls useradius-sm. - Depth. Prefer borders and spacing to shadow.
shadow-lgis reserved for the auth card, drawer, drop-down panel and cookie banner. - Layout. Content width about 1080 to 1200px, centred; 16px gutters on mobile, 20 to 24px above. The mobile boundary is
max-width: 768px. Touch targets are at least 44px (touch-target). - Focus. A solid 3px
accentoutline, 2px offset, on every interactive element. Tabs and fields use a 2px outline. - Motion. Short transitions only (150 to 300ms);
prefers-reduced-motioncollapses all of them. - Imagery. Photography carries mood or identity, never information the page depends on: decorative images take empty
alt, and text over an image sits on a local scrim that holds WCAG AA on the rendered pixels. Examples are built from HTML, SVG or real components, not generated pictures of UI.
Using the system
- Compose a page from the components here: Wordmark, Button, AuthCard, CookieBanner, AIBadge, VisibilityGlobe, four headers, four footers and the logged-out root page (wide and mobile).
- Headers: logged out (Pre-Auth) and logged in (Post-Auth), each wide and mobile. No variant is literally named "compact header"; the compact bars are the mobile logged-out bar and the logged-in bar, both 28px.
- Page: the logged-out root page composes the header, a hero with the auth card, three sections and the footer. It is placeholder copy, and a product replaces every word.
- Footers: standard, compact, standard mobile and compact mobile (a swipeable strip). Mobile is 560px and below for footers and 768px and below for headers.
- Variants show side by side because a preview cannot change the page's viewport. They are scoped by
data-viewportand carry the same declarations the products apply through media queries. They are copied into each repo, not linked at runtime, so a site never waits on another to paint its own header. - When two products independently build the same piece, promote it into this system instead of leaving two copies.
- Shared presentational parts are copied; shared services (Accounts, Registry, Communications, Images) are called live and must fail gracefully.
Iconography
No icon font or sprite is defined. Icons are small inline SVG that take currentColor: the AI sparkle, the visibility globe, the header burger (three bars drawn in CSS) and the disclosure caret (a CSS triangle). Do not use emoji as decoration.
Accessibility
WCAG 2.2 AA is the floor, measured on the rendered pairing.
- Text and wordmark pairs below are the real family values and are kept exact where they miss: Pets' wordmark suffix on light (3.69:1) and the Upnext and Games
on-accentpairs pass only the large-text bar, never 4.5:1. borderseparates surfaces but is below 3:1 againstbg, so a control's boundary needs more than the border alone.- Never rely on colour alone: errors, public/private and AI state all carry words.
- One
h1per page, a skip link to a focusablemain, andforced-colorssupport on the auth card.
Not in this system yet
Product-specific art direction and application screens are deliberately out of scope. Components not yet built here: the cookie banner's fixed positioning and the profile card. Satellites (Pulse, Subtext) borrow the language but are not family members and are left out of the brand tokens.
Colour
Neutral base
Amoleo Dark is the default; Amoleo Light applies only on an explicit signal.
| Token | Amoleo Dark | Amoleo Light | Used for |
|---|---|---|---|
bg | #101013 | #f7f7fb | Page background. Dark is the family default: a visitor with no OS preference and no data-theme gets Amoleo Dark. |
panel | #191920 | #ffffff | Surface and card background, header bar, drawer, auth card, cookie banner. Sits on bg. |
text | #e9e9ee | #3a3a4a | Body text on bg and panel. |
muted | #9a9aa8 | #6b6b7a | Secondary and meta text, captions, inactive tabs on bg and panel. |
border | #2b2b33 | #e0e0e6 | Dividers, card outlines, input borders. Decorative separation only: against bg and panel it is below 3:1 in both themes, so it must not be the only cue for a control boundary; the real source ships it that way and it is kept exact. |
brand-amoleo | #ffffff | #1c1c2e | The AMOLEO half of the wordmark, and nothing else. The one colour in the family allowed a light/dark pair. Reads on bg and panel. |
Design-system additions
| Token | Amoleo Dark | Amoleo Light | Used for |
|---|---|---|---|
panel-2 not in tools/tokens yet | #2b2b33 | #e0e0e6 | Hover fill for quiet buttons. Per-site token today (only Website defines it); values are Website's. |
text-strong not in tools/tokens yet | #ffffff | #1c1c2e | Headings and emphasised text on bg and panel. Per-site token by design (Website's values here); never used for the AMOLEO half of the wordmark. |
accent not in tools/tokens yet | #6e7178 both themes | The current product's identity colour: links, focus ring, primary buttons, active tab, wordmark suffix. Each product redefines it from its own brand-* token (set data-product on the root). Defaults to the neutral Accounts slate. | |
on-accent not in tools/tokens yet | #ffffff both themes | Text on an accent fill (primary button, active tab). White clears 4.5:1 on every brand token except three: Pets (3.69:1), Upnext (4.33:1) and Games (4.40:1). Those pairs are the real source's and are kept exact; a product that needs to fix its pair redefines this token (Pets' cat themes already switch to #121212). | |
danger not in tools/tokens yet | #ff6b6b | #d32f2f | Error text and invalid-field border. Values are Accounts'. Always paired with words, never colour alone. |
danger-tint not in tools/tokens yet | rgba(255, 107, 107, 0.12) | rgba(211, 47, 47, 0.08) | Background of the auth error banner behind danger-coloured edge and body text. |
globe-on not in tools/tokens yet | #64b5f6 | #1976d2 | Public-visibility globe when sharing is ON. Chosen by the rendered surface, not the OS preference. Never the product accent. |
globe-off not in tools/tokens yet | #9a9aa8 both themes | Public-visibility globe when sharing is OFF (grey). | |
ai-generated not in tools/tokens yet | #9fb3d1 | #4a5f80 | Text and icon of the AI Generated badge: a muted, cooler blue-grey. PROPOSED by this system (the spec leaves exact values TBD); reads on bg and panel at 4.5:1 or better. |
ai-assisted not in tools/tokens yet | #c9b8a3 | #76603f | Text and icon of the AI Assisted badge: a muted, warmer grey. PROPOSED by this system (spec leaves values TBD); reads on bg and panel at 4.5:1 or better. |
Product accents
| Token | Amoleo Dark | Amoleo Light | Used for |
|---|---|---|---|
brand-pets | #D9603F both themes | Amoleo · Pets accent (terracotta). 3.69:1 on white and 5.15:1 on the dark ground: passes the 3:1 large-text bar at lockup size, not 4.5:1 on light. Same value in both themes. | |
brand-connections | #0b6e8f both themes | Amoleo · Connections accent (teal-blue). One value in both themes since 4 Aug 2026. | |
brand-rissbrook | #2f7994 both themes | Amoleo · Rissbrook accent, from Robert Bickley's own 'Side Bar Header' colour. 3.87:1 on dark, 4.59:1 on light. | |
brand-accounts | #6e7178 both themes | Amoleo · Accounts accent. Slate grey, deliberately boring so it does not compete with the products. | |
brand-todo | #8a6d1a both themes | Amoleo · Todo accent (olive gold). Design-stage product. | |
brand-editions | #DC143C both themes | Amoleo · Editions accent (crimson). 4.99:1 on white, 3.81:1 on dark via the large-text allowance. | |
brand-upnext | #1E8A5C both themes | Amoleo · Upnext accent (emerald). 4.33:1 on white, 4.38:1 on dark. | |
brand-collections | #9346B9 both themes | Amoleo · Collections accent (amethyst). 5.50:1 on white, 3.45:1 on dark. | |
brand-registry | #7A756E both themes | Amoleo · Registry accent (warm taupe). Internal product: never on a public listing surface. | |
brand-communications | #62665C both themes | Amoleo · Communications accent (near-neutral grey). Behind-the-scenes service. | |
brand-images | #6B6661 both themes | Amoleo · Images accent (grey). Behind-the-scenes service. | |
brand-reviews | #BA2C99 both themes | Amoleo · Reviews accent (magenta-rose). 5.37:1 on white, 3.53:1 on dark. | |
brand-budget | #177871 both themes | Amoleo · Budget accent ('Fiver Teal'). 5.30:1 on white, 3.30:1 on dark. | |
brand-games | #8566CC both themes | Amoleo · Games accent ('Retro Violet'). 4.40:1 on white, 4.31:1 on dark. | |
brand-home | #515AD6 both themes | Amoleo · Home accent (electric indigo); the Pulse satellite reuses it. | |
Type
Page
| Style | Specimen | Used for |
|---|---|---|
display42px / 1.2 / 700 |
Know your pet's weight | Root and marketing h1: clamp(28px, …, 42px) in code, 42px at full width. |
identity48px / 1.1 / 700 |
Biscuit | Subject name on a public profile hero; the spec allows 36 to 56px. |
h224px / 1.2 / 700 |
How it works | Section titles and card titles on profile pages (22 to 24px). |
h318px / 1.2 / 700 |
Keep a log | Card headings (16 to 18px). |
body17px / 1.65 / 400 |
Pets keeps every weight in one place. | Shared default body copy. Prose never drops below 16px on public pages. |
Controls
| Style | Specimen | Used for |
|---|---|---|
button15px / 1.2 / 600 |
Create account | .btn labels. 16px at 780px and below. |
field-label14px / 1.4 / 600 |
Email address | Auth box labels, tabs, switch links. 16px at 780px and below. |
field-hint13px / 1.4 / 400 |
At least 12 characters. | Hints and problems under a field. 16px at 780px and below. |
caption14px / 1.5 / 400 |
Powered by Amoleo · Accounts | Taglines and 'Powered by' captions in muted. |
Wordmark
| Style | Specimen | Used for |
|---|---|---|
wordmark24px / 1.2 / 800 / 0.1em |
AMOLEO | Base AMOLEO wordmark: uppercase, 800 weight, 0.10em tracking. Suffix and dot are 0.79em at weight 700 and 400. Header sizes: 36px pre-auth, 28px post-auth. |
Spacing
| Token | Value | Used for |
|---|---|---|
gutter-sm | 16px | Mobile page gutter. |
gutter-md | 24px | Desktop and tablet gutter (the spec allows 20 to 24px); .wrap padding. |
card-pad | 24px | Profile-style card padding on mobile. |
card-pad-lg | 32px | Profile-style card padding on wider screens. |
touch-target | 44px | Minimum height and width of any touch control (WCAG 2.2 AA). |
wrap | 1080px | Website's content width. Public pages run 1120 to 1200px; this is the Website's value. |
Radius
radius-sm
8px
Inputs, small controls, skip link.
radius-md
14px
Cookie banner, auth card at 480px and below.
radius-lg
20px
Auth card; larger identity and hero surfaces (about 20 to 28px).
radius-card not in tools/tokens yet
16px
Profile and page module baseline from family-page-design.md. Documented but not yet in family-css.
radius-full
9999px
Pills: buttons, tabs, badges, chips. Not for ordinary containers.
Shadow
Amoleo Dark
shadowshadow-lgAmoleo Light
shadowshadow-lgComponents
Live previews, rendered in both themes. Mobile variants are shown at 375px inside a frame, scoped by data-viewport; products apply the same declarations through media queries.
Brand
Wordmark · AMOLEO · Product
The Amoleo · Product mark, built from three classes that always appear together: .brand-wordmark (the whole mark), .brand-dot (separator, aria-hidden) and .brand-suffix (the product name).
Consumer provides: the product name as the suffix, and data-product (or a --wordmark-accent) so the dot and suffix take that product's accent.
- AMOLEO is always
brand-amoleo, nevertext-strongand never a product accent. - Dot and suffix take the product's
brand-*colour, at 0.79em of the name. - Set the size per context, never on the base class: 36px pre-auth header, 28px post-auth header, 24px footer.
- Align items by centre, not baseline. Where the pair sits visibly off in a browser, correct both glyphs by the same measured pixel value, not an independent em.
- Cross-links underline
.brand-suffixon hover, never the whole anchor or the dot. The current site's own name is plain text, not a link. - In running prose use
.inline-mark(0.95em, inline-flex, line-height 1,vertical-align: middle). The dot and suffix are centred with the name and need no per-glyph offset. This differs fromfamily-css'swordmark.css(0.85em with a -0.132em nudge, which rendered the suffix tiny and high); fold it back there before relying on it in a repo.
Amoleo Dark
Amoleo Light
Actions
Button · Hero and quiet pills
Pill buttons: .btn plus .btn-hero (accent fill) or .btn-quiet (outline).
Consumer provides: the label and, for .btn-hero, an --accent / --on-accent pair through data-product.
- One
.btn-heroper view for the primary action; everything else is.btn-quiet. - Height is at least
touch-target(44px); labels are 15px semibold, 16px at 780px and below. - Do not hard-code an accent hex. A product whose white-on-accent pair misses 4.5:1 (Pets, Upnext, Games) redefines
on-accentrather than re-tinting the brand. - Pills are for compact controls only. Containers use
radius-cardorradius-lg.
Amoleo Dark
Amoleo Light
Visibility Globe · Blue is public, grey is off
The public-sharing toggle. A blue globe means sharing is on; a grey globe means it is off. The meaning is the same in every product.
Consumer provides: the item's state, an accessible name that states the state and the action, and whether a change saves immediately or needs Save.
- Never colour the globe with the product accent. Blue is
globe-on(#1976d2light,#64b5f6dark, chosen by the rendered surface, not the OS preference); grey isglobe-off. - An interactive globe is at least 44px, shows a visible focus ring and sets
aria-pressed. A decorative status globe beside a labelled action isaria-hidden. - Explain it once: "Press a globe to change what is shared. A blue globe means sharing is on; a grey globe means it is off."
- Keep permission, moderation and consent gates; if sharing is blocked by another gate, say why beside the control.
- Turning a profile off belongs with visibility settings, not a danger zone: say what stops being public and what saved data is kept.
Amoleo Dark
Amoleo Light
Forms
Auth Card · Sign in and create account
The shared sign-in and create-account box, copied into every repo that has one; Connections' .auth-card is the reference. Colour comes from the product's own --accent and --on-accent, never a literal hex.
Consumer provides: data-product, the wordmark suffix, the field set, and the validation state (aria-invalid="true" plus a .field-problem line).
- Class contract:
.auth-card,.auth-tabs/.auth-tab/.active,.password-field/.password-toggle,.field-hint/.field-problem,.auth-error,.auth-submit,.auth-switch. - Active tab and submit button take
accent/on-accent. Everything else is neutral base theme. - Errors always carry words: the
dangeredge on.auth-erroris never the only cue. - Two variants share this shell: the redirect card (heading, tagline, one
.auth-submitlink, a "Powered by Amoleo · Accounts" caption) and the terminal card (tabs and fields, Accounts' own sign-in only). - At 780px and below every line is 16px and tabs and the password toggle are 44px high, so iOS does not zoom on focus.
- Known gap: input borders use
border, which is below 3:1 againstbg; the real source ships it that way.
Amoleo Dark
Amoleo Light
Header
Header Logged In · Post-auth, desktop (.family-header-postauth)
The logged-in header on a wide screen: the Post-Auth Header, .family-header-postauth. This is the compact 28px bar: wordmark left, session actions right.
Consumer provides: an optional .tagline, the actions (a "Signed in as…" label plus button-styled actions), and the sticky decision, which is per repo.
- AMOLEO at 28px with a 22px suffix, left-aligned. Smaller than the logged-out header's 36px, never equal to it.
- 1px
borderunderneath, a minimum height of 64px, actions at least 44px high. - The actions row is
.wide-only: below 768px a duplicate copy lives in the drawer instead (see Header Logged In Mobile). - Actions here are session actions. A logged-in header carries no navigation. A repo with real in-app navigation to collapse would need a third pattern that no product has needed yet.
- A lighter public, read-only variant of the same shape drops the session actions and keeps the 28px wordmark.
Amoleo Dark
Amoleo Light
Header Logged In Mobile · Post-auth, mobile: closed and burger open
The logged-in header at 768px and below: the same .family-header-postauth bar, with its session actions moved into a drawer behind a burger.
Consumer provides: the session actions, which appear twice in the markup: an inline .wide-only row for wide screens and a copy inside the drawer. The copy is duplicated, not moved by script.
- The burger sits at the right edge, 44px, and opens the same right-hand drawer the logged-out header uses.
- With a burger, the wordmark steps down from 28px to 22px with a 17px suffix, because the full size overflows a 375px phone beside a 44px burger ("AMOLEO · CONNECTIONS" needs 348px of the 293px left). A header with no burger keeps 28px.
- The
.taglineis hidden on a phone. - In the drawer the actions stack full-width and the "Signed in as…" label shows as a line of its own, since a username beside the wordmark would compete for room.
- The drawer holds session actions only, never navigation.
Amoleo Dark
Amoleo Light
Header Logged Out · Pre-auth, desktop (.family-header)
The logged-out header on a wide screen: the Pre-Auth Header, .family-header. Everything before sign-in is one state: the hero wordmark plus, on pages that have one, the in-page sign-in card below the pitch. Not a separate login screen and not a modal.
Consumer provides: the nav links (or none) and the product's --accent. Website and Rissbrook show this header permanently, since neither ever signs anyone in.
- Centred, not sticky, 36px AMOLEO with a 22px suffix: the base 24px wordmark plus a 12px offset. Always larger than the logged-in header's 28px.
- The nav row is
muted, goingtext-strongon hover. Nav items are links. - A repo with no nav and no login renders neither element, just the wordmark.
- At 768px and below this header is replaced, not resized: see Header Logged Out Mobile. Only one of the two is ever in the accessibility tree.
- No variant is named "compact header" in the family docs. The compact one is the mobile bar and the logged-in bar, both 28px.
Amoleo Dark
Amoleo Light
Header Logged Out Mobile · Pre-auth, mobile: burger drawer and sign-in panel
The logged-out header at 768px and below (768 itself is still mobile): a compact sticky bar, .family-header-bar, that replaces the wide hero. Two shapes, chosen by what there is to reveal.
Consumer provides: either nav links (burger and drawer) or a sign-in form (login control and panel). A repo with both shows both triggers side by side.
- Wordmark at 28px with a 22px suffix, centred when stacked. Shows the same name as the wide header, never a smaller one.
- Burger and drawer: a 44px burger at the right edge opens an off-canvas drawer sliding in from the right, about 280px wide, with a backdrop. The drawer holds secondary nav links only. The burger never hides the login control.
- Login control and panel: a full-width outlined control in the accent colour sits on its own row under the wordmark, with a caret that flips when open. It drops down a sticky panel directly under the bar (no backdrop), holding the auth card without its own frame.
- Only a site with real nav content gets a burger. Rissbrook, with only a wordmark, gets neither control.
- Move focus into the drawer or panel on open and back to the trigger on close.
- In these previews the drawer is positioned inside its frame. Live, it is fixed to the viewport.
Amoleo Dark
Amoleo Light
Footer
Feedback
AIBadge · AI Generated and AI Assisted
The AI transparency pill: shown wherever an AI generated or polished content. Two states, AI Generated (the model wrote it) and AI Assisted (a person wrote it, the model refined it). Fully human content gets no badge.
Consumer provides: which state applies, the product's edit threshold for flipping Generated to Assisted, and its disclaimer text.
- Subtle, like a watermark: pill outline, sparkle icon in inline SVG (never an image), label text.
- Generated uses
ai-generated(cooler); Assisted usesai-assisted(warmer). Both are PROPOSED values: the family spec leaves exact colours open until a product ships, so confirm them on first adoption. - Both states carry the words as well as the colour.
- Visible to all users by default; editors and admins may hide it after review, per product.
- Pair with a plain disclaimer, e.g. "This article was AI-generated. Always consult a veterinarian for medical advice."
Amoleo Dark
Amoleo Light
Cookie Banner · Consent before loading
The cookie consent banner. Nothing optional loads until the visitor chooses; the choice is stored under cookieConsent.
Consumer provides: the copy, the two handlers, and a --wrap width (or a literal one). Only repos that actually set optional cookies need one.
- Decline and Accept carry equal weight: Decline is
.btn-quiet, Accept.btn-hero. Never make declining harder than accepting. - In production the banner is fixed 16px from the left, right and bottom at
z-index: 50; check it against the repo's modal stack so it never floats over a privacy modal it opened. - Below 560px the two buttons share the row equally.
Amoleo Dark
Amoleo Light
Page
Page Logged Out Root · Logged-out root page, wide
The logged-out root page on a wide screen: a product page first and a sign-in surface second, composed from the family header, hero, three short sections and the footer. This is the default public-page language from docs/family-page-design.md, not a fixed template: products arrange the same ideas differently.
Consumer provides: the product's data-product, one concrete h1, the lead sentence, honest example data and three true sections. Every word here is placeholder copy.
- One
h1that says what the product is useful for in concrete terms, a specific user problem or outcome rather than brand language. - One strong hero. On wide screens the auth card sits inside the hero beside the copy, not as the whole page. The reading order stays copy, action, example, then sign-in.
- Show the product with real components or honest static examples. Dummy data is allowed only when labelled ("Example data, not your account").
- Follow the hero with a few explanatory sections (three here), not a long catalogue. Claims match shipped behaviour, including opt-ins and caveats.
- Modules are
panelonbgwith a 1pxborderandradius-card(16px), padded 24px on mobile and 32px wider. Pills are for buttons and tabs only. - Accent goes on the primary action, the sign-in tab, links and the step rings. It stays off body-size text: it fails 4.5:1 for several products in one theme or the other, so the eyebrow is
mutedwith an accent rule. - Width is about 1120 to 1200px with 20 to 24px gutters. Keep long copy to roughly 46 to 60 characters a line. Prose never goes below 16px.
- Hero imagery, where used, is decorative with empty
altand sits behind a local scrim. This preview uses none. - Skip link, a focusable
mainand oneh1are part of the page, not optional extras.
Amoleo Dark
Amoleo Light
Page Logged Out Root Mobile · Logged-out root page, mobile
The logged-out root page at 768px and below. The pitch is not removed: it is rearranged. The hero's auth card leaves the page and moves into the family bar's sign-in control and panel, so sign-in stays reachable without interrupting the pitch.
Consumer provides: the same content as the wide page. Only the layout changes.
- The wide hero and in-page form give way to the compact sticky
.family-header-barwith a full-width sign-in control. Tapping it drops the same auth card down as a panel (see Header Logged Out Mobile). - Never hide the main pitch just because the sign-in box would fill the first screen.
- The hero stacks to one column, the three sections stack, and the
h1drops to about 30px. - The footer is the standard mobile footer: stacked 40px rows.
- Touch controls stay at least 44px. Move focus into the panel on open and back to the control on close.
- Check the page at phone width, 768px, tablet and wide desktop, and measure contrast on the rendered page rather than the tokens.
Amoleo Dark
Amoleo Light
Family design system
Added 23 October 2026. The Amoleo Design System is the one place the family's shared tokens, components and usage rules are laid out together: neutral base (Dark and Light), the product accents, type, spacing, radii, shadows, and the shared components (wordmark, buttons, auth box, footer lockup, header, cookie banner, AI badge, visibility globe). It is a view of the family specs, not a second source for them.
Where the values live
The repo stays the authority. The design system is generated from it.
| Part | Source | Edited by hand? |
|---|---|---|
| Brand colours, the neutral base, radii, shadows | tools/tokens/*.tokens.json |
Yes, there |
| Usage notes, spacing, type scale, themes | tools/design-system/overlay.json |
Yes, there |
| Brand book and component guidelines, previews and CSS | tools/design-system/README.md, tools/design-system/components/ |
Yes, there |
| Design-system-only additions (see below) | tools/design-system/overlay.json, entries with origin: "design-system" |
Yes, there |
| The tokens file the design system reads | tools/design-system/tokens.json |
No. Generated |
| The guidebook page | docs-site-src Design System page |
No. Built from tokens.json, the brand book and the components; live previews come from docs-site-src/scripts/build-design-system-previews.mjs |
node tools/build-design-system.mjs # write tools/design-system/tokens.json
node tools/build-design-system.mjs --check # exit 1 if it is stale
The script is loud on drift: a brand colour or base-theme token in tools/tokens/ with no overlay entry fails the run, so a product added to the family cannot silently be missing from the design system. A value in tools/tokens/ always wins over the overlay.
What the design system adds that the repo does not define yet
These ten colours and one radius exist only in overlay.json and are marked origin: "design-system". The list is the to-do list for promoting them into tools/tokens/; each one is an unreviewed decision until then.
panel-2,text-strong: per-site tokens today (Website's values).accent,on-accent: the per-product identity colour and the text on it. Every product defines its own.danger,danger-tint: Accounts' values.globe-on,globe-off: fromdocs/public-visibility.md(#1976d2light,#64b5f6dark; grey off).ai-generated,ai-assisted: proposed, not agreed.docs/family-ai-transparency.mdleaves the exact values open. Both clear 4.5:1 onbgandpanelin both themes.radius-card(16px): the card baseline fromdocs/family-page-design.md, documented but not yet in family-css.
Spacing and the type scale are overlay-only too and are not checked against any repo's CSS.
Component CSS, and where it differs from the shipped files
The design system carries its own copy of the component CSS, ported from tools/family-css/components/. It is a copy for design and review; tools/family-css/components/ is what ships to repos. The mobile and wide-compact variants are scoped to data-viewport attributes instead of media queries so they can sit side by side in a preview; the declarations are the same. One change here is deliberate and not yet folded back: .inline-mark is 0.95em, line-height: 1, middle-aligned, with no per-glyph nudge. The shipped wordmark.css (0.85em with a -0.132em offset) rendered the inline Amoleo · Accounts suffix tiny and high. Until the shipped file changes, the two disagree on purpose.
Publishing to the artifact
The Amoleo Design System artifact (a private claude.ai artifact) is a published copy of what lives under tools/design-system/: tokens.json, the brand book as the artifact's README, and components/ as its components. The repo is the source. Publishing is a deliberate step, not part of the build: regenerate tokens.json, then republish those files to the artifact. The artifact's own copy has no checker, so republish in the same pass as any change here. The artifact's cover (components/Cover/preview.html) is artifact-only and is not on the guidebook page.
Known gaps (recorded, not fixed here)
- White on
brand-petsis 3.69:1, onbrand-upnext4.33:1 and onbrand-games4.40:1: all miss 4.5:1 for button text. These are the real source's pairs and are kept exact. borderis below 3:1 againstbg, so it cannot be the only cue for a control's boundary.- Not built yet: the profile card and the cookie banner's fixed positioning.
- Header and footer variants are named for what they are: logged-out and logged-in headers, each wide and mobile; standard, compact, mobile and compact-mobile footers. The family docs have no variant called "compact header". The compact bars are the 28px mobile logged-out bar and the logged-in bar.
- Pulse and Subtext are satellites and are left out of the brand tokens.
Generated from docs/family-design-system.md + tools/design-system/tokens.json + tools/design-system/README.md + tools/design-system/components/*. Edit there and re-run npm run build in docs-site-src/ — never hand-edit a page.