---
name: Robin of Loxley
description: One look for every app in the family. Fair tools, fairly priced.
colors:
  sherwood: "#10261A"
  lincoln-green: "#1F4D35"
  lincoln-green-hover: "#2E6A4A"
  moss: "#DCE7D8"
  scarlet: "#C0392B"
  scarlet-soft: "#F6DAD5"
  gold: "#D4A23C"
  gold-deep: "#A87A1E"
  straw: "#E9D7A6"
  yew: "#6B4A2B"
  parchment: "#F5EFE1"
  linen: "#FCF9F2"
  ink: "#17201A"
  ink-soft: "#4A554D"
  ink-faint: "#636C65"
  band: "#17201A"
  accent-myownsession: "#217567"
  accent-myownedu: "#3E3A9E"
  accent-myownarc: "#1F4E79"
  accent-myownmenu: "#B23A0B"
  accent-myownlingo: "#C2185B"
  accent-myownteach: "#6E2B6E"
  accent-myownpurse: "#566314"
typography:
  display:
    fontFamily: "Gloock, Georgia, 'Times New Roman', serif"
    fontSize: "clamp(2.5rem, 1.75rem + 3vw, 3.75rem)"
    fontWeight: 400
    lineHeight: 1.08
    letterSpacing: "-0.01em"
  headline:
    fontFamily: "Gloock, Georgia, 'Times New Roman', serif"
    fontSize: "clamp(1.75rem, 1.4rem + 1.4vw, 2.25rem)"
    fontWeight: 400
    lineHeight: 1.08
  title:
    fontFamily: "Gloock, Georgia, 'Times New Roman', serif"
    fontSize: "1.5rem"
    fontWeight: 400
    lineHeight: 1.15
  body:
    fontFamily: "'Hanken Grotesk', 'Helvetica Neue', Arial, sans-serif"
    fontSize: "1rem"
    fontWeight: 400
    lineHeight: 1.6
  lede:
    fontFamily: "'Hanken Grotesk', 'Helvetica Neue', Arial, sans-serif"
    fontSize: "1.125rem"
    fontWeight: 400
    lineHeight: 1.6
  label:
    fontFamily: "'Hanken Grotesk', 'Helvetica Neue', Arial, sans-serif"
    fontSize: "0.8125rem"
    fontWeight: 700
    letterSpacing: "0.08em"
rounded:
  sm: "4px"
  md: "6px"
  dot: "999px"
spacing:
  "1": "4px"
  "2": "8px"
  "3": "12px"
  "4": "16px"
  "5": "24px"
  "6": "32px"
  "7": "48px"
  "8": "64px"
  "9": "96px"
components:
  button-primary:
    backgroundColor: "{colors.lincoln-green}"
    textColor: "{colors.linen}"
    rounded: "{rounded.sm}"
    padding: "0 18px"
    height: "44px"
  button-secondary:
    backgroundColor: "transparent"
    textColor: "{colors.ink}"
    rounded: "{rounded.sm}"
    padding: "0 18px"
    height: "44px"
  button-go:
    backgroundColor: "{colors.scarlet}"
    textColor: "{colors.linen}"
    rounded: "{rounded.sm}"
    padding: "0 18px"
    height: "44px"
  button-gold:
    backgroundColor: "{colors.gold}"
    textColor: "{colors.sherwood}"
    rounded: "{rounded.sm}"
    padding: "0 18px"
    height: "44px"
  input:
    backgroundColor: "{colors.linen}"
    textColor: "{colors.ink}"
    rounded: "{rounded.sm}"
    height: "44px"
  card:
    backgroundColor: "{colors.linen}"
    rounded: "{rounded.md}"
    padding: "24px"
  tag:
    backgroundColor: "{colors.moss}"
    textColor: "{colors.lincoln-green}"
    rounded: "3px"
    padding: "2px 8px"
  table-head:
    backgroundColor: "{colors.band}"
    textColor: "{colors.parchment}"
    typography: "{typography.label}"
---

# Design System: Robin of Loxley

This file is for anyone, human or agent, building a page or screen for an
app in the family. `BRAND.md` holds the story, the mark and the voice; this
file holds the system. The values live in `tokens.css`, the pieces in
`components.css`, and the Tailwind bridge in `tailwind.css`. If this file and
those disagree, the CSS wins: fix this file.

## Overview

