One visual language for every Bubblegum surface
The manager, the calendar drawer, the cross-agent library, Bubbles, the visitor cards, inbound and outbound, pending, the widget, the accounts portal — they grew one at a time and each brought a font, a blue and a corner radius of its own. This is the single set of decisions they all follow from here, with the tokens to import and the list of what each app has to change.
Principles
Five rules that settle most arguments before they start.
How to use this
Two files, one import, no raw hex.
Every product surface links tokens.css first and components.css second, then writes its own styles only in token names. A colour, radius or font that is not a token is not a Bubblegum colour, radius or font. When something is missing, add the token here and ship it everywhere, rather than inventing one locally.
Both files are versioned with the guide; a breaking change to a token name is a new major and a note in Files. Marketing (the landing site) shares the type scale and the neutrals and keeps its own hero palette, which is documented below and nowhere else.
Colour
Neutrals do the work; one accent acts; four statuses speak. Every value below is a token name in tokens.css.
Neutrals
Warm-grey ink on cool-white surfaces. There is one line colour and one muted text colour — the manager used to carry two families of grey (Google's #5f6368 and Tailwind's #6b7280) side by side; the survivor is the one below.
#fbfbfc#ffffff#f6f7f9#f1f2f6#e3e3e6#c8c9cf#1f2330#6b7280#9aa0a6Accent — Bubblegum Violet
The product's one colour. It was already the majority vote (94 uses in the manager, Bubbles, outbound, pending, chatthrough); Google blue #1a73e8 on .btn.primary is retired, and links go violet too.
#5b5bd6#4f4fc4#eeeefb#dedef7#3f3fa8Status
Each status is a trio: the strong colour for a dot or a border, a weak fill for the box, and an ink for text on that fill. Never the strong colour as text on white.
#1f9d57#eafbf0#b45309#fff8e8#d93025#fce8e6#0f766e#be185dSides of a conversation. Outbound and transcripts colour the two parties — ours teal, theirs pink — and only there. Inbound's own pink accent #e0447e folds into side-theirs.
Dark surface
The visitor-facing business card is dark, and the same token names carry it: [data-theme="dark"] swaps the values, nothing else changes.
Books coffee chats and study-abroad consultations.
Marketing palette (landing only)
The landing site keeps its navy CTA #113a7c, the mint hero gradient, and Lato — it is a brochure, not the product. It adopts the type scale, the neutrals and the radius scale from here; nothing from its palette crosses into an app.
- Violet for the one primary action on a panel, selected chips, links, the eyebrow of the section you are in.
- Status fills with their own ink colour.
- Rules and borders in
line; hover borders inline-strong.
- Blue buttons. Blue was Google; it is gone.
- Two greys for muted text on one screen.
- Strong status colour as body text on white.
- Tints for decoration — a tinted box means "this is different", so it must be.
Typography
Inter for the interface, JetBrains Mono for anything a machine reads back. Nothing else.
The manager's body says "Google Sans", which users do not have, so it silently renders in whatever the system falls back to — while Inter is loaded and used in eleven places. Bubbles says Google Sans too; cards, inbound, outbound, pending and chatthrough use a system stack; booking uses Lato. From here every product surface is Inter at 13px, weights 400/500/600/700, and the mono face is JetBrains Mono for ids, keys, URLs and code.
3xl · 26 / 700Booking prerequisite formsshelf and screen titles2xl · 20 / 700Calendar bookingpage titlesxl · 16 / 600Cross-agent librarypanel and modal headslg · 14 / 600intake formcard and row namesmd · 13 / 400All the event types that can be booked in this specific calendar.body — the defaultsm · 12.5 / 400Shared privately with the agentdescriptions, notesxs · 12 / 600Test with agentmini buttons, chips2xs · 11 / 700Event typeseyebrows, uppercase, .07emmono · 12pk_2ampdq · https://maps.google.com/?cid=…ids, links, keys- Sentence case everywhere, including buttons and titles.
- Eyebrows in uppercase with tracking — and only eyebrows.
- Line height 1.45 for body, 1.62 in chat bubbles, 1.25 for titles.
- Title Case, ALL CAPS body text, or bold for emphasis mid-sentence.
- Weights 450 and 650 — they round to 500 and 600.
- Sizes off the scale (13.5, 12.8). Pick the neighbour.
Space & layout
A 4px grid, a 20px gutter inside panels, 24px at the page edge.
| Constant | Value | Where |
|---|---|---|
--bg-bar-h | 57px | Every top bar — app head, drawer head, Bubbles head — so the seams meet across a split screen. |
--bg-dock-w | 344px | Bubbles, docked left. The library opens in exactly this slot. |
--bg-drawer-w | 540px | A side drawer. The calendar drawer is the wide one at 900px. |
--bg-modal-w | 460px | A centred modal. |
--bg-page-w | 1080px | Content column on a page. |
--bg-floor-w | 1204px | Below this the app asks for a wider window, drawers included. |
Between cards in a drawer: a clear band of white above the next header (24px bottom padding). Inside a card: 12px between a label and its control, 8px between siblings, 16px around a card's content.
Radius
Five stops and a pill. The manager was using eleven different values; these are the ones that stay.
| Stop | Used for |
|---|---|
| xs · 6 | Checkboxes, tiny tags, the corner of a "me" chat bubble that points at the sender. |
| sm · 8 | Icon buttons, segmented tabs, tiles. |
| md · 10 | Inputs, dropdown menus, menu rows, tooltips. |
| lg · 12 | Cards, option cards, notes, toasts, dropdown buttons. |
| xl · 16 | Modals, the chat input, hero tiles. |
| pill | Everything you press: every button at both sizes, chips, tabs, switches, tags. The pill is the shape of an action; the rectangle is the shape of content. |
- Press = pill. Type or read = rectangle. That is the whole rule.
- The outer radius is one stop larger than what it contains (a 12 card holds 10 inputs).
- 7, 9, 11, 14, 15 — they are gone.
- A pill button at full width. Pills are inline.
Elevation
Surfaces rest; only floating things cast a shadow.
A side drawer has no shadow: it is a column of the page with a 1px seam. Two drawers side by side (the library beside the calendar drawer) are a split screen — a line between, no tint on either. The scrim (--bg-scrim) appears only behind a modal, and behind a drawer only where clicking it closes that drawer.
Motion
Short, directional, and off for anyone who asked.
| Token | Value | Rule |
|---|---|---|
--bg-dur-hover | 150ms | Background, border and colour changes on hover. Never transform on hover except a 1px lift on a linked card. |
--bg-dur-enter | 200ms, ease-out | A panel arrives with a 24px slide from the edge it lives on, and a fade from 0.6. |
--bg-dur-exit | 180ms, ease-in | It leaves the way it came. When one panel replaces another in the same slot, the first leaves fully before the second arrives. |
--bg-tip-delay | 300ms | Tooltips wait, then appear at once; they leave instantly. A click on the thing quiets its tip until the pointer leaves. |
| reduced motion | 0ms | prefers-reduced-motion zeroes every duration and animation. Nothing depends on an animation finishing. |
Scroll containers set overscroll-behavior: none; anything that must stay put while content scrolls lives outside the scroller (a pinned card head is moved out of the body, not made sticky).
Icons & imagery
Line icons on a 24 grid; one pixel-art character; brand marks as they are.
| Thing | Rule |
|---|---|
| Glyphs | 24×24 viewBox, 2.2 stroke, round caps and joins, currentColor. Drawn at 15–18px inside buttons. Never a font glyph (‹ ›) where an SVG is meant — fonts put them wherever they like. |
| Icon buttons | A 32px circle. The close ✕ in every head, the send in every chat, the chevrons and arrows — one shape, like every other button. |
| The eye | The closed-eye mark on a config card means "skip this in the guided chat". Hidden since 21 September 2026 (Joe: back later if needed) — the wiring stays, so every new card still registers its key; see marks. |
| Avatars | 40px circle. A file or place gets a tinted circle (accent-weak) holding a 20px glyph; a person gets their photo or an initial. |
| Tiles | 32px, radius sm, tinted. Used in dropdown options and settings index rows so a thing keeps the same face everywhere. |
| Bubbles | The pixel sprite (helper-sprite.svg) at 26px, image-rendering: pixelated, always. It is the only illustration in the product. |
| Brand marks | Google, Zoom, Telegram, Discord, OpenAI, Cloudflare and model logos are used as supplied, 16px, on a tile. Never recoloured. |
Buttons
One shape. Every button is a pill — regular or small — in one of four colours. A panel has one primary.
| Kind | Looks | When |
|---|---|---|
| Primary | Violet fill, white text, the accent shadow — the only button with a shadow. | The one action a panel exists for: Save changes, Create form, Send to config chat, Create agent. One per panel or modal foot. |
| Secondary | White, 1px line, ink text. No shadow. | Cancel, Back, Manage, FAQ, the alternative next to a primary. |
| Danger | Danger-weak fill, danger ink. Never a red fill with white text. | Remove, delete, trash — always behind a typed confirmation. |
| Text | Violet text, no box. | A link that acts in place: Show me where, Start here, Show cross-agent library. |
| Regular · 36px | 13px/600, 16px side padding. | Panel and modal foots, page headers, the create section of a shelf, the config card's Send. |
| Small · 30px | 12px/600, 12px side padding. Same colours, same pill. | Inside a row, under a field, in a toolbar: Test with agent, Save changes per question, Open in new tab, Open / Exit form settings, Activate, Manage, the fold bar. |
| Icon | 32px circle, no border, hover soft-2; with a line border when it stands alone (prev/next). | Close ✕, chevrons, overflow ⋯, arrows, send. |
- Verb labels: "Save changes", "Create form", "Remove and trash the Google file".
- Disabled at 45% until there is something to do.
- "Saving…" in the button while it saves; the label comes back after.
- Two primaries on one surface, or a primary in a card head.
- A rounded-rectangle button anywhere — a pill Create form beside a rectangular Save changes is the thing this guide exists to stop.
- A shadow on anything but the primary.
- A pill at full width: a full-width pressable thing is a menu row, and rows are rectangles.
Chips & tags
A chip is something you press — so it is the small button's exact pill. A tag is something you read.
Settled pills
What a setting is right now — the row under "What's configured now". One size for every one of them: 30px, 12px/600, the pill. Colour is the only thing that varies, and it says the category: saved kinds are green, defaults and derived values grey, a proposal not yet saved is dashed violet, an exception amber, places pink, leads blue. A pill's own controls (≡ menu, × remove) are 22px circles inside it and never change its height. Two linked values are joined by a short rule in the first pill's colour.
- Same height and type as every small pill on the screen.
- Colour by category, and only the categories above.
- A pill that grows because it holds buttons (this is the one that shipped).
- Two pill sizes in one row, or a 16px radius pretending to be a pill.
A dashed chip is a value that has not been saved yet (a pill the config chat proposed). A selected chip takes the accent border and weak fill. Tags are 11px uppercase and never carry a click; if you want to click it, it is a chip. The quick-paste rows ("Event types quick paste", "Location labels quick paste") use a small lowercase label, not an eyebrow, so they do not compete with the section heads.
Inputs & choices
On a white panel: a soft fill at rest, white with a violet ring on focus. On a tinted surface: white with a line. Labelled, with an example in the placeholder.
On a tinted surface
A soft-filled field is only a field when it sits on white. Inside a quiet card, a note, or anything else painted soft, it inverts: white with a line border, the same ring on focus. Never a grey field on a grey block.
- A soft field on a soft card — it disappears (this is the one that shipped).
- A darker grey to "fix" it. Invert to white instead.
Option cards
A few choices that each need a sentence. The heading format again: a word, then what it feels like.
Segmented tabs and dropdowns
Tabs are pills on a pill track; a stacked list of views is the same pill with the selected one in the accent tint. A dropdown that navigates carries the tile each destination wears elsewhere, never a native <select> — those render in the platform font.
- Label above, hint below the label, example in the placeholder.
- Switch for a state that takes effect now; radio or checkbox for a choice that waits for Save.
- Native checkbox and radio with
accent-color— no custom drawings.
- 1px hard-bordered white inputs (the 2012 look). Soft fill at rest.
- Placeholders as labels.
- A dashed circle with a plus as an upload target — use the tinted circle with a silhouette and a badge.
Cards, rows and bars
The units a screen is made of.
List row
Avatar, name, one line under it, actions as mini pills. A row that opens something says so in words on a button ("Open form settings" / "Exit form settings"), not with a chevron, and the words carry the state. A kind tag is dropped when the buttons already say what the thing is.
Card and quiet card
A card rests on shadow-rest and lifts on hover only if the whole card is the link. A quiet card (soft fill, no border) groups one item's controls inside a pane — a question and its guidance.
Top bar
Cross-agent library
Config card head
All the event types that can be booked in this specific calendar. Type them in naturally and then send to the config chat to smooth them out.
The rule under the head stays when the card is expanded; the rule at the bottom of an expanded card is an extra one. The eyebrow of the section you are in is violet; the three sub-heads (Instructions, Natural-text entry, What's configured now) are muted.
Drawers, panels and modals
Three containers, and the rules for stacking them.
| Container | Shape | Rules |
|---|---|---|
| Side drawer | Right edge, 540px (900 for the calendar drawer), full height, 1px seam, no shadow. Slides in 24px from the right. | Head 57px with the title and ✕. Body scrolls; a sticky toolbar (collapse bar) may sit at its top. A foot holds the one primary (Save changes) when the drawer edits something. |
| Split panel | Left edge, in Bubbles' slot, capped at the drawer's left column, 1px seam. | Both sides stay live — no tint on either. Clicking the gap closes both: the drawer first, with its unsaved-changes question, then the library, each leaving the way it came. The library's ✕ closes it alone. Bubbles leaves before the library arrives, and returns after it leaves. |
| Modal | Centred, 460px, radius xl, modal shadow, scrim behind. | One question, one primary in the foot. A modal over a modal dismisses only itself. Never for settings — those are drawers. |
| Bubbles | Docked left, 344px, always present above the floor width. | Has no close of its own. When summoned over the split panel it sits on top at a higher layer, with an ✕ at the far right of its head that shows only in that state; a tap on the panel behind it sends it away and leaves the panel standing. |
| Pinned head | A bar between a panel's head and its body. | When a list item opens its full settings, its head (avatar, name, the two buttons) is moved out of the scrolling body into this bar, and the shelf's own title, blurb and create section hide. It cannot travel because it is not in anything that scrolls. |
Split view inside a panel
A test of one thing happens inside the panel that owns it, not in a new window and not in Bubbles' column, which may be mid-conversation: a fixed top half (the thing under test, still editable) and a chat below. The bar reads Back to the list · Question n of m · ‹ ›. When the test ends, the chat half turns accent-weak with a verdict and one button (Test again).
Notes, tooltips and toasts
Three ways to say something small.
| Thing | Rule |
|---|---|
| Note | A tinted box with a bold first line and a sentence. Neutral for guidance, accent for the Ask Bubbles row, warn for something that changed while you were away, danger for something broken. A note is dismissed by fixing the thing, not by an ✕. |
| Tooltip | Our own (data-tip), never title — the browser's waits a second. Above the element, spanning the row it sits in so it can never overhang the panel. 300ms in, instant out, quiet after a click until the pointer leaves. Not shown in compact views where the words are already understood. |
| Toast | Top right, dark, one line, radius lg, the toast shadow. Says what happened ("Saved", "Questions synced"), never what to do next. Errors are the same shape in dark red. |
Chat
One transcript style for Bubbles, the config chat, tests and the visitor widget.
What would you like to work as?
Just wanna have fun
Ha, wouldn't we all — but I need an actual occupation, such as a teacher, electrician, or nurse. What's yours?
Nurse
The other side's words are bare text at 1.62 line height. Ours sit in an accent-weak pill, indented 28px, with a 4px corner pointing at us. The input is a pill-cornered textarea that grows to a few lines; Enter sends, Shift+Enter is a newline; the send button is a violet circle that greys until there is something to send. A system note in the transcript ("The agent accepted the answer") is a bare line in muted ink. Markdown headings are never rendered inside a bubble.
Pattern: the config card
The calendar drawer's unit, top to bottom.
- Head — tile, violet eyebrow (the setting's name), the fold chevron and the closed-eye mark at the right; a rule under it that stays when open.
- Instructions (foldable sub-head) — the one-paragraph description, then Examples as a bulleted list of quiet cards, then the Ask Bubbles row.
- Graphical entry (sub-head, only on a card that has one — the weekly and day-by-day availability grids: the type pills, Clear all, and the week) under the same dotted rule.
- Natural-text entry (sub-head) — the textarea ("Enter here then sent to the config agent for a quick review"), quick-paste chips under it with small lowercase labels, and the Send to config chat primary.
- What's configured now (sub-head) — the settled pills, green when saved, dashed when proposed, each with a menu and an ✕.
- 24px of white before the next card's head.
The drawer's sticky toolbar holds two small pills — Collapse all · Expand all — and every card's Instructions line carries its own Collapse all · Expand all as muted text buttons at the right, with "Prefer to just chat through all of it? Start here" on a non-sticky line above it. The config chat's head reads "Config chat for ‹box›" with its ✕ on the same row, and Next / Prev rows under its input navigate between boxes without opening a conversation.
Pattern: a library shelf
Every cross-agent shelf is the same page.
- Panel head "Cross-agent library" with ✕; under it the Showing dropdown of shelves, each with its tile.
- Shelf title (26/700) and its one-paragraph lede; then the Ask Bubbles about this library feature row.
- Create — a titled section with the primary (Create form / Create doc + Create sheet), framed by a rule above and below.
- In the library — list rows. A form row shows two mini pills (Open in new tab · Open form settings); a doc or sheet shows its link and a chevron.
- Open settings take the panel: the row's head moves into the pinned bar, the title, lede, ask row and Create hide, and the layout is one column. Forms show two tabs — Agent guidance (Proactiveness option cards; "Specific expectations for short-answer and paragraph questions" with Sync now under its sentence; a quiet card per question with expectations, effort pills, Save changes + Test with agent) and Other settings (Name, Sharing, Danger zone).
Pattern: saving, danger and marks
| Rule | How |
|---|---|
| Save only when changed | Every Save button starts disabled and wakes on a real difference from what is stored; reverting puts it back to sleep. A single-choice control (a switch, an option card) saves on the click and toasts "Saved". |
| Per-thing saves | A list of editable things (questions) saves per item, with the button beside that item; there is no "save all" at the bottom. |
| Danger zone | Last in its dropdown, under its own head. The name of the thing, typed exactly, unlocks the buttons. Two ways out where both exist ("Remove and trash the Google file" / "Remove, keep the file in Drive"). The wording says what is lost and what stays. |
| The closed-eye mark | Every config card carries it (hidden for now, wiring intact). It needs the key in OD_FOLD_KEYS (app.js) and the worker's SETTLED_KEYS, or it will not stick. This is the thing that is always forgotten. |
| Both sides live | A write in the library echoes into the drawer at once (the caches it reads take the returned list; the parts that draw it repaint). Nothing waits for a panel to close. |
| Fresh before use | A mirror of something in Google (a form's questions) is reconciled against the live read at the moment it is used, with a note on anything that moved. |
Example layouts
The patterns above, drawn. Each is built from the components on this page and nothing else, so it is also a test of whether the components are enough.
A config card, in full
The calendar drawer's unit. Head with the eyebrow and the eye; three sub-heads — Instructions (with its fold and its own Collapse all · Expand all), Natural-text entry, What's configured now — the second and third each under a dotted rule. Under Instructions: the description, the Examples list, the Ask Bubbles row. Under Natural-text entry: the textarea, quick-paste chips, the card's one primary. 24px of white before the next head.
How long each event type can run for.
- A fixed durationCoffee chats are 30 minutes
- Entirely up to the visitorFor coffee chats let the visitor decide how long.
- A minimum, maximum or bothCoffee chats can be from 30 minutes to 1 hour.Coffee chats must be no longer than 1 hour.
What's configured now
The calendar drawer
900px, right edge, two columns: the config cards on the left under a sticky toolbar, the calendar's switches and Google links on the right. The one primary lives in the foot. Shown here at reduced scale.
goocal2
A library shelf, and the same shelf with a file open
Left: the shelf as you arrive — panel head, the Showing dropdown, title and lede, the ask row, Create, the list. Right: a file's settings open — its head pinned in a bar of its own, everything above the list hidden, the tabs, and the guidance.
Cross-agent library
Booking prerequisite forms
A Google Form a visitor must submit before an event type can be booked.
CreateIn the library
Cross-agent library
A test, as a split view
Inside the panel that owns it: the bar (Back to the list · Question n of m · ‹ ›), the question under test with its guidance still editable and a Save at the end of the effort row, and the chat below. When the agent accepts, the chat half turns accent-weak with the verdict and Test again.
What would you like to work as?
Just wanna have fun
Ha, wouldn't we all — but I need an actual occupation, such as a teacher, electrician, or nurse. What's yours?
Voice & copy
Written for an owner who is not technical and is reading one line at a time.
- Sentence case: "Send to config chat", "Booking prerequisite forms".
- Say who it is for and what it does in one sentence: "Determines the guests (from the hosting side) that are added to the Google Calendar invite for the event."
- Name the real thing: Google Form, Google Calendar, the config chat, Bubbles.
- Buttons are verbs; toggles are states; tags are nouns.
- Errors say what happened and what still works: "Synced — but Google has this form closed to responses."
- "Made once here, usable by every agent." for anything in the library.
- Title Case Headings, exclamation marks, "Oops".
- "Pre-requisite", "Sync Now", "Config Agent" — one spelling, one case, everywhere.
- Explain the mechanism when the outcome is enough.
- Describe a thing twice on one screen (the shelf lede already said what Create makes).
- Say "successfully". "Saved." is the whole sentence.
| Canonical names | |
|---|---|
| Cross-agent library · Calendar booking · Standalone-form filling · Chat history and streaming · Reward payouts · Prerequisite Google Form · Host-side calendar invitees · Pre-event homework · Event-details docs and sheets · Booking prerequisite forms · Config chat · Bubbles · Send to config chat · Collapse all / Expand all · Collapse instructions / Expand instructions · Open form settings / Exit form settings · Test with agent · Save changes · Sync now · Share and send email / Share but don't email · Low / Med. / High · High / Medium / Functional |
Compliance, app by app
What each surface does today against this guide, and what has to change. Import the two files first; then work the list.
- Done (v1.1): a normalisation layer at the end of styles.css gives every pressable class the one pill, two heights and the one shadow rule, over the top of the 160 local radius overrides that had accumulated. The next pass deletes those overrides rather than out-ranking them.
- Body font is
"Google Sans"(unavailable) →--bg-font-ui(Inter). Drop the 11 local Inter declarations; they become the default. .btnradius 7 → md;.btn.primaryblue → violet;#settings .btn.primaryoverride and.set-hd-btncollapse into.bg-btn--primary.- Two grey families →
--bg-ink-muted. Three token vocabularies (--al-*,--d2-*, bare) → the--bg-*names, aliased during migration. - Modal radius 15 → xl; drawer shadows off; toast already right.
- Eleven radii → six. Sweep with the table above.
- Already the source of most patterns here. Make every card's head, sub-heads, examples, ask row and quick-paste labels use the component classes rather than per-card CSS.
- "Fixed online locations" form → the labelled-field style the location and invitee forms have.
- Homework shelf's internal copy still says "Pre-meeting homework"; the dropdown says "Pre-event homework". One name.
- Compliant in shape (this guide was written from it). Replace
.od-mini,.ld-*,.lp-*with.bg-btn--sm,.bg-option,.bg-tabs,.bg-note,.bg-tip.
- Font "Google Sans" → Inter. Its CSS is inlined in JS; it should import
tokens.cssand read the names, keeping only the dock mechanics local. - Bubble radii, the me-pill fill, the head height and the send circle already match; the error red
#b3261e→--bg-danger-ink.
- Dark surface. Its private palette (
--bg #0a0f1e,--accent #6366f1) becomes the[data-theme="dark"]values here; the indigo shifts to the dark-mode violet. - System font stack → Inter; mono → JetBrains Mono.
- Pink accent
#e0447eis a conversation-side colour, not a brand accent →--bg-side-theirsfor the visitor, violet for actions. The blue → gone. - System font → Inter. Google grey → ink-muted.
- Closest to compliant: violet accent, teal/pink sides, proper status trios. Rename their local tokens to
--bg-*and switch the font.
- Violet already; ink
#1f2330is this guide's ink. Font and radius sweep only.
- Runs on host pages, so it keeps its
--ocw-*namespace, but the defaults behind those variables become these tokens (font, radii, accent, bubble style).
- Server-rendered HTML with inline styles: link the two files from the guide origin and remove the local button, input and card rules. Admin's Inter stack is already right.
- Visitor-facing pages in Lato → Inter (it is product, not brochure). Navy CTA → violet.
- Keeps Lato and its navy/mint palette. Adopts the neutrals, the radius scale, sentence case and the canonical names above wherever it shows the product.
- Theme colour → violet; font → Inter; screenshots retaken after the sweep.
Files
| File | What |
|---|---|
| tokens.css | Every value in this guide as a CSS custom property, with the dark set and reduced-motion. Import first. |
| components.css | The reference implementation of every component on this page, written only in token names. Import second. |
| Example layouts | The config card, the calendar drawer, a library shelf open and closed, and the test split view — each drawn from the components alone. |
bubblegum/styleguide/ | The source of this site, deployed by deploy.sh to Cloudflare Pages at styleguide.bubblegum.ai. Change the guide and the files together; they ship as one. |
Version 1.4 · 21 September 2026 — example layouts, drawn from the components. 1.3 — settled pills standardised. 1.2 — inputs invert on tinted surfaces. 1.1 — one shape for everything you press. 1 — first edition.