AmoleoFamily

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

Visual foundations

Using the system

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.

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.

TokenAmoleo DarkAmoleo LightUsed for
bg #101013 #f7f7fbPage background. Dark is the family default: a visitor with no OS preference and no data-theme gets Amoleo Dark.
panel #191920 #ffffffSurface and card background, header bar, drawer, auth card, cookie banner. Sits on bg.
text #e9e9ee #3a3a4aBody text on bg and panel.
muted #9a9aa8 #6b6b7aSecondary and meta text, captions, inactive tabs on bg and panel.
border #2b2b33 #e0e0e6Dividers, 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 #1c1c2eThe 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

TokenAmoleo DarkAmoleo LightUsed for
panel-2 not in tools/tokens yet #2b2b33 #e0e0e6Hover fill for quiet buttons. Per-site token today (only Website defines it); values are Website's.
text-strong not in tools/tokens yet #ffffff #1c1c2eHeadings 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 themesThe 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 themesText 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 #d32f2fError 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 #1976d2Public-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 themesPublic-visibility globe when sharing is OFF (grey).
ai-generated not in tools/tokens yet #9fb3d1 #4a5f80Text 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 #76603fText 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

TokenAmoleo DarkAmoleo LightUsed for
brand-pets #D9603F both themesAmoleo · 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 themesAmoleo · Connections accent (teal-blue). One value in both themes since 4 Aug 2026.
brand-rissbrook #2f7994 both themesAmoleo · 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 themesAmoleo · Accounts accent. Slate grey, deliberately boring so it does not compete with the products.
brand-todo #8a6d1a both themesAmoleo · Todo accent (olive gold). Design-stage product.
brand-editions #DC143C both themesAmoleo · Editions accent (crimson). 4.99:1 on white, 3.81:1 on dark via the large-text allowance.
brand-upnext #1E8A5C both themesAmoleo · Upnext accent (emerald). 4.33:1 on white, 4.38:1 on dark.
brand-collections #9346B9 both themesAmoleo · Collections accent (amethyst). 5.50:1 on white, 3.45:1 on dark.
brand-registry #7A756E both themesAmoleo · Registry accent (warm taupe). Internal product: never on a public listing surface.
brand-communications #62665C both themesAmoleo · Communications accent (near-neutral grey). Behind-the-scenes service.
brand-images #6B6661 both themesAmoleo · Images accent (grey). Behind-the-scenes service.
brand-reviews #BA2C99 both themesAmoleo · Reviews accent (magenta-rose). 5.37:1 on white, 3.53:1 on dark.
brand-budget #177871 both themesAmoleo · Budget accent ('Fiver Teal'). 5.30:1 on white, 3.30:1 on dark.
brand-games #8566CC both themesAmoleo · Games accent ('Retro Violet'). 4.40:1 on white, 4.31:1 on dark.
brand-home #515AD6 both themesAmoleo · Home accent (electric indigo); the Pulse satellite reuses it.

Type

Page

StyleSpecimenUsed for
display
42px / 1.2 / 700
Know your pet's weight Root and marketing h1: clamp(28px, …, 42px) in code, 42px at full width.
identity
48px / 1.1 / 700
Biscuit Subject name on a public profile hero; the spec allows 36 to 56px.
h2
24px / 1.2 / 700
How it works Section titles and card titles on profile pages (22 to 24px).
h3
18px / 1.2 / 700
Keep a log Card headings (16 to 18px).
body
17px / 1.65 / 400
Pets keeps every weight in one place. Shared default body copy. Prose never drops below 16px on public pages.

Controls

StyleSpecimenUsed for
button
15px / 1.2 / 600
Create account .btn labels. 16px at 780px and below.
field-label
14px / 1.4 / 600
Email address Auth box labels, tabs, switch links. 16px at 780px and below.
field-hint
13px / 1.4 / 400
At least 12 characters. Hints and problems under a field. 16px at 780px and below.
caption
14px / 1.5 / 400
Powered by Amoleo · Accounts Taglines and 'Powered by' captions in muted.

Wordmark

StyleSpecimenUsed for
wordmark
24px / 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

TokenValueUsed for
gutter-sm16px
Mobile page gutter.
gutter-md24px
Desktop and tablet gutter (the spec allows 20 to 24px); .wrap padding.
card-pad24px
Profile-style card padding on mobile.
card-pad-lg32px
Profile-style card padding on wider screens.
touch-target44px
Minimum height and width of any touch control (WCAG 2.2 AA).
wrap1080px
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

