Design System: Warrington + Rose Store
Overview
Creative North Star: "The Ruled Index"
The store reads like a printed index. Big light type sits between thin ink rules, and every row answers a question. The wordmark runs the full width of the page, top and bottom. Photographs are the only colour most screens carry, and each one sits in a flat mat.
The system is flat and quiet. There are no shadows and no outlined cards. Structure comes from 1px rules, generous space and a strict split between two voices. AUTHENTIC Sans speaks. Space Mono labels, prices and measures.
One stylesheet carries three looks. A data-look attribute on the html element swaps tokens and nothing else in the markup. MOK, the outdoor kitchen sub-brand, is a separate world inside the same header and footer.
Key Characteristics:
- Full-width wordmark between hairlines, in the home band and the footer.
- Light sans display type, set tight, at near-wordmark scale.
- Space Mono in uppercase for navigation, prices, measurements and short labels.
- 1px ink rules divide everything. No boxes, no shadows.
- Photos sit in flat mats. Real pieces, never generated.
- Pills for actions, circles for badges and colour swatches.
The three looks
The look is set by data-look on the html element. Gallery is the default and needs no attribute. A boot script reads ?look= or the last saved choice before first paint. Components never test the look in code.
Gallery is today's brand done properly. It uses the root token values in the frontmatter: paper ground, ink text, tile-grey mats, sand "New" badges, ink buttons and chips.
Workshop is warmer and bigger. It changes these tokens. Ground becomes sand. Text and rules become workshop ink (#2a2521). Muted text becomes workshop muted (#4d4741), so it still passes on sand. Tile and mat become paper. The "New" badge becomes paper. Route hover becomes workshop hover (#e0d6cb). The minimum tile width grows from 168px to 230px. Tile padding grows to clamp(10px, 1.8vw, 24px). Route thumbnails grow from 76px to 96px.
Signal is bolder and borrows MOK orange on purpose. It changes these tokens. Accent, "New" badge, route hover and selected chip all become MOK orange, each carrying ink text. Display type grows to clamp(2.5rem, 7.4vw, 6rem), tracks tighter at -0.045em, sets at 0.92 leading and moves up to weight 400. The headline step grows to clamp(2.5rem, 1.6rem + 4vw, 5.75rem). A 4px orange bar appears along the top of the header. Signal keeps the paper ground.
Flag: a few look-scoped rules in globals.css style components directly instead of swapping a token. In Signal, the route fact becomes an orange pill, the route fact turns ink on hover, and the Bespoke tile turns orange. In Workshop, the made-to-order tile image ground turns paper. They live in globals.css, so the "tokens in globals.css only" rule holds at file level. They are not pure token swaps.
The MOK sub-world
Every MOK page wraps its content in a .mok container. That container re-declares the tokens locally. Ground becomes MOK cream. Text and rules become MOK charcoal. Muted becomes MOK muted (#5c5650). Tile becomes MOK sand. Accent and selected chip become MOK orange with ink text. The base font becomes Bai Jamjuree.
MOK headings use Bai Jamjuree at 600, in uppercase, tracked at -0.02em. The hero title sets one line in orange text (#c24300), never in #ff5d00. MOK has one dark band: charcoal ground with cream text.
The store header, footer and demo dock stay in the parent look. Because MOK re-declares colour tokens, the look switcher barely touches MOK. Signal's type scale and orange header bar still apply. Workshop's tile and thumbnail sizes still apply.
Colors
Monochrome ink on paper, with sand and tile grey as quiet grounds, and colour reserved for photographs, sold badges and MOK.
Primary
- Ink (#212121): all text, all rules, primary buttons, selected chips, the Bespoke tile ground, the focus outline and text selection. In Gallery it is the only accent.
Secondary
- MOK Orange (#ff5d00): a ground colour only. Buttons, chips, badges and the header bar in Signal and on MOK pages. It always carries ink text.
- MOK Orange Text (#c24300): the only orange allowed as text. Used for the orange line of the MOK hero title. It reaches about 4.7:1 on cream.
Tertiary
- Sold Coral (#ff6b6b): the circular "Sold" badge, with ink text. Nowhere else.
- Error Red (#b3261e): field errors, invalid input underlines, and form-level errors. It is hard-coded in two places, not a token.
Neutral
- Paper (#fefefe): the default ground, the inner mat behind photos, and Workshop tiles.
- Sand (#e9e1d8): the "New" badge in Gallery and the whole ground in Workshop.
- Tile Grey (#f2f1ee): the mat around photographs, gallery thumbnails and basket line images, and route hover in Gallery.
- Muted Grey (#595959): secondary text, breadcrumbs, facts, mono labels, captions.
- Soft Rule (ink at 18% via color-mix): inner dividers inside a ruled block, such as spec rows, assurance rows, summary lines, footer legal and the demo note.
- MOK Cream (#fff5e1), MOK Sand (#e3d8c5), MOK Charcoal (#2e2e2e), MOK Muted (#5c5650): the MOK ground, tile, text and rule, and muted text.
- Workshop Ink (#2a2521), Workshop Muted (#4d4741), Workshop Hover (#e0d6cb): Workshop's warmer text, muted text and route hover.
Named Rules
The Orange Ground Rule. #ff5d00 is a background, never text. Orange grounds carry ink text, never white. Orange text is always #c24300.
The Photograph Is The Colour Rule. Outside MOK and Signal, the interface stays ink, paper, sand and grey. Colour on screen comes from real photographs and real colour swatches.
Typography
Display Font: AUTHENTIC Sans (with Helvetica Neue, Helvetica, Arial)
Body Font: AUTHENTIC Sans (same stack)
Label/Mono Font: Space Mono (with ui-monospace, SFMono-Regular, Menlo)
MOK Font: Bai Jamjuree, MOK pages only
Character: A light, open grotesque that speaks, against a typewriter mono that counts. Two cuts of AUTHENTIC Sans ship. The "60" cut is mapped to weight 300 and the "90" cut to weight 400.
Hierarchy
- Display (300, clamp(2.25rem, 6vw, 5.75rem), leading 1): the four home route rows only. Signal makes it larger, heavier and tighter.
- Headline (300, clamp(2.25rem, 1.5rem + 3.4vw, 5rem), leading 1): page titles and piece titles, capped at 16ch.
- Title (300, clamp(1.625rem, 1.3rem + 1.5vw, 2.75rem), leading 1.08): section titles, collection titles, the confirmation title.
- Lede (300, clamp(1.25rem, 1.12rem + 0.6vw, 1.75rem), leading 1.3): the opening sentence of a page, room titles, card titles, the piece colour. Capped at 40 to 44ch. On the home page, the question "What are you looking for?" is a second lede line in muted grey, pulled up a step to sit with the sentence above it.
- Small heading (display weight, lede size): the samples family headings, such as a colour family name, and the basket "Summary" heading. Display weight is 300, or 400 in Signal.
- Body (400, clamp(1rem, 0.96rem + 0.2vw, 1.1875rem), leading 1.5): running text. Prose is capped at 62ch.
- Small (400, 0.875rem): hints, assurances, footer columns, line details, note text, and the colour family names in the made-to-order picker, in muted grey.
- Label (Space Mono 400, clamp(0.75rem, 0.71rem + 0.18vw, 0.875rem), tracking 0.06em, uppercase): navigation, breadcrumbs, buttons, chips, form labels, route facts, footer headings and figure captions.
- Measure (Space Mono 400, label size, tracking 0.02em, uppercase): dimensions and weight in a spec list, and nothing else in that list. Other spec values, such as colour and origin, are body sans.
- Price (Space Mono 400, lede size, tracking 0.02em): the price on a piece page. Basket and summary prices use the label size.
- Micro label (Space Mono, 0.6875rem): badges, colour counts under tiles, swatch states and sample references.
Named Rules
The Two Voices Rule. AUTHENTIC Sans says things. Space Mono names and counts things. Never set a sentence in mono, and never set a price or measurement in the sans.
The Glyph Rule. Any string with £, × or a measurement goes in Space Mono. AUTHENTIC Sans lacks £ and ×.
The Never Bold Rule. Sans headings are weight 300. Body is 400. No heavier sans weight exists in the build. A note's lead-in uses a strong element, restyled to body size at 400 on its own line. It is never bolded.
Flag: the brand rule says mono is for navigation, prices and measurements only. The build also uses mono for buttons, chips, form labels, breadcrumbs, figure captions, footer headings, badges and swatch states. This document records the build.
Layout
The page is a single column of full-width bands, each closed by a 1px ink rule. Content sits in a wrapper capped at 1600px with a fluid side gutter (16px to 48px). The wordmark band and the route rows run edge to edge, with the gutter as inner padding.
Vertical rhythm uses five steps. Step 1 is 0.5rem and step 2 is 1rem. Steps 3 to 5 are fluid, from about 1.5rem up to 7.5rem. Sections pad with step 4. Section heads sit a step 3 above their content. A section that follows another section draws a rule between them.
The route row is the signature layout. On phones it is a two-column grid: title and mono fact on the left, a square thumbnail on the right. From 760px on a device with a fine pointer, the mono fact sits under the title, and the photo is hidden in a right column of 180px to 360px. It wipes in from the right on hover or focus. Keeping the fact under the title stops the titles wrapping onto two lines on desktop.
From 760px on touch devices, where there's no hover, the fact also sits under the title and the photo is always visible in a right column of 180px to 360px. Flexible rows above and below keep the title and fact together, centred against a tall photo.
Product grids auto-fill. The minimum tile width is the smaller of the tile token and 44vw, so phones always get two columns. Sample grids work the same way at 140px. Card grids use 300px.
Two-column splits, the piece page, the samples pack and the MOK hero all switch on at 900px. The basket switches at 960px. The piece info column and the basket summary stick below the 52px header.
Horizontal scrollers are used for room photos and filter chips on phones. They bleed to the screen edge, snap, and hide the scrollbar. From 900px they wrap into a grid.
The demo dock is fixed to the bottom. Body padding reserves its 64px height plus the safe area.
Named Rules
The Router First Rule. On the home page, the first viewport is the wordmark, one sentence and the route rows. Nothing sits above the routes.
The 390 Rule. Every page works at 390px wide in all three looks with no sideways scroll. Scrollers bleed by the gutter and pull back with matching padding.
Elevation & Depth
The system is flat. No box-shadow conveys depth anywhere. The only tonal layer is the photo mat: a photo sits on paper inside a tile-grey mat. Asides such as notes and the basket summary are hairline sections, not filled panels. The sticky header and fixed dock sit on the ground colour with a 1px rule, not a shadow.
The one box-shadow in the build is the selected colour swatch. It draws a 2px ground-coloured gap and a 1px ink ring. It is a selection ring, not elevation.
Named Rules
The Hairline Rule. Separation is a 1px rule in the text colour, or a soft rule at 18% inside a ruled block. Never a shadow.
Shapes
Three shapes cover everything. Pills (999px) are for anything you press: buttons, chips, option chips, the quantity stepper, look switcher options and the demo flag. Circles (50%) are for badges and colour swatches. Everything else is square: mats, photos, inputs.
Borders are always 1px. Inputs have a bottom rule only. Photos are cropped with object-fit cover at fixed ratios: 4:5 for pieces and rooms, 1:1 for models and modules, 3:2 for project cards, 4:3 for splits, 16:9 for the MOK hero.
Components
Buttons
The button is a quiet pill that inverts on hover.
- Shape: full pill (999px), minimum 48px tall.
- Primary: accent ground with accent text, in the label style. In Gallery and Workshop that is ink on paper. In Signal and on MOK it is orange with ink text.
- Hover: the fill drops to the ground colour, the text becomes the text colour, and a rule-coloured border remains. Transitions run 160ms.
- Ghost: transparent with a rule border. On hover it fills with the accent.
- Block: full width, used for "Add to basket" on the piece page.
- Disabled: 50% opacity with a not-allowed cursor.
- Text link: mono label with an underline, used for "All designs" style links in section heads.
Chips
- Style: transparent pill with a 1px rule border, 40px tall, in the label style.
- State: pressed chips fill with the chip-on colour and its text colour. Hover adds a 7% ink tint. Option chips in forms are hidden radio or checkbox inputs with the same look, and they draw the focus outline on the visible pill.
Product Tile
The tile is a photo in a mat, then name, colour, mono price and ex-VAT price beneath.
- Mat: the tile colour with tile padding around a 4:5 photo on the mat colour. Hover lowers the photo to 88% opacity and underlines the name.
- Flag: the direction contract says photos sit in white mats. In Gallery the mat is tile grey (#f2f1ee). Only Workshop gives a paper mat.
- Gallery captions: a mono caption under the main piece photo says what it is. "Photographed in our workshop" for the piece's own photos. "Shown with others from the same set" for a group photo shared across pieces. "Render" for renders. The data script marks shared photos and orders them after the piece's own photos, with renders last.
- Badges: circular, 3.25rem, top left inside the mat, micro mono label. "New" uses the badge-new token. "Sold" uses coral. Sold photos drop to 70% opacity with a light greyscale.
- Made-to-order tiles: a 1:1 contained image, then 12px colour dots and a mono count such as "32 colours".
- Bespoke tile: closes a basins grid. A square ink panel with the word in title-size light sans on paper. Orange with ink text in Signal.
Route Row
The home router. Display-size title, a mono fact under it, a photograph, and a 1px rule under each row. Hover and focus fill the row with route hover. The photo reveal uses a 460ms clip-path wipe and a 700ms scale from 1.06 to 1. In Signal the fact becomes an orange pill.
Cards / Containers
- Corner Style: square.
- Background: none. Notes and the basket summary sit on the page ground in every look.
- Shadow Strategy: none. See Elevation & Depth.
- Border: a 1px rule above and below. Ruled lists use a top rule and a rule under each row.
- Internal Padding: step 2, top and bottom only. No side padding.
- Note: a hairline section for honest caveats, such as "This exact piece". Its lead-in is body-size sans at 400 on its own line, then small text. At the top of checkout, the first note drops its top rule and top padding, because the page heading's rule is already above it.
- Basket summary: the same hairline section, with a sans "Summary" heading at lede size, mono amounts and a ruled total. It sticks below the header from 960px.
- Spec list and assurances: a two-column ruled list. Muted term on the left, value on the right, soft rules between rows.
- Partner strip: a grid of ruled cells on paper, three across on phones and six from 900px. Logos use multiply blending.
Inputs / Fields
- Style: no box. Transparent, a 1px bottom rule, square, 48px tall, body size. Labels sit above in the label style. Hints are small and muted.
- Focus: the bottom rule thickens to 2px. No outline is drawn.
- Error: the bottom rule turns error red, and a small red message follows, linked by aria-describedby. Fields set aria-invalid.
- Form error: a failure of the whole form, used in live mode. It shows above the submit button as red text under a 1px red rule, with role alert. It offers the email address as a way out.
- Spam trap: a hidden field for live mode. It sits off screen, out of the tab order, and hidden from screen readers. Never style it visible.
- Select: native appearance removed, with a small drawn chevron in ink.
- Radio rows: full-width ruled rows with an ink-accented radio, a title, a muted line and a mono price.
- File upload: the native file input is visually hidden. A ghost pill button labelled "Add drawings or photos" opens it, and reads "Change files" once files are chosen. The input's focus ring draws on the pill. A small muted hint below lists accepted types and chosen file names. There is no drop box or dashed border; the message field's bottom rule separates it.
Navigation
- Header: sticky, 52px minimum, ground colour, 1px rule beneath. On the home page the left side reads "Home" in mono, because the wordmark band follows. Elsewhere it shows the wordmark at 148px to 260px.
- Wide nav (1000px and up): mono links separated by muted slashes. Hover and current page are underlined. The basket shows its count in brackets once it has items.
- Narrow nav: "Basket" and a "Menu" disclosure. The menu opens a full-width sheet of light lede-size links with soft rules.
- Breadcrumbs: mono, muted, slash-separated.
Colour Swatch
Circular chips filled with the real colour sample photograph over its hex. Selected swatches get the ground gap and ink ring. Hover shrinks the chip to 96%. Names sit below in small sans. States such as "In stock" use micro mono.
Demo Dock
Fixed to the bottom on the ground colour. It holds the dismissible demo note and the look switcher. Look options are pills that fill with the chip-on colour when pressed. It exists for the demo and is not part of the store design.
Do's and Don'ts
Accessibility the build relies on
- Every page has a skip link that drops in on focus, ink on paper.
- The default focus style is a 2px ink outline at 3px offset. Route rows draw it inset at -3px so it stays inside the row.
- Inputs show focus by thickening the bottom rule to 2px.
- The hidden file input passes its focus ring to the visible pill that opens it, and is described by its title and hint.
- Muted text is darkened per world so it passes AA: #595959 on paper, #4d4741 on sand, #5c5650 on cream.
- Orange grounds carry ink text. Orange text uses #c24300.
- In Signal, a hovered route row turns its muted fact to ink so it stays readable on orange.
- Every pressable element is at least 40px tall, and buttons and inputs are 48px.
- Toggles expose state with aria-pressed. Errors use aria-invalid and role alert.
- Reduced motion cuts all transitions to near zero and stops the route photo scale.
- Decorative route photos have empty alt text and sit in an aria-hidden wrapper. Product photos carry real alt text, and a shared group photo says so in its alt text as well as its caption.
Do:
- Do change a look by editing its token block in globals.css. Add a token before adding a look-scoped component rule.
- Do set every price, size, weight and count in Space Mono.
- Do separate content with 1px rules, and use the 18% soft rule inside a ruled list.
- Do put every product photograph in a mat, on the tile colour with tile padding.
- Do use pills for actions and circles for badges and swatches.
- Do wrap MOK content in the .mok container so its tokens apply, and keep the store header and footer outside it.
- Do keep demo mode identical to a build without Medusa settings. Form errors and the spam trap only matter in live mode.
Don't:
- Don't use box-shadow for depth, or put a border box around a card.
- Don't set #ff5d00 as text, or put white text on orange.
- Don't set a sans heading heavier than 300 outside Signal's display scale, and never bold the sans.
- Don't branch a component on the look in TSX.
- Don't use MOK orange, cream or Bai Jamjuree outside MOK pages, except in the Signal look.
- Don't add focusable elements to the charcoal MOK band without a light focus outline. The ink outline disappears on charcoal.
- Don't show a generated product image, or a render without a label.