---
version: alpha
name: "Fernway"
description: "a shared task, docs and files workspace for small teams"
colors:
  background: "#faf8ff"
  surface: "#ffffff"
  border: "#dbd5e7"
  text: "#191522"
  muted: "#666073"
  primary: "#7b34cb"
  on-primary: "#ffffff"
  accent: "#9f5700"
  on-accent: "#ffffff"
  dark-background: "#120f19"
  dark-surface: "#201b28"
  dark-border: "#36313f"
  dark-text: "#edebf3"
  dark-muted: "#b3aebf"
  dark-primary: "#b98eff"
  dark-on-primary: "#111111"
  dark-accent: "#ff9420"
  dark-on-accent: "#000000"
typography:
  h1:
    fontFamily: "Fredoka"
    fontSize: "3.052rem"
    fontWeight: 700
    lineHeight: 1.15
    letterSpacing: "-0.02em"
  h2:
    fontFamily: "Fredoka"
    fontSize: "2.441rem"
    fontWeight: 700
    lineHeight: 1.2
    letterSpacing: "-0.01em"
  h3:
    fontFamily: "Fredoka"
    fontSize: "1.953rem"
    fontWeight: 600
    lineHeight: 1.25
  h4:
    fontFamily: "Fredoka"
    fontSize: "1.563rem"
    fontWeight: 600
    lineHeight: 1.25
  body-lg:
    fontFamily: "Nunito"
    fontSize: "1.25rem"
    fontWeight: 400
    lineHeight: 1.6
  body-md:
    fontFamily: "Nunito"
    fontSize: "1rem"
    fontWeight: 400
    lineHeight: 1.6
  body-sm:
    fontFamily: "Nunito"
    fontSize: "0.8rem"
    fontWeight: 400
    lineHeight: 1.5
  label:
    fontFamily: "Nunito"
    fontSize: "1rem"
    fontWeight: 600
    lineHeight: 1.25
  caption:
    fontFamily: "Nunito"
    fontSize: "0.64rem"
    fontWeight: 600
    lineHeight: 1.4
  code:
    fontFamily: "JetBrains Mono"
    fontSize: "0.8rem"
    fontWeight: 400
    lineHeight: 1.5
rounded:
  sm: "7px"
  md: "14px"
  lg: "28px"
  full: "9999px"
spacing:
  unit: "4px"
  xs: "4px"
  sm: "8px"
  md: "16px"
  lg: "24px"
  xl: "32px"
  2xl: "48px"
  3xl: "64px"
  gutter: "16px"
  control-height: "48px"
  control-padding: "20px"
  gap: "16px"
  section: "112px"