shadow
shadow-lg

Amoleo Light

shadow
shadow-lg

Components

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, never text-strong and 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-suffix on 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 from family-css's wordmark.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-hero per 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-accent rather than re-tinting the brand.
  • Pills are for compact controls only. Containers use radius-card or radius-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 (#1976d2 light, #64b5f6 dark, chosen by the rendered surface, not the OS preference); grey is globe-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 is aria-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 danger edge on .auth-error is never the only cue.
  • Two variants share this shell: the redirect card (heading, tagline, one .auth-submit link, 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 against bg; 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 border underneath, 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 .tagline is 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, going text-strong on 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

Footer Compact · Compact, desktop (1025px and above)

The compact footer on a wide screen, .site-footer.compact: for a page that cannot spare the full footer's height (a map, a canvas, an editor). At 1025px and above the lockup, any notice and the copyright fold onto one wrapping row.

Consumer provides: the compact modifier on its own .site-footer, with the notice (optional), .family-mark-wrap and the copyright as direct children.

  • Compact may drop optional supplementary prose only: a data-sources sentence, say. It never drops the lockup, a required third-party notice or the copyright line.
  • The lockup moves first by order: -1 for display only. Document order stays notice, lockup, copyright, so wrapping always breaks between the lockup and its neighbours, never mid-row.
  • Padding falls to 8px; prose rows tighten to a 1.35 line height. At 1024px and below only this tightening applies and the lockup keeps the standard stacking, so a tablet is not a separate shape.
  • Nested one flex level deeper, the lockup needs its own -2px correction (the standard footer's -1.2px leaves a 0.81px residual).

Amoleo Dark

Amoleo Light

Footer Compact Mobile · Compact, mobile: swipeable strip

The compact footer at 560px and below. Yes, it exists: a fifth of a phone screen taken by five stacked rows is the cost compact is for, so the lockup becomes a single horizontally swipeable strip instead.

Consumer provides: the same .site-footer.compact markup as the wide compact footer.

  • The row scrolls sideways with proximity snap. There is no width constraint beyond its own content, so the next name always peeks in; the peek is what signals "swipe", not an arrow.
  • The edges fade with a 24px mask rather than hard-cropping a word. Padding is 0 28px.
  • Name size and the 40px tap height are unchanged from the standard footer. Only the layout around them changes.
  • A tap-to-collapse caret was tried first and reverted the same session: a toggle read as one more thing to work out, where a swipeable row invites the gesture on its own.
  • The lockup is still complete, in order, with the copyright line below it.

Amoleo Dark

Amoleo Light

Footer Mobile · Standard, mobile (560px and below)

The standard footer at 560px and below: the lockup stacks into centred rows you can hit with a thumb.

Consumer provides: the same markup as the standard footer. The layout changes by CSS alone.

  • .family-mark-wrap becomes a block so the rows span the footer. Without it they are only as wide as their words.
  • Each name is a 40px-high row. That is what every adopted repo ships; WCAG 2.2 AA's floor is 44px, a recorded gap rather than a fix made here.
  • The dot and suffix pair shifts 1em left within its row. This is an approved visual correction, not a token: the leading dot would otherwise make the centred string read as off-centre.
  • The copyright stays a separate line below.

Amoleo Dark

Amoleo Light

Footer Standard · Standard, desktop

The standard family footer on a wide screen: the lockup Amoleo · Pets · Connections · Rissbrook · Accounts on one centred line, then a separate copyright line.

Consumer provides: the live product list in the fixed order from tools/lockup.json (oldest first, Accounts last), with the current site's own name as plain text, not a link.

  • Wrap the lockup in .family-mark-wrap. Every .brand-dot is aria-hidden.
  • The copyright names Amoleo and no product, in its own element.
  • Accounts carries no status label.
  • Wordmark at 24px, suffix and dot pinned to 19px with a measured 1.2px correction. Re-measure if the sizes change.
  • Cross-links underline .brand-suffix on hover.
  • Products in pendingApps stay out until promoted.
  • Related: Footer Compact, Footer Mobile and Footer Compact Mobile are the other three shapes.

Amoleo Dark

Amoleo Light

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 uses ai-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 h1 that 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 panel on bg with a 1px border and radius-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 muted with 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 alt and sits behind a local scrim. This preview uses none.
  • Skip link, a focusable main and one h1 are 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-bar with 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 h1 drops 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.

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)

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.