**Creative North Star: "The Woodcut Ledger"**

Plain, fair and a little old-English. A page should look like a well-set
notice: a near-black band at the top, parchment below, square-ish corners,
heavy ink where it matters and nowhere else. The family is recognisable from
its type and its skeleton, and each app is recognisable from one accent
colour and its own mark.

Every app shares one skeleton:

| App | Domain | Accent | `data-rol-app` |
|---|---|---|---|
| Robin of Loxley | robinofloxley.com | Lincoln green `#1F4D35` | `robinofloxley` |
| MyOwnSession (was Faresay) | myownsession.com | Session teal `#217567` | `myownsession` |
| MyOwnEdu (was fair-do) | myownedu.com | Slate indigo `#3E3A9E` | `myownedu` |
| MyOwnArc | myownarc.com | Library blue `#1F4E79` | `myownarc` |
| MyOwnMenu | myownmenu.com | Persimmon `#B23A0B` | `myownmenu` |
| MyOwnLingo | myownlingo.com | Raspberry `#C2185B` | `myownlingo` |
| MyOwnTrader | myowntrader.com | Lincoln green `#1F4D35` | `myowntrader` |
| MyOwnReach | myownreach.com | Lincoln green `#1F4D35` | `myownreach` |
| MyOwnLarder | myownlarder.com | Lincoln green `#1F4D35` | `myownlarder` |
| MyOwnTeach | myownteach.com | Damson `#6E2B6E` | `myownteach` |
| MyOwnPurse | myownpurse.com | Olive `#566314` | `myownpurse` |

The family shares type, neutrals, layout, components, motion and voice.
Each app owns its accent, its mark beside a Gloock wordmark, the proof in
its hero (a product shot, a price card) and its density.

**Key characteristics:**
- Gloock for display, Hanken Grotesk for everything else. No other faces.
- Warm neutrals only. No cold greys, no pure white pages.
- 4px corners on controls, 6px on cards. Pills only for dots and number discs.
- One accent per app, one scarlet action per screen, gold only on dark.
- Prices always come as a pair: theirs struck through in scarlet, ours in the accent.

## Colors

Lincoln green does the work, scarlet speaks rarely, gold is the centre of
the target, and the neutrals are parchment and ink.

### Primary
- **Lincoln green** (`#1F4D35`): the family primary and the accent for robinofloxley.com, MyOwnTrader, MyOwnReach and MyOwnLarder. Buttons, links, our prices.
- **The app accent** (`--rol-accent`): one per app, from the table above. Primary buttons, links, focus rings and the app's own price. Hover and tint are mixed from it (`--rol-accent-hover`, `--rol-accent-soft`), so an app sets one value per theme. Every accent passes AA with linen text on it.

### Secondary
- **Scarlet** (`#C0392B`): their price, struck through; the one most important action on a screen (`.rol-btn--go`); errors and alerts. Never decoration.

### Tertiary
- **The gold** (`#D4A23C`): the centre of the target. Numbers and highlights on the dark band, the target dot. Never text on a light page (it fails contrast).
- **Straw** (`#E9D7A6`) and **yew** (`#6B4A2B`): the butt and the bow. Fills, rules, text selection, small detail.

### Neutral
- **Parchment** (`#F5EFE1`): the page.
- **Linen** (`#FCF9F2`): cards, tables, inputs, text on accent buttons.
- **Ink** (`#17201A`): text, the 2px rule, table heads, the band.
- **Ink soft** (`#4A554D`) and **ink faint** (`#636C65`): secondary text and small print. Both pass AA on parchment and linen.
- **Moss** (`#DCE7D8`): status tags and quiet fills.
- **Lines**: `--rol-line` (12% ink) for hairlines, `--rol-line-strong` (24% ink) for input and button outlines.

Dark mode is in `tokens.css`, both for `prefers-color-scheme` and for a page
that sets `data-theme="dark"`. Each accent has a lighter partner of the same
hue for dark, and text on it turns dark.

### Named Rules
**The One Accent Rule.** An app has one accent. Its primary button, its links and its own price are that colour. Nothing else is.

**The One Scarlet Rule.** At most one scarlet button per screen. If two actions both feel that important, neither is.

**The Gold Is Not Text Rule.** Gold appears on the dark band or as the centre of a target dot, never as text on parchment or linen.

## Typography