components:
  page:
    backgroundColor: "{colors.background}"
    textColor: "{colors.text}"
    typography: "{typography.body-md}"
  text-muted:
    backgroundColor: "{colors.background}"
    textColor: "{colors.muted}"
    typography: "{typography.body-sm}"
  card:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.text}"
    rounded: "{rounded.lg}"
    padding: "20px"
  card-muted:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.muted}"
    typography: "{typography.body-sm}"
  button-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    typography: "{typography.label}"
    rounded: "{rounded.md}"
    height: "48px"
    padding: "20px"
  button-secondary:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.text}"
    typography: "{typography.label}"
    rounded: "{rounded.md}"
    height: "48px"
    padding: "20px"
  input:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.text}"
    typography: "{typography.body-md}"
    rounded: "{rounded.md}"
    height: "48px"
    padding: "20px"
  divider:
    backgroundColor: "{colors.border}"
    height: "1px"
  badge:
    backgroundColor: "{colors.accent}"
    textColor: "{colors.on-accent}"
    typography: "{typography.caption}"
    rounded: "{rounded.sm}"
    padding: "2px 8px"
  page-dark:
    backgroundColor: "{colors.dark-background}"
    textColor: "{colors.dark-text}"
    typography: "{typography.body-md}"
  text-muted-dark:
    backgroundColor: "{colors.dark-background}"
    textColor: "{colors.dark-muted}"
    typography: "{typography.body-sm}"
  card-dark:
    backgroundColor: "{colors.dark-surface}"
    textColor: "{colors.dark-text}"
    rounded: "{rounded.lg}"
    padding: "20px"
  card-muted-dark:
    backgroundColor: "{colors.dark-surface}"
    textColor: "{colors.dark-muted}"
    typography: "{typography.body-sm}"
  button-primary-dark:
    backgroundColor: "{colors.dark-primary}"
    textColor: "{colors.dark-on-primary}"
    typography: "{typography.label}"
    rounded: "{rounded.md}"
    height: "48px"
    padding: "20px"
  button-secondary-dark:
    backgroundColor: "{colors.dark-surface}"
    textColor: "{colors.dark-text}"
    typography: "{typography.label}"
    rounded: "{rounded.md}"
    height: "48px"
    padding: "20px"
  input-dark:
    backgroundColor: "{colors.dark-surface}"
    textColor: "{colors.dark-text}"
    typography: "{typography.body-md}"
    rounded: "{rounded.md}"
    height: "48px"
    padding: "20px"
  divider-dark:
    backgroundColor: "{colors.dark-border}"
    height: "1px"
  badge-dark:
    backgroundColor: "{colors.dark-accent}"
    textColor: "{colors.dark-on-accent}"
    typography: "{typography.caption}"
    rounded: "{rounded.sm}"
    padding: "2px 8px"
---
<!-- UI by Made Good Designs — https://madegooddesigns.com/inspiration/ui/dropdown-menu-mobile-playful-139aa7d24ce6 Free to use and adapt in any project, including commercial ones; no credit needed in your product. Republishing the screens themselves (a gallery, template pack, article or dataset)? Credit Made Good Designs with a link. Terms: https://madegooddesigns.com/inspiration/ui/terms -->


# DESIGN.md — Fernway

