Brand system
↓Download markdownThe working reference for everything Stitch puts in front of a person — the mark, the palette, the type, the surfaces that hold content, and the charts that carry the numbers. Light is the ground. Dark is opt-in. Ink is the voice; violet is an accent
The mark
One wordmark, one symbol, one weight — a single flat colour object, never a gradient, never an effect
Lockups
The wordmark is the default. The symbol is for square crops, favicons and app tiles where the wordmark would fall below its minimum size.
Approved colour usage
Four treatments. Everything else is a misuse. --white and --paper are interchangeable as the light ground.
Muted is a fallback, not a style. A single --titanium file sits on a light or a dark ground, so one asset covers both modes where CSS cannot follow it — email templates, PDF exports, third-party embeds, app-store art. At 2.0:1 on paper the mark is deliberately quiet, which logotypes are permitted to be, but it is the wrong choice anywhere Solid or Reversed can be used instead.
Do
- Render the mark in one flat colour drawn from the palette.
- Switch from Solid to Reversed the moment the background is darker than
--silver. - Sit the mark on a solid field, or on a photograph with a clear, even area.
- Keep the paper mark on violet — never ink on violet.
- Reach for Muted only when one file has to serve both modes.
Don't
- Fill the mark with a gradient, a photo, or the chart fade.
- Add a stroke, a shadow, a glow or an outline.
- Recolour the mark to amber, neon, electric or a categorical violet.
- Sit violet on ink, or ink on violet — the contrast fails.
- Use Muted as a style choice where Solid or Reversed would work.
- Stretch, rotate, condense, or rebuild the mark from type.
Clear space
Measured in x — the height of the symbol's lower loop. Nothing enters the gutter: no type, no rule, no crop edge, no other logo.
Minimum clear space on all four sides is 1x. In dense UI chrome — a topbar, a rail, a card header — 0.5x is permitted, but only against a plain surface.
Minimum sizes
Below these the counters close up and the loop reads as a blob.
In print the wordmark holds to 25 mm wide and the symbol to 8 mm. Below that, use the symbol; below the symbol minimum, drop the mark entirely.
Position in layouts
The mark anchors a layout; it does not float in it. Three placements cover everything we make.
Product UI, decks, documents. The default anchor.
Advertising and social, where the headline owns the top.
Covers, splash and end frames only. Sits 4% above true centre.
Margin rule. The mark sits on the layout's safe margin — 8% of the short edge for advertising and covers, 24 px for product UI. It never sits closer to an edge than its own clear space, whichever is larger.
Download
Vector for anything that scales. PNG only when vector is impossible.
fill="currentColor" · for embedding in codeColour palette
A greyscale system with three loud colours held in reserve. Ink does the work
Every swatch copies. Click any chip to put its hex on your clipboard.
Neutrals
Nine steps from white to ink. These flip between themes — the token stays, the value moves.
Accents
Fixed in both themes, and ranked by how much of the interface each one may touch. Width carries the rank — of eight columns, primary takes four, secondary two, and each tertiary one.
Primary
Secondary
Tertiary
| Colour | Token | What it means |
|---|---|---|
| Brand violet | --brand | Highlight fill in charts, focus ring, dark-mode toggle. Never type. |
| Amber | --amber | Warning, cost, lapse, needs action. Replaces red in the interface, and --danger now points at it. |
| Neon | --signal | Positive, live, on, protected. Type on neon is always --signal-ink. |
| Electric | --electric | Cold stop on heatmap ramps. Nothing else. |
Accent ramps
Every accent carries a dark end for type and a light end for fills. The base sits in the middle, and the two tertiary ramps share slate.
Primary
Indigo is --brand-ink, and it is type on lavender and mist only. On base violet it falls to 2.8:1, so type there stays --paper.
Secondary
Bronze is --amber-ink. It clears AA on amber itself at 5.03:1, where paper manages only 3.01:1 — so bronze, not paper, is the type on amber.
Tertiary — neon
Slate is --signal-ink, spring is the light tint. Spring sits at the same luminance as paper, so on the light stage it reads as hue alone and needs the inset hairline to hold an edge.
Tertiary — electric
The same slate opens the electric ramp, with ice as the cold tint.
| Ink | Token | Goes on | Contrast |
|---|---|---|---|
| Indigo | --brand-ink | Lavender, mist | 9.96 / 13.05 |
| Bronze | --amber-ink | Amber, peach | 5.03 / 12.11 |
| Slate | --signal-ink | Neon, spring, electric, ice | 14.03 / 15.53 / 12.79 / 14.87 |
| Paper | --paper | Base violet only | 5.86 |
Surfaces
How the neutrals assemble into a screen.
| Token | Light | Dark | Where it goes |
|---|---|---|---|
| --bg | --paper #fcfbfb | --paper #0f0c15 | The stage. Everything sits on it. |
| --raised | --white #ffffff | --white #16131c | Cards and the sidebar. Solid, no blur. |
| --surface-glass | white 62% | white 68% | Overlays, drawers, tooltips. |
| --chrome-glass | white 78% | white 84% | Sidebar, rail, topbar, popovers. |
| --grid | ink 8% | #f5f4f4 9% | Chart gridlines and layout guides. |
| --line | transparent | transparent | There are no 1 px borders. Edges come from the inset hairline. |
Colour rules
- Ink is the voice. Primary buttons, selected thumbs, links and "ok" cells are all ink. A button is never
--brand— see Buttons. - Selection is platinum, not ink. A selected card or an active nav item fills with
--platinum, keeps its hairline and takes ink type. An ink fill at that size reads as a button. - Colour lives on fills, strokes and legend swatches. It reaches type only to correlate with a graph, or as
--amberon a negative figure in a table — never on a chart title, a KPI value, or body copy. - Status is never colour alone. Every state carries a label.
- Up is neon, warning is amber. No green, and no red at all —
--dangerresolves to--amber.
Status states
| State | Fill | Type |
|---|---|---|
| Up / ok / live | signal 55% | --signal-ink |
| Down / warn | --warn-s | --amber |
| Flat | ink 6% | --ink2 |
| Selected | --ink | --ink-reversed |
Typography
Suisse Intl, and only Suisse Intl. One family for display, interface, body and numerals
The family
Four licensed cuts, and no separate mono — Suisse's tabular figures do that job. Weight 500 is aliased to Regular: no Medium file exists, and synthesising one is not permitted.
Character set
ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz
0123456789
R $ € £ & @ # % · ()[]{} — – - .,:;!?'"
Typescale
Body is 16 px with -0.011em tracking. Tracking tightens as size grows and opens up for small caps-style labels.
Colour in type
Four levels of ink, and nothing else. Type never takes a brand colour.
Primary
--ink · 100%
Headings, KPI values, table first column, active nav.
Secondary
--ink2 · ink 62%
Body copy, descriptions, labels, table cells.
Tertiary
--ink3 · steel / titanium
Table headers, axis ticks, placeholders, captions.
Muted
--muted · ink 45%
Section headlines only, at 24 px and up. It clears AA for large type at 3.05:1, so it never carries body copy.
Type rules
- Tabular numerals where figures stack. Anything read down a column — tables, chart values — carries
tabular-nums. KPI values are lining figures. - One family. Suisse Intl carries display, UI, body and code.
- Emphasis is 600. Never 900. Black is a display weight — it belongs at hero and page-title size, never inside a sentence.
- Sentence case for headings and buttons. Uppercase is for labels, eyebrows and table headers only.
- No full stop on a headline. Titles, section headlines, ledes, labels and button text end without one. A period closes a thought; a headline is meant to stay open. Internal punctuation is fine — it is only the last character that goes.
- Measure caps at 62 ch for body copy.
Never
- Violet, amber or neon type. Colour is a fill, not a voice.
- A synthesised Medium, Italic or Bold — only the four licensed cuts.
font-weight: boldor700. There is no 700 cut, so the browser resolves it upward to Black. Always write600.- Aeonik, Neue Rational, Reckless, or a system fallback in shipped work.
- Tabular figures in running text. Even widths are what make a column align; in a sentence they just leave gaps.
- Letter-spacing on body copy beyond the
-0.011emdefault. - Underlines on anything but inline links.
Download
Web cuts for anything that renders in a browser; desktop cuts for Figma, Illustrator and Keynote.
@font-face {
font-family: 'Suisse Intl';
src: url('./fonts/SuisseIntl-Regular.woff2') format('woff2');
font-weight: 400;
font-display: swap;
}
/* No Medium cut is licensed — alias 500 to Regular. */
@font-face {
font-family: 'Suisse Intl';
src: url('./fonts/SuisseIntl-Regular.woff2') format('woff2');
font-weight: 500;
font-display: swap;
}
body {
font-family: 'Suisse Intl', -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 16px;
letter-spacing: -0.011em;
}
/* figures read down a column, and nowhere else */
table,
.bar__val {
font-variant-numeric: tabular-nums;
}
Licensing. Suisse Intl is licensed from Swiss Typefaces. Load the web cuts with @font-face from your own origin — do not ask people to install the desktop cuts to view a page, and do not redistribute either set outside Stitch.
Cards and the inset shadow
Stitch surfaces have no borders. An edge is a hairline pressed into the inside of the shape
The recipe
Two inset shadows, 0.75 px each, on opposite diagonals — light catching the top-left, shadow settling into the bottom-right. It reads as a physical lip rather than a drawn line, and it survives on glass where a 1 px border would not. The colour is ink at 20% so it holds in both themes.
Blown up so you can see which edge lights and which edge sinks.
At production scale the effect is almost subliminal — that is the point. It defines the shape without adding a line to the composition.
:root {
--inset-edge: color-mix(in srgb, var(--ink) 20%, transparent);
--inset:
inset -0.75px -0.75px 0.5px 0 var(--inset-edge),
inset 0.75px 0.75px 0.5px 0 var(--inset-edge);
--inset-strong:
inset -0.75px -0.75px 0.5px 0 color-mix(in srgb, var(--ink) 30%, transparent),
inset 0.75px 0.75px 0.5px 0 color-mix(in srgb, var(--ink) 30%, transparent);
}
.card--glass {
background: var(--surface-glass);
backdrop-filter: blur(20px) saturate(140%);
border-radius: 1.5rem;
box-shadow: var(--inset);
border: 0;
}
Asset cards
For specimens: a mark, a colour, a type cut. The plate is full-bleed and carries the card's own radius, so the card shows through at its two lower corners.
.asset {
position: relative;
border-radius: var(--r);
background: var(--raised);
}
/* Hairline above the plate, not behind it. */
.asset::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: var(--inset);
pointer-events: none;
}
.asset__plate {
width: 100%;
aspect-ratio: 3 / 2;
max-height: 220px;
border-radius: var(--r);
overflow: hidden;
}
.asset__label {
padding: 1.1rem 1.25rem 1.25rem;
line-height: 1.3;
}
- Plate radius equals card radius — both
--r. The lower corners curve inward and reveal the card. - The plate is flush to the card's top, left and right. Only the label block is padded.
- The inset hairline is drawn on top by
::after, so it reads across the plate edge rather than hiding behind it. - Label is a two-line pair — title in
--inkover subtitle in--muted, same size, no gap. The same pairing as a section head. - The ink plate carries its own hairline at paper 16%, because ink on a carbon card has no edge in dark mode. The paper plate carries none.
Two tiers
The tier is decided by what the surface is for, not by how it looks.
Tier 1 — content card
No shadowSolid --raised — --white in light, --carbon in dark. No blur, no border. It reads as a sheet laid on the --paper stage, and content sits directly on it.
Tier 2 — chrome card
Inset hairlineGlass fill, blurred backdrop, hairline edge.
Glass fill plus the inset, for surfaces that float over content: popovers, drawers, tooltips, buttons, chips and controls. The sidebar and topbar are chrome but sit beside content rather than over it, so they take the solid --raised fill and keep only their directional hairline.
Directional insets
Chrome that meets the viewport only takes the hairline on the edge that faces content.
| Surface | Inset | Declaration |
|---|---|---|
| Card, popover, drawer, tooltip | All four edges | var(--inset) |
| Sidebar | Right only | inset -0.75px 0 0.5px 0 var(--inset-edge) |
| Rail | Right only | inset -0.75px 0 0.5px 0 var(--inset-edge) |
| Topbar | Bottom only | inset 0 -0.75px 0.5px 0 var(--inset-edge) |
| Table header | Bottom only | inset 0 -0.75px 0.5px 0 var(--inset-edge) |
| Selected table row | Left, 3 px | inset 3px 0 0 0 var(--ink) |
Radius and spacing
Four radii. Nothing in between.
24 px
--r · cards, drawers, overlays, the composer.
16 px
--r-m · a card inside a card, and the demo surfaces in this guide.
12 px
--r-s · inner plates, inputs, code blocks, media.
999 px
Pills · buttons, chips, toggles, legend swatches, bar tracks.
States
The hairline strengthens on hover. Selection swaps the fill to platinum and keeps the hairline — an ink fill would read as a button, and a selected card is not something you press.
--inset · ink 20%
--inset-strong · ink 30%
--platinum fill, ink type
2 px --brand, 2 px offset
What the inset replaces
Side by side against the conventions it exists to avoid.
Avoid A hard line competes with content and breaks over glass.
Avoid Reserved for tooltips and the Ask bubble. Never on a card.
Use Defines the edge from inside. Works on any fill, in either theme.
Layout note. Never leave a hole larger than about 48 px under a card's last child. If a card looks empty at the bottom, the padding is wrong or the content belongs somewhere else.
Buttons
Ink for the interface, amber and neon for the call to action. Violet is never something a person presses
The four
One interface button, two CTAs and one secondary. Everything else is a size or an icon variant of these.
Fills and labels
Ink, amber, neon, hollow| Button | Fill | Label | Where it goes |
|---|---|---|---|
| Primary | --ink | --ink-reversed | Every action inside the product. This is the default and it covers most cases. |
| CTA — B2B | --amber | --ink-reversed | Marketing calls to action aimed at businesses. |
| CTA — B2C | --signal | --ink | Marketing calls to action aimed at consumers. |
| Secondary | None | --ink | Hollow, carrying only the inset hairline. Pairs with any of the three above. |
- Never
--brand. Violet is the chart highlight and the focus ring. It is not a button fill, in either theme. - A CTA is not an interface button. Amber and neon belong on marketing surfaces. Inside the product, the primary action is ink.
- One CTA to a view. Two competing fills means neither is the call.
- No third label colour. A button label is
--inkor--ink-reversed. Not muted, not an accent, not a ramp ink.
A label is only ever --ink or --ink-reversed. The two are a mirror — #0f0c15 and #f5f4f4 — and they swap places with the theme, so the primary button is dark on light and light on dark at 17.65:1 either way. Amber and neon hold the same value in both themes, so their labels are frozen at the light-mode pair rather than swapping: --ink on neon at 16.92:1, --ink-reversed on amber at 2.83:1.
Chips
A short categorical label in a pill of air. No fill, no colour — just the inset hairline and ink
Anatomy
A chip is transparent. The edge is the same inset hairline that defines a card, bent around a pill, so a row of chips reads as structure rather than as buttons.
Standalone
Under a label, in a content columnProducts live & launching
Card footer
Pinned to the bottom, one step quieterChips in a card sit last and stay last, so a row of cards lines its chips up on one baseline no matter how much copy sits above them.
The rules
Inherited wholesale from Kantha. The chip is a label, not a control — nothing about it should invite a press.
| Property | Rule |
|---|---|
| Shape | Pill, 999px |
| Fill | none |
| Edge | var(--inset) |
| Type | 0.75rem, weight 600, --ink |
| Type as a card footer | Steps down to 0.6875rem on .card--chips |
| Layout | .chips is a wrapping flex row |
- Never a filled chip. No
--brand, no--amber, no neon. The moment a chip takes a fill it reads as a CTA. - Chip type is always
--ink. Not muted, not an accent. A chip that needs a colour is a pill. - Labels, not sentences. A few words. Products, channels, tags, categories.
The hairline is --inset-edge, ink at 20%, so it inverts with the theme and the chip holds its edge on either ground without ever carrying a fill.
Chip or pill?
They look alike and they are not interchangeable. The difference is whether the label carries a state.
Chip
Neutral and countable. A chip names a thing. Every chip in a row carries the same weight, so the set reads as a list.
Pill
Carries a state. A pill takes a fill and a colour precisely because it is saying something about status, so it is never neutral.
Markup
<p class="chips__head">Products live & launching</p> <div class="chips chips--tight"> <span class="chip">Pay by bank</span> <span class="chip">Card</span> </div> <!-- as a card footer --> <div class="card card--chips"> … <div class="chips"><span class="chip">Slack</span></div> </div>
Data visualisation
Charts sit on white cards on the paper stage. Colour lives on fills and strokes, and reaches type only where it has to tie back to a graph
Chart ramps
Two scales, seven steps each. Violet for categories that need ranking or mix; ink-grey for quiet series. Both invert between themes on their middle step, so a step means the same thing in either one — index 0 always carries, index 6 is always the quietest.
Categorical — violet
--c0 … --c6Channels, payment methods, stacked areas. The brand ramp interpolated to seven steps, from --indigo through --brand to --mist, pivoting on --c3. Series should be drawn from --c1 to --c4; --c0 is the extreme and is held back for emphasis, and the last two steps are too close to the stage to carry a series on their own.
Sequential — ink
--s0 … --s6Greyscale series where nothing needs to shout. Seven neutrals from --ink to --silver, with --carbon between --ink and --graphite, pivoting on --s3. The tail sinks into the surface on purpose — in dark mode --s5 is the card fill and --s6 is the stage, so they read as absence rather than as a step. Default bar fill is --silver — a bar only takes colour when it is making a point.
The fade
The one rule that makes a Stitch chart recognisable. Violet and amber fills ramp from full opacity to 15%. Direction depends on the shape.
Bars and pillars — solid at the tip
The value end is solid; the origin dissolves. A horizontal bar growing right uses a 270deg gradient.
Areas — solid at the series
Under a line the fade runs the other way — full opacity where it meets the stroke, 15% at the baseline.
Do not fade line strokes, legend swatches, ring segments, scatter bubbles or cohort cells. They stay solid.
Horizontal stat bars
Track 7–9 px, pill radius. Default fill is --silver — a bar only takes colour when it is making a point.
Volume by payment method
Last 30 daysThe 1.5 px tick on the first bar is a reference marker — last period, target, or category median.
Bar variants
| Variant | Fill | Use |
|---|---|---|
| Default | --silver | Quiet comparison |
| Violet | --brand fade | The series in focus |
| Amber | --amber fade | Cost, warning, lapse |
| Steel | --s3 / --steel | Long tail, "other" |
| Ranked | --bar-fade by val/max | Ordered league tables |
Vertical pillars and lines
Pillars take rx="3" and fade top to base. Lines are 2 px with round caps and joins.
Transactions per month
ThousandsAcceptance rate
Two seriesComposition
Stacked areas and rings both draw from the categorical ramp. On a stack, only the bottom band fades.
Channel mix
100% stackedSettlement split
Solid strokesChange over a period
Waterfalls and divergence bars both compare against a baseline rather than a total.
Volume bridge
Q1 → Q2Where it sells
Online lean vs in-storeDensity and correlation
Heatmaps ramp electric → neon → amber with opacity from 10% to 100%. Cohort cells quantise onto the categorical ramp. Scatter bubbles stay solid.
Volume by hour
Mon–SunRetention by cohort
Month 0–7Retention quantises onto the categorical ramp — --c0 at month 0, --c6 once a cohort is spent. Type is picked per cell against the fill, so the grid inverts cleanly with the theme.
Volume against margin
Four quadrantsChart rules
- Grey bars are silver, and silver goes darker in dark mode.
- Filled violet and amber fade 100% → 15%. Bars solid at the tip, areas solid at the series.
- Rings, bubbles, legend chips and lines stay solid.
- Legend swatches are pills matching the series before any fade is applied.
- Axis ticks are
--ink3at 10.5 px, gridlines are--grid.
Colour on type
Type is ink by default. Colour reaches it in two places only — a label that has to be read against a graph, and a negative figure in a table.
Settlement by region
Change on Q1| Region | Volume | Change |
|---|---|---|
| South Africa | R 4.82 bn | +12.4% |
| Nigeria | R 1.19 bn | −3.8% |
| Kenya | R 840 m | +6.1% |
| Ghana | R 312 m | −18.2% |
Negatives are --amber and keep their minus sign. Amber on a white card is 3.11:1, so the sign is what carries the meaning — the colour only makes the column scannable.
When type takes colour
- A label read against a graph. A series name, an inline value, a legend label — anything the eye has to match to a fill or a stroke takes that series colour.
- A negative value in a table.
--amber, with the minus sign kept. The one place colour lands on type with no chart beside it.
- Chart titles, KPI values and body copy. Nothing correlates to these, so colour on them is decoration.
- Violet type, anywhere. Brand is a fill and a focus ring. It has no voice, so it never becomes a letterform — use the series colour from the ramp instead.
- Colour as the only signal. A red-green delta with no sign and no label is unreadable to a third of people. There is no green here anyway.
Downloads
Everything in this guide, packaged — with the written specifications alongside as markdown
Logo pack
Wordmark, symbol, reversed and single-colour variants in SVG, PNG, PDF and AI.
↓stitch-logos.zipType pack
Suisse Intl in four cuts — WOFF2 for web, OTF and TTF for desktop.
↓stitch-fonts-suisse-intl.zipSlide template
Grid, layouts and data-vis rules for the deck template, as markdown.
↓PRESENTATIONS.mdToken sheet
Drop into any stylesheet:root {
--white: #ffffff; --paper: #fcfbfb; --platinum: #f5f4f4;
--silver: #dddcdd; --titanium: #b5b3b6; --steel: #56545a;
--graphite: #2e2b33; --carbon: #16131c; --ink: #0f0c15;
--brand: #6e2cff; --amber: #ff5b00; --signal: #daff35;
--electric: #59fcf9; --danger: var(--amber);
/* accent ramps */
--indigo: #221244; --lavender: #c4c0ff; --mist: #e3deff;
--bronze: #3f1711; --peach: #fddcc9;
--slate: #0e242c; --spring: #f8ffda; --ice: #d1fffe;
/* type on an accent */
--brand-ink: var(--indigo); --amber-ink: var(--bronze); --signal-ink: var(--slate);
--bg: var(--paper); /* the stage */
--raised: var(--white); /* cards and the sidebar */
--ink-reversed: #f5f4f4; /* mirrors --ink; swaps in dark */
--ink2: color-mix(in srgb, var(--ink) 62%, transparent);
--ink3: var(--steel);
--muted: color-mix(in srgb, var(--ink) 45%, transparent);
--grid: color-mix(in srgb, var(--ink) 8%, transparent);
--inset-edge: color-mix(in srgb, var(--ink) 20%, transparent);
--r: 1.5rem; --r-m: 16px; --r-s: 12px;
--sans: 'Suisse Intl', -apple-system, BlinkMacSystemFont, sans-serif;
}