**Display Font:** Gloock (with Georgia, Times New Roman)
**Body Font:** Hanken Grotesk (with Helvetica Neue, Arial)

**Character:** a bookish, high-contrast serif with a little of the ballad
about it, over a plain, warm grotesk that does all the reading. Both are SIL
OFL and self-hosted from `fonts/`.

### Hierarchy
- **Display** (Gloock 400, 40 to 60px fluid, line-height 1.08): the one h1 on a marketing page. `.rol-h1`, Tailwind `text-h1 font-display`.
- **Headline** (Gloock 400, 28 to 36px fluid, 1.08): section headings. `.rol-h2`, `text-h2`.
- **Title** (Gloock 400, 24px, 1.15): card headings, app names, our prices. `.rol-h3`, `text-h3`.
- **Lede** (Hanken Grotesk 400, 18px, 1.6, max 60ch): the paragraph under an h1 or h2. `.rol-lede`, `text-lede`.
- **Body** (Hanken Grotesk 400, 16px, 1.6, max 68ch): everything you read. Interface text, buttons and nav are 16px or 15px at 500 to 600.
- **Small** (Hanken Grotesk 400, 13px): small print, sources, footers. `.rol-small`, `text-small`.
- **Label** (Hanken Grotesk 700, 13px, 0.08em, capitals): table heads and data labels. `.rol-label`.

### Named Rules
**The 24px Rule.** Gloock is for 24px and up. Below that, and on every logged-in screen except the wordmark, it is Hanken Grotesk.

**The 13px Floor.** Nothing on any page is smaller than 13px. Not a tag, not a footnote.

**The No Eyebrow Rule.** No small capital label above a heading. The heading carries its own weight. Capitals belong to table heads and data labels.

**The Plain Headline Rule.** Don't colour, italicise or bold one word of a headline for effect. The one exception is a price, which is information.

## Layout

One centred column, `--rol-container` 1120px wide, with a fluid gutter of
16 to 32px (`.rol-container`). Sections are padded 48 to 96px top and bottom
(`--rol-section`). Spacing comes from a 4px scale (`--rol-space-1` to `-9`);
use gap on flex and grid rather than margins.

**Header** (`.rol-header`): 64px. Mark and Gloock wordmark on the left, three
or four links, then Sign in and one primary button. On the dark band use
`.rol-header--band`. Under 760px the links fold into a `<details>` menu and
Sign in moves into it; nothing wraps.

**Hero:** left-aligned. Headline, a lede, two buttons (primary and
secondary), then the app's proof on the right: a product shot or the price
pair. On a phone the proof goes under the buttons. At most one hero band per
page.

**Footer** (`.rol-footer`): link columns, then one legal row with the
badge. The legal line is always: "© 2026 [App]. [App] is a Robin of Loxley
app. Robin of Loxley is a trading name of Faresay Ltd, registered in England
and Wales, company number 17302034." Update every app when the company
name changes.

**Measure:** body text 60 to 70 characters. The robinofloxley.com home page
fits a 1440 x 900 screen without scrolling; app landing pages may scroll.

**Breakpoints:** 760px (header folds), 720px (the band drops its photo).
Everything else reflows with `auto-fit` grids.

## Elevation & Depth

Flat by default. Surfaces separate by tone (parchment page, linen card) and
by hairlines, not by shadows.

### Shadow Vocabulary
- **The woodcut** (`box-shadow: 8px 8px 0 var(--rol-ink)` with a 2px ink rule, `.rol-surface`): the one important surface per page, such as the price table or the comparison. It is a printmaker's offset, not a lift.
- **Focus** (`outline: 2px solid var(--rol-accent); outline-offset: 2px`): every focusable thing.

### Named Rules
**The One Woodcut Rule.** One `.rol-surface` per page. Cards get a hairline and no shadow. Never a card inside a card.

## Shapes

Square-ish and printed. 4px on buttons, inputs, tags and chips
(`--rol-radius`); 6px on cards and surfaces (`--rol-radius-lg`). Round is
reserved for the target: the target dot before our price and number discs.
Borders are 1px hairlines or the 2px ink rule; never a thick coloured stripe
down one side of a card.

## Components

Load `tokens.css`, then `components.css`. Put `data-rol-app` on `<html>` and,
if the app isn't styling the body itself, `class="rol"` on `<body>`.

### Buttons

