Styleguide
Type, icons, imagery and motion, and how they carry into print, social media, email and presentations. Then the rules every screen in the app follows. For how we sound, see the Voice page.
Typography
One superfamily, three cuts. Serif for headings, sans for everything people read and work in, mono for anything that must line up.
Typefaces
All three are open source (SIL Open Font Licence) and free from Google Fonts, so print, slides and social templates use the same faces as the app. In the product they load through next/font in the root layout.
font-headingfont-sans (default)font-monoHeadings
Serif, semibold, sentence case. Display to Heading 2 use text-balance, so a title never leaves one word alone on its last line.
Every project, one place
<Heading level="display">text-balance font-heading font-semibold text-4xl tracking-tight md:text-5xlContacts and deals
<Heading level={1}>text-balance font-heading font-semibold text-3xl tracking-tightBrand refresh for Northwind
<Heading level={2}>text-balance font-heading font-semibold text-2xlUpcoming tasks
<Heading level={3}>font-heading font-semibold text-xlInvoices due this month
<Heading level={4}>font-heading font-semibold text-lgContact details
<Heading level={5}>font-heading font-semibold text-baseBilling address
<Heading level={6}>font-heading font-semibold text-sm<CardTitle>font-heading font-medium text-baseThis week
<Eyebrow>font-bold text-primary text-xs uppercase tracking-widestBody text
Noto Sans, text-sm by default. Make text muted before you make it smaller.
Everything a project needs, from the first enquiry to the final invoice.
<Lead>text-balance text-lg text-muted-foregroundThe app's base size is text-sm. It fits a lot on a working screen, and every control is sized around it.
<Text>text-sm leading-relaxedDescriptions, helper text and anything secondary.
<Muted>text-muted-foreground text-smTimestamps, counts and captions.
<Small>text-muted-foreground text-xsfont-medium text-2xl tabular-numsElements
Inline pieces that sit inside running text.
Run bun run docs:check before committing.
rounded-md bg-muted px-1.5 py-0.5 font-mono text-sm<KbdGroup><Kbd>⌘</Kbd><Kbd>K</Kbd></KbdGroup>text-primary underline-offset-4 hover:underlineborder-primary border-l-2 pl-4 text-muted-foreground italicProse
Text someone wrote, such as docs, notes, proposals and chat messages, renders inside Prose. It wraps shadcn's Typeset stylesheet, which styles the plain elements inside it with our fonts and colour tokens. The layout around it sets the width. The rich-text editor and viewer both use it.
Kick-off notes
Northwind want the new site live before their spring launch. Sign-off sits with the marketing lead, and finance approve anything over budget.
Next steps
- Share the discovery findings by Friday.
- Book the launch review. Their team needs
2 weeksnotice.
Keep the tone warm. Their customers are loyal.
| Milestone | Owner | Due |
|---|---|---|
| Discovery | Sarah | 14 March |
| Launch review | Tom | 2 April |
<Prose preset="docs">{content}</Prose>typeset typeset-docsDraft proposal is in the Northwind folder.
Can you check the pricing table before Friday?
<Prose preset="chat">{message}</Prose>typeset typeset-chat- Use preset="docs" for documents, notes, proposals and help, and preset="chat" for messages and comments.
- Keep the content to plain elements. Typeset styles headings, lists, quotes, tables and code by position.
- Add not-typeset to an embedded card or code frame so it keeps its own layout.
- Style the elements inside Prose one by one. Change typeset.css instead, so every surface follows.
- Wrap interface text, such as labels, buttons and settings, in Prose.
Code blocks
Code in docs, notes and proposals renders in the editor's frame, with the language in a header bar. Highlighting uses one muted palette, with light and dark versions.
import { Button } from "@workspace/ui/components/button"
// One primary action per view: the orange button.
export function CreateProject({ onCreate }: { onCreate: () => void }) {
return <Button onClick={onCreate}>Create project</Button>
}<StaticCodeBlock code={source} language="typescript" />Iconography
Hugeicons, stroke style, at stroke width 2. The mark is not an icon and never appears in the set.
Icons come from @hugeicons/core-free-icons, rendered with @hugeicons/react.
Buttons size their own icons. Set a size only outside a button.
<HugeiconsIcon icon={Search01Icon} strokeWidth={2} className="size-4" />- Use Hugeicons at strokeWidth={2}, size-4 by default (size-3.5 in tight rows, size-5 for emphasis).
- Give icon-only buttons an aria-label and, where it isn't obvious, a tooltip.
- Let the icon take currentColor, so it follows the text around it.
- Mix in another icon library, or filled with stroke icons.
- Colour icons orange for decoration. Orange is for the one thing that matters.
- Use emoji as UI icons.
Imagery
Photography and screenshots for the website, social, print and decks. Documentary, not staged. The brand is about the work, so show the work.
- Show real clients, teams and places, with their permission.
- Crop product screenshots to the part that makes the point, in either theme.
- Generic stock: handshakes, pointing at screens, staged office scenes.
- Heavy filters, neon or cold blue grading, HDR.
- AI-generated people or places presented as real.
Motion
Motion explains a change. It never decorates one. Most transitions are 150–300ms, and background motion is measured in tens of seconds.
- Add motion-reduce:transition-none or motion-reduce:animate-none to anything that moves.
- Move with transforms (translate, scale) so nothing shifts layout.
- Animate to get attention: pulsing badges, shaking fields.
- Chain animations that make the user wait to continue.
Channels
The same wordmark, four colours and two typefaces, applied to each place the brand shows up. Values for each colour are under Colour on the brand guidelines page.
Cards, letterheads, signage and anything else we print. Use warm white, uncoated stock, never lighter than 250gsm. Thinner stock feels cheap in the hand.
Social media
LinkedIn first, then Instagram and X. A post should look like it came from the same place as the product: dark and warm, with one orange accent and little else.
Product emails and marketing email share one kit, so a customer can't tell which system sent them.
Presentations and documents
Decks, one-pagers and reports.
- Start from a shared template for each channel, so the details are right by default.
- Follow the Voice page: British English, sentence case, plain words.
- Introduce new colours or typefaces for a campaign.
- Put more than one message, or more than one orange accent, in a single post or slide.
Screen rules
The conventions every screen in the app follows. The full reasoning is in ARCHITECTURE.md, under Presentation.