> Design rules for Fernway: a shared task, docs and files workspace for small teams. This file is the source of truth for colour, type, spacing, shape, motion and component behaviour. People and AI coding agents should follow it exactly and should not invent new values. The YAML front matter holds the tokens in the [DESIGN.md format](https://github.com/google-labs-code/design.md) (version alpha); the sections below explain how to use them.

## Overview

- **Product type:** Mobile app
- **Personality:** Friendly, Playful, Energetic
- **Themes:** light and dark (follows the system setting, overridable with `data-theme`; dark tokens are the `dark-*` colours and the `*-dark` components)
- **Accessibility target:** WCAG 2.2 AA

### Rules for AI coding agents

1. Use only the tokens in this file. If something seems to need a new colour, size or shadow, reuse the nearest token and leave a TODO comment instead of inventing one.
2. Reference colours through CSS variables (`var(--color-primary)`) or the matching Tailwind classes — never raw hex in component code.
3. Build every interactive state: default, hover, active, focus-visible, disabled and loading.
4. Keep text contrast at the ratios in the Colors section. Re-check any new colour pairing before using it.
5. Respect `prefers-reduced-motion` and the tokens in the Motion section.
6. When a rule here conflicts with a framework default, this file wins.

### Personality and voice

- **Friendly:** Second person (“you”), contractions are fine, explain rather than command.
- **Playful:** Light wit in empty states and confirmations; never in errors or anything about money.
- **Energetic:** Active verbs and momentum; motion may be a little livelier, but never blocks input.

## Colors

| Token | Role | Light | Dark |
|---|---|---|---|
| `background` (`--color-background`) | Page background | `#FAF8FF` | `#120F19` |
| `surface` (`--color-surface`) | Cards, menus, navigation, inputs | `#FFFFFF` | `#201B28` |
| `border` (`--color-border`) | Dividers and input borders | `#DBD5E7` | `#36313F` |
| `text` (`--color-text`) | Body text and headings | `#191522` | `#EDEBF3` |
| `muted` (`--color-muted`) | Secondary text, captions, placeholders | `#666073` | `#B3AEBF` |
| `primary` (`--color-primary`) | Primary buttons, key links, selected states | `#7B34CB` | `#B98EFF` |
| `on-primary` (`--color-on-primary`) | Text and icons on primary | `#FFFFFF` | `#111111` |
| `accent` (`--color-accent`) | Highlights, tags, focus ring, charts | `#9F5700` | `#FF9420` |
| `on-accent` (`--color-on-accent`) | Text on accent-filled tags | `#FFFFFF` | `#000000` |

### Measured contrast

| Pair (light) | Colours | Ratio | Needs | Result |
|---|---|---|---|---|
| Text on background | #191522 on #FAF8FF | 17.01:1 | 4.5:1 | Pass |
| Text on surface | #191522 on #FFFFFF | 17.92:1 | 4.5:1 | Pass |
| Muted text on background | #666073 on #FAF8FF | 5.72:1 | 4.5:1 | Pass |
| Muted text on surface | #666073 on #FFFFFF | 6.02:1 | 4.5:1 | Pass |
| Primary on background | #7B34CB on #FAF8FF | 6.24:1 | 3:1 | Pass |
| Label on primary button | #FFFFFF on #7B34CB | 6.57:1 | 4.5:1 | Pass |
| Accent on surface | #9F5700 on #FFFFFF | 5.47:1 | 3:1 | Pass |

| Pair (dark) | Colours | Ratio | Needs | Result |
|---|---|---|---|---|
| Text on background | #EDEBF3 on #120F19 | 16.04:1 | 4.5:1 | Pass |
| Text on surface | #EDEBF3 on #201B28 | 14.24:1 | 4.5:1 | Pass |
| Muted text on background | #B3AEBF on #120F19 | 8.78:1 | 4.5:1 | Pass |
| Muted text on surface | #B3AEBF on #201B28 | 7.79:1 | 4.5:1 | Pass |
| Primary on background | #B98EFF on #120F19 | 7.56:1 | 3:1 | Pass |
| Label on primary button | #111111 on #B98EFF | 7.53:1 | 4.5:1 | Pass |
| Accent on surface | #FF9420 on #201B28 | 7.61:1 | 3:1 | Pass |

### Colour rules

- One primary action per view uses `--color-primary` with `--color-on-primary` text.
- `--color-accent` is for small highlights (tags, focus rings, charts). Never use it for body text.
- Errors, warnings and success states use text plus an icon, not colour alone.

## Typography

- **Headings:** Fredoka (600–700)
- **Body:** Nunito (400; 600 for emphasis)
- **Code and data:** JetBrains Mono
- **Base size:** 16px, scale ratio 1.25, body line-height 1.6, headings 1.15–1.25
- Maximum line length: about 70 characters (`max-width: 68ch`).

| Token | Size | rem | Typical use |
|---|---|---|---|
| `--text-xs` | 10.2px | 0.64rem | Fine print, badges (`caption`) |
| `--text-sm` | 12.8px | 0.8rem | Captions, table cells, helper text (`body-sm`, `code`) |
| `--text-base` | 16px | 1rem | Body text, inputs, buttons (`body-md`, `label`) |
| `--text-lg` | 20px | 1.25rem | Lead paragraph, card titles (`body-lg`) |
| `--text-xl` | 25px | 1.563rem | H4 / section titles (`h4`) |
| `--text-2xl` | 31.3px | 1.953rem | H3 (`h3`) |
| `--text-3xl` | 39.1px | 2.441rem | H2 (`h2`) |
| `--text-4xl` | 48.8px | 3.052rem | H1 / hero (`h1`) |

## Layout

Base unit **4px**. Use only these steps: `2`, `4`, `6`, `8`, `12`, `16`, `24`, `32`, `48`, `64` (px).

- **Density:** spacious — controls 48px tall, 20px inner padding, 16px gaps between related items.
- **Section spacing:** 112px between page sections on desktop, about half on mobile.
- **Layout:** 12-column grid, max content width 1200px, 16px side gutter on phones; no horizontal scrolling at 320px.

## Elevation & Depth

Depth uses three soft shadow levels; surfaces sit on the background and borders separate dense content.

| Token | Value | Use |
|---|---|---|
| `--border-width` | 1px | Inputs, dividers, outline buttons |
| `--shadow-sm` | `0 1px 3px rgb(0 0 0 / 0.1)` | Inputs, small cards |
| `--shadow-md` | `0 4px 14px rgb(0 0 0 / 0.12)` | Dropdowns, popovers |
| `--shadow-lg` | `0 18px 44px rgb(0 0 0 / 0.18)` | Dialogs |

## Shapes

| Token | Value | Use |
|---|---|---|
| `--radius-sm` | 7px | Badges, checkboxes, small chips |
| `--radius-md` | 14px | Buttons, inputs |
| `--radius-lg` | 28px | Cards, dialogs, images |
| `--radius-full` | 9999px | Avatars, pills |

## Components

The `components` tokens in the front matter give the base atoms (page, text-muted, card, button-primary, button-secondary, input, divider, badge, each with a `-dark` variant). Behaviour:

### Buttons
- Height 48px, horizontal padding 20px, radius `--radius-md`, label in `--text-base` 600.
- **Primary:** `--color-primary` background, `--color-on-primary` label. **Secondary:** transparent with a `--border-width` `--color-border` outline and `--color-text` label. **Ghost:** text only.
- Hover: darken or lighten the fill by about 8% lightness; active: a further 4%. Disabled: 50% opacity, no pointer events. Loading: keep the width, show a spinner, block repeat clicks.

### Inputs and forms
- Height 48px, `--color-surface` fill, `--border-width` `--color-border` border, radius `--radius-md`.
- Every input has a visible label above it; helper text below in `--text-sm` `--color-muted`.
- Error: message under the field with an icon, border switches to an error colour that passes 3:1, and focus moves to the first invalid field on submit.

### Cards
- `--color-surface`, radius `--radius-lg`, 20px padding, `--shadow-sm`.
- A whole-card link has one clear target and a visible focus ring.

### Navigation
- Top bar on `--color-surface` with a `--color-border` bottom edge; current page marked with weight and an underline or indicator, not colour alone.
- Below 768px, collapse to a menu button with an accessible name; the open menu traps focus and closes on Escape.

### Tables and lists
- Header row in `--text-sm` 600 `--color-muted`; rows separated by `--color-border` lines; numbers right-aligned in JetBrains Mono.
- On phones, tables scroll inside their own container or collapse to stacked cards.

### Tags and badges
- `--text-xs` 600, radius `--radius-sm`, padding 2px 8px. Accent-filled tags use `--color-on-accent` (white) text.

## Motion

Motion confirms an action or shows where something came from. Fade and short slides (4–8 px); no bounces.

| Token | Value |
|---|---|
| `--duration-fast` | 120ms (hover, press) |
| `--duration-base` | 200ms (menus, toasts) |
| `--duration-slow` | 320ms (dialogs, page sections) |
| `--ease` | `cubic-bezier(0.2, 0.8, 0.2, 1)` |

With `prefers-reduced-motion: reduce`, replace movement with an instant change or a fade of 100ms or less.

## Accessibility

- Text contrast at least 4.5:1 (3:1 for 24px+ or 18.7px+ bold); UI parts and focus rings at least 3:1.
- Visible focus on everything interactive: 2px `--color-accent` outline with a 2px offset.
- Touch targets at least 24×24px (44×44px preferred) with 8px between targets.
- Every image has alt text (empty `alt=""` if decorative); icons-only buttons have an accessible name.
- Pages work with keyboard only and at 200% zoom; headings are in order (one H1 per page).

## Tokens as CSS

Check this file with `npx @google/design.md lint DESIGN.md`; export the front-matter tokens with `npx @google/design.md export --format css-tailwind DESIGN.md` (Tailwind v4 `@theme`) or `--format dtcg` (W3C design tokens). The same tokens as plain CSS:

```css
:root {
  --color-background: #faf8ff;
  --color-surface: #ffffff;
  --color-border: #dbd5e7;
  --color-text: #191522;
  --color-muted: #666073;
  --color-primary: #7b34cb;
  --color-on-primary: #ffffff;
  --color-accent: #9f5700;
  --color-on-accent: #ffffff;
  --font-heading: "Fredoka", system-ui, sans-serif;
  --font-body: "Nunito", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;
  --text-xs: 0.64rem;
  --text-sm: 0.8rem;
  --text-base: 1rem;
  --text-lg: 1.25rem;
  --text-xl: 1.563rem;
  --text-2xl: 1.953rem;
  --text-3xl: 2.441rem;
  --text-4xl: 3.052rem;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --space-16: 64px;
  --radius-sm: 7px;
  --radius-md: 14px;
  --radius-lg: 28px;
  --radius-full: 9999px;
  --border-width: 1px;
  --shadow-sm: 0 1px 3px rgb(0 0 0 / 0.1);
  --shadow-md: 0 4px 14px rgb(0 0 0 / 0.12);
  --shadow-lg: 0 18px 44px rgb(0 0 0 / 0.18);
  --duration-fast: 120ms;
  --duration-base: 200ms;
  --duration-slow: 320ms;
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --color-background: #120f19;
    --color-surface: #201b28;
    --color-border: #36313f;
    --color-text: #edebf3;
    --color-muted: #b3aebf;
    --color-primary: #b98eff;
    --color-on-primary: #111111;
    --color-accent: #ff9420;
    --color-on-accent: #000000;
  }
}
:root[data-theme="dark"] {
  --color-background: #120f19;
  --color-surface: #201b28;
  --color-border: #36313f;
  --color-text: #edebf3;
  --color-muted: #b3aebf;
  --color-primary: #b98eff;
  --color-on-primary: #111111;
  --color-accent: #ff9420;
  --color-on-accent: #000000;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}
```

<!-- Generated with the free DESIGN.md generator at madegooddesigns.com/tools/design-md-generator/ -->

## Component: Dropdown menu

An actions menu behind a button: arrow keys move through the items, Escape closes, and a disabled item is skipped.

- **Pattern:** WAI-ARIA Authoring Practices, Menu button (https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/)
- **Roles and attributes:** A button with aria-haspopup="menu", aria-expanded and aria-controls opens a list with role="menu"; items have role="menuitem" and tabindex="-1" (focus is moved by script); a disabled item has aria-disabled="true"; a separator has role="separator".
- **States drawn:** default, hover, focus-visible, open, disabled
- **Focus:** a visible `:focus-visible` outline (3px solid accent), never removed
- **Style knobs (playful):** border 2px, corners 14px, shadow `0 4px 14px rgb(0 0 0 / .10)`, labels sentence case
- **Motion:** transitions are short (≤160ms) and switched off under `prefers-reduced-motion: reduce`
- **Code:** HTML + CSS + a few lines of plain JavaScript (no libraries); colours come only from the tokens above, so light and dark both work

### Keyboard
- **Enter / Space / Down arrow:** open and focus the first item
- **Up arrow:** open and focus the last item
- **Up / Down arrow:** move between items (wraps, skips disabled)
- **Home / End:** first / last item
- **A letter:** jump to the next item starting with it
- **Escape:** close and return focus to the button

### Licence
Original Made Good Designs code: free to use and adapt in any project, including commercial ones, with no credit needed. Fonts are Google Fonts under their own licences.