```html
<a class="rol-btn rol-btn--primary" href="/signup">Start free</a>
<a class="rol-btn rol-btn--secondary" href="/compare">Compare with Jobber</a>
<button class="rol-btn rol-btn--go" type="submit">Pay £15</button>
```

44px tall, 4px corners, Hanken Grotesk 600. Primary is the accent;
secondary is an ink outline; `--go` is scarlet, once per screen; `--gold`
and `--band` are for the dark band; `--sm` (36px) is for dense app screens
only. They press to `scale(0.97)` in 160ms with the strong ease-out.
Labels say what happens: "Start free", "Save changes", not "Submit".

### Price pair

```html
<div class="rol-price">
  <div class="rol-price__them">Jobber Core, plus a helper <s>$78</s></div>
  <div class="rol-price__us"><span class="rol-dot" aria-hidden="true"></span>£15 a month</div>
  <p class="rol-price__source">From getjobber.com/pricing, checked September 2026.</p>
</div>
```

Always a pair, always with the source and the month checked.

### Header

```html
<header class="rol-header">
  <div class="rol-container rol-header__inner">
    <a class="rol-header__brand" href="/"><img src="/brand/app-mark.svg" alt="">MyOwnTrader</a>
    <nav class="rol-header__nav" aria-label="Main">
      <a href="/#features">Features</a><a href="/#pricing">Pricing</a><a href="/compare">Compare</a>
    </nav>
    <div class="rol-header__actions">
      <a class="rol-header__secondary rol-btn rol-btn--secondary" href="/login">Sign in</a>
      <a class="rol-btn rol-btn--primary" href="/signup">Start free</a>
    </div>
    <details class="rol-header__menu">
      <summary aria-label="Menu"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round"><path d="M4 7h16M4 12h16M4 17h16"/></svg></summary>
      <nav class="rol-header__menu-panel" aria-label="Menu">
        <a href="/#features">Features</a><a href="/#pricing">Pricing</a><a href="/compare">Compare</a><a href="/login">Sign in</a>
      </nav>
    </details>
  </div>
</header>
```

### Footer and badge

```html
<footer class="rol-footer">
  <div class="rol-container">
    <div class="rol-footer__cols">...</div>
    <div class="rol-footer__legal">
      <p>© 2026 MyOwnTrader. MyOwnTrader is a Robin of Loxley app. Robin of Loxley is a trading name of Faresay Ltd, registered in England and Wales, company number 17302034.</p>
      <a class="rol-badge" href="https://robinofloxley.com" aria-label="A Robin of Loxley app">
        <picture>
          <source srcset="/brand/badge-reversed.svg" media="(prefers-color-scheme: dark)">
          <img src="/brand/badge.svg" alt="A Robin of Loxley app" width="164" height="40">
        </picture>
      </a>
    </div>
  </div>
</footer>
```

The badge's text is always "A Robin of Loxley app", matching the SVG. In
apps with locale files (MyOwnSession, MyOwnEdu, MyOwnMenu, MyOwnLingo) it
lives there.

### Inputs

```html
<div class="rol-field">
  <label class="rol-field__label" for="email">Email</label>
  <input class="rol-input" id="email" type="email" autocomplete="email">
  <p class="rol-field__hint">We send the receipt here.</p>
</div>
```

44px, 16px text (so iOS doesn't zoom), a 2px accent ring on focus. Errors
name the problem and the fix, in `.rol-field__error`, with
`aria-invalid="true"` on the input.

### Also
- `.rol-card`: linen, hairline, 6px, 24px padding, no shadow.
- `.rol-surface`: the woodcut, once per page.
- `.rol-tag`: moss status tag ("Early access").
- `.rol-band`, `.rol-band--quiver`: the dark top band, with the quiver photo on wide screens.
- `.rol-table` in `.rol-table-wrap`: ink head row with capital labels, tabular figures.
- `.rol-link`: accent, underlined at a 3px offset.

### Icons
Lucide, 1.75px stroke, 20 or 24px, `currentColor`. Inline SVG or the
`lucide` package; no icon fonts. No emoji as icons, and no emoji flags (they
show as letters on Windows): use SVG flags.

### Motion
- Presses and hover colour: 160ms (`--rol-dur-press`). Menus, popovers, tooltips: 200ms (`--rol-dur-ui`). Nothing over 300ms (`--rol-dur-max`).
- Entering and pressing: `--rol-ease-out` (`cubic-bezier(0.23, 1, 0.32, 1)`). Moving on screen: `--rol-ease-in-out`. Never ease-in.
- Popovers grow from their trigger (`transform-origin` at the trigger); dialogs from the centre. Never from `scale(0)`; start at 0.95 with opacity.
- No animation on anything used dozens of times a day (keyboard actions, list navigation).
- `prefers-reduced-motion` sets every duration token to 0. Pulsing dots only for live data.

## App shell

The signed-in side of every app is one shell, in `app.css` (load it after
`tokens.css` and `components.css`), with icons from the sprite `icons.svg`.
It follows the theme, so leave `data-theme` off `<html>` inside the app and
dark mode works.

```html
<body class="rol-app rol-app--tabbar">
  <aside class="rol-sidebar">
    <a class="rol-sidebar__brand" href="/"><img src="/static/icon.svg" alt="">MyOwnTrader</a>
    <div class="rol-sidebar__meta">Harvey Plumbing</div>
    <nav aria-label="Main">
      <ul class="rol-nav">
        <li><a class="rol-nav__link" href="/" aria-current="page">
          <svg class="rol-icon" aria-hidden="true"><use href="/static/rol/icons.svg#house"></use></svg>Today</a></li>
        ...
      </ul>
    </nav>
    <div class="rol-sidebar__foot">...name, role, Sign out...</div>
  </aside>
  <main class="rol-main"><div class="rol-page">
    <div class="rol-page-head"><h1 class="rol-page-title">Jobs</h1><a class="rol-btn rol-btn--primary">New job</a></div>
    ...
  </div></main>
  <nav class="rol-tabbar" aria-label="Quick">...four or five links...</nav>
</body>
```

- **Sidebar**: the band, 248px, the app's mark and Gloock wordmark, then the
  nav. The current page has `aria-current="page"`, a lighter fill and a gold
  icon. Under 900px it becomes a band across the top with the links in one
  row that scrolls sideways; `.rol-tabbar` adds a bottom bar for the few
  things done most (add `rol-app--tabbar` to make room for it).
- **Type**: Hanken Grotesk only. `.rol-page-title` is 26px at 650,
  `.rol-section-title` 17px. Gloock appears once, in the wordmark.
- **Panels**: `.rol-panel` is the card inside an app. Never one inside
  another; use a hairline or a heading to split one instead.
- **Numbers**: `.rol-stats` holds `.rol-stat` tiles (`__value`, `__label`).
- **Messages**: `.rol-banner` with `--info`, `--ok`, `--warn` or `--danger`,
  above the page head. Words first, a link to the fix second.
- **Status**: `.rol-tag` with `--ok`, `--warn`, `--bad`, `--muted` or
  `--accent`. 3px corners, never a pill.
- **Lists**: `.rol-table.rol-table--quiet` in `.rol-table-wrap`: no ink head
  row (that's for the one comparison on a public page), a row hover.
- **Icons**: `<svg class="rol-icon"><use href="…/icons.svg#name"></use></svg>`,
  20px (`--sm` 16, `--lg` 24). The names are the Lucide names. Need another?
  Add it to `icons.svg` here from lucide.dev, then pull.

## Do's and Don'ts

**Do**
- Import `tokens.css` and use `--rol-*` variables. Change the brand in `robinofloxley/brand`, then pull it into each app.
- Set the accent with `data-rol-app`, never by overriding `--rol-accent` in an app.
- Show their price beside ours, with the source and month in small print.
- Check new colour pairs with `python3 brand/check_contrast.py`.
- Screenshot at 1440 x 900 and 390 x 844, light and dark, before shipping.
- Keep `python3 <kit>/design_check.py <live url> --strict` clean: no contrast failures, overflowing or hidden text, or text under 13px.

**Don't**
- Use Inter, Roboto, Fraunces, Bricolage Grotesque or a system font stack.
- Use pill buttons, `rounded-2xl` cards, purple gradients or soft grey drop shadows.
- Use emoji in navigation, as icons or as a favicon, or a system font inside an app.
- Put a small capital label above a heading, number things that aren't a sequence, or join a line of claims with middle dots.
- Put a thick coloured border down one side of a card, or nest cards.
- Use em-dashes, "genuinely", "simply", "unlock", "transform" or "isn't just X, it's Y" in anything that renders.
- Talk about stealing, robbing or theft. We take the margin, not anyone's money.
