# PIAF Alignment Studio — Design Language

> Machine-readable brand brief for AI agents and coding tools. Drop this file into a
> project (or reference it) and any agent can build on-brand without installing anything.
>
> **Generated** from the canonical design data (`lib/brand.ts`) on every build, so it never
> drifts. Do not hand-edit. Freshness stamp: `/ds/version.json`. Source of truth (live):
> <https://brand.piaf.studio/ds/>.
>
> This is the *brand language* only — the distilled rules. For the full kit (the real
> `tokens/*.css`, self-hosted fonts, component source, mood photography, and a live-updating
> skill), install the **piaf-design** skill: <https://brand.piaf.studio/resources>.

**PIAF** — Find your lightness through movement.
Spacious Minimal × Warm Tonal. North Point, Hong Kong. EN / Traditional Chinese (HK).

## Non-negotiables

1. Brand name is PIAF — all caps in copy and display; lowercase ‘piaf’ in file, repo, package & skill names, URLs and CSS classes; never mixed. Voice is calm, grounded, second person; never hype, never emoji.
2. Accent is a quiet terracotta — used sparingly. Buttons use dark espresso text on terracotta (AA).
3. Warm tonal only: sand / linen / espresso. No cool tones, no harsh shadows, no bouncy motion.
4. Bilingual EN / Traditional Chinese as equals — serif (Noto Serif HK) for ZH titles, sans (Noto Sans HK) for ZH body.
5. Always reference semantic tokens (--surface, --text-muted, --accent), never raw ramp stops, in product UI.

## Colour

Use **semantic tokens** in product UI — never raw ramp stops. They flip light/dark with a
single `[data-theme]` change.

### Semantic tokens

| Token | Light | Dark | Use |
| --- | --- | --- | --- |
| `--background` | spine-50 | spine-950 | Page canvas |
| `--surface` | spine-100 | spine-900 | Panels, bars |
| `--surface-raised` | spine-0 | spine-800 | Cards, modals |
| `--surface-sunken` | spine-200 | #150D0B | Wells, inset fields |
| `--text` | spine-900 | spine-50 | Body · 14.1:1 ✓ |
| `--text-subtle` | spine-700 | spine-300 | Headings · 7.8:1 ✓ |
| `--text-muted` | spine-600 | spine-400 | Captions · 5.1:1 ✓ |
| `--accent` | clay-500 | clay-400 | Fills |
| `--accent-hover` | clay-400 | clay-300 | Hover (lifts lighter) |
| `--accent-muted` | spine-200 | clay-900 | Tint backgrounds |
| `--accent-text` | clay-700 | clay-300 | Links · 5.0:1 ✓ |
| `--on-accent` | spine-900 | spine-950 | Text on accent · 4.7:1 ✓ |
| `--border` | stone-300 | stone-800 | Hairline dividers |
| `--border-strong` | stone-500 | stone-600 | Form controls |
| `--ring` | clay-600 | clay-400 | Focus ring |

### Ramps

#### Warm Spine — `spine` (Tier 1 · Core)

The backbone neutral. Backgrounds, surfaces AND text all draw from this one family — sand in the light half, espresso/near-black in the dark half.
Hue: warm-yellow → red (~85° → ~30°)

| Stop | Hex | Note |
| --- | --- | --- |
| 0 | `#FAF8F4` | Warm Porcelain — sanctioned near-white |
| 50 | `#F5F2EC` | Harbour Linen — light background |
| 100 | `#EDE9E1` | Warm Stone — surface |
| 200 | `#DDD7CC` | Sand Dune — sunken |
| 300 | `#D9C6B0` | ◆ Warm Sand (anchor) |
| 400 | `#C1A685` | ◆ Camel (anchor) |
| 500 | `#A07E65` |  |
| 600 | `#7D5A4A` |  |
| 700 | `#5F3E34` |  |
| 800 | `#392927` | ◆ Espresso (anchor) |
| 900 | `#341D17` | ◆ Deep warm brown |
| 950 | `#1D1311` | ◆ Near-black (reddest) |

#### Stone — `stone` (Tier 1 · Core)

Cooler greige neutral for borders, dividers and secondary surfaces — keeps the UI from going monotone-brown.
Hue: greige (~90°, low chroma)

| Stop | Hex | Note |
| --- | --- | --- |
| 50 | `#F6F5F1` |  |
| 100 | `#EDEBE5` |  |
| 200 | `#DDDBD3` |  |
| 300 | `#CDCAC1` |  |
| 400 | `#BDBAB0` | ◆ Creamy greige (anchor) |
| 500 | `#9B988F` |  |
| 600 | `#77746C` |  |
| 700 | `#58554E` |  |
| 800 | `#403D37` |  |
| 900 | `#2B2823` |  |
| 950 | `#1A1814` |  |

#### Clay — `clay` (Tier 1 · Accent)

The single accent. Used sparingly. Hover LIFTS one step lighter (a warm glow) rather than darkening, so dark-text contrast holds.
Hue: deeper terracotta (~33°)

| Stop | Hex | Note |
| --- | --- | --- |
| 50 | `#F4EAE5` |  |
| 100 | `#EAD3CA` | gradient-accent (light) |
| 200 | `#DEB6A6` |  |
| 300 | `#D99F8F` | accent / text (dark) |
| 400 | `#D38878` | accent fill (dark) · hover (light) |
| 500 | `#CB7967` | ◆ primary accent (light) |
| 600 | `#B16351` |  |
| 700 | `#894736` | accent-text (light) |
| 800 | `#6C3629` |  |
| 900 | `#522921` | accent-muted (dark) |
| 950 | `#381C17` |  |

### Tier 2 · Functional (status only — never on core chrome)

- **Success** — Muted sage-green (H≈145)
- **Warning** — Warm ochre/amber (H≈78)
- **Error** — Desaturated brick red (H≈25)
- **Info** — Dusty teal (H≈198)

### Tier 3 · Event hues (seasonal accents — never on core chrome)

- **Sage** — Soft olive green (H≈140)
- **Ochre** — Earthy gold (H≈75)
- **Plum** — Muted mauve (H≈345)
- **Lavender** — Smoky lilac / aubergine (H≈318)
- **Teal** — Dusty eucalyptus (H≈195)

## Typography

Canela Deck (display serif) pairs with Montserrat (UI/body); Cormorant Garamond carries
italic pull-quotes; **Moglan is the logo/wordmark only — never set text in it**. Traditional
Chinese is set as an equal: Noto Serif HK for titles, Noto Sans HK for body.

### Families

| Family | Role | Use | Source | Weights |
| --- | --- | --- | --- | --- |
| Canela Deck | Display serif | Hero, titles, display caps | Self-hosted (woff) | Thin → Black + italics |
| Moglan | Logo face | Logo / wordmark ONLY | Self-hosted (otf) | Regular |
| Cormorant Garamond | Italic quote serif | First-person pull-quotes | Google Fonts | Italic 400–600 |
| Montserrat | UI / body sans | Eyebrows, subtitles, body, UI | Google Fonts | 400 → 900 |
| Noto Serif HK | ZH title serif | Traditional-Chinese titles | Google Fonts | 400 → 700 |
| Noto Sans HK | ZH body sans | Traditional-Chinese body & UI | Google Fonts | 400 → 700 |

### Roles & scale (English)

| Class | Role | Font | Weight | Size | Line-height | Tracking |
| --- | --- | --- | --- | --- | --- | --- |
| `.piaf-hero` | Hero | Canela Deck | Regular 400 | 36 → 48px (fluid) | 1.06 | -0.01em |
| `.piaf-display-caps` | Display Caps | Canela Deck | Bold 700 | 36px | 0.98 | 0.02em |
| `.piaf-title` | Title | Canela Deck | Medium 500 | 24px | 1.15 | 0 |
| `.piaf-subhead` | Subhead | Canela Deck | Medium 500 | 20px | 1.15 | 0 |
| `.piaf-quote` | Pull-quote | Cormorant Garamond italic | Medium 500 | 24 → 30px (fluid) | 1.36 | 0 |
| `.piaf-subtitle` | Subtitle | Montserrat | Bold 700 | 12px | 1.15 | 0.13em |
| `.piaf-eyebrow` | Eyebrow | Montserrat | Black 900 | 12px | 1.15 | 0.18em |
| `.piaf-body` | Body | Montserrat | Regular 400 | 16px | 1.70 | 0 |

### Roles & scale (Traditional Chinese)

| Class | Role | Font | Weight | Size | Line-height | Tracking |
| --- | --- | --- | --- | --- | --- | --- |
| `.piaf-title-zh` | Title (ZH) | Noto Serif HK | Regular 400 | — | 1.3 | 0 |
| `.piaf-body-zh` | Body (ZH) | Noto Sans HK | Regular 400 | 16px | 1.85 | 0 |
| `.piaf-quote-zh` | Pull-quote (ZH) | Noto Serif HK italic | Regular 400 | 24 → 30px (fluid) | 1.36 | 0 |

## Spacing, radii, elevation & motion

A 4px base. Sections breathe at 96–128px. Soft, generous corners — never pill-everything.
Warm, low shadows (never harsh/grey). Motion ≤ 440ms, ease-out, no overshoot; honour
`prefers-reduced-motion`.

### Spacing

| Token | Value |
| --- | --- |
| `--space-1` | 4px |
| `--space-2` | 8px |
| `--space-3` | 12px |
| `--space-4` | 16px |
| `--space-5` | 24px |
| `--space-6` | 32px |
| `--space-7` | 48px |
| `--space-8` | 64px |
| `--space-9` | 96px |
| `--space-10` | 128px |

### Radii

| Token | Value | Use |
| --- | --- | --- |
| `--radius-xs` | 4px | chips inner |
| `--radius-sm` | 8px | small |
| `--radius-md` | 14px | default card / input |
| `--radius-lg` | 22px | large cards, sheets |
| `--radius-xl` | 32px | hero panels |
| `--radius-full` | 999px | chips, avatars, icon buttons |

### Elevation

| Token | Value |
| --- | --- |
| `--shadow-xs` | 0 1px 2px rgba(57,41,39,.05) |
| `--shadow-sm` | 0 2px 8px rgba(57,41,39,.06) |
| `--shadow-md` | 0 8px 24px rgba(57,41,39,.08) |
| `--shadow-lg` | 0 18px 48px rgba(57,41,39,.12) |

### Motion — duration

| Token | Value | Use |
| --- | --- | --- |
| `--dur-fast` | 140ms | hovers, taps, micro-feedback |
| `--dur-base` | 240ms | fades, theme flip, surfaces |
| `--dur-slow` | 440ms | drawers, sheets, page-level |

### Motion — easing

| Token | Value | Use |
| --- | --- | --- |
| `--ease-out` | cubic-bezier(0.22, 0.61, 0.36, 1) | entrances · gentle, no overshoot |
| `--ease-inout` | cubic-bezier(0.45, 0, 0.2, 1) | two-way · theme & color transitions |

## Voice & content

- **Tone.** Calm, grounded, sensory. Sells a feeling, not a transformation. Sanctuary, not gym.
- **Person.** Second person, gentle imperative — and a quiet host. Speaks to the reader.
- **Casing.** Display copy is sentence case (Canela); eyebrows, subtitles & buttons are UPPERCASE, wide tracking.
- **Name.** The brand name is PIAF — all caps in copy and display, but lowercase ‘piaf’ in technical identifiers (file, repo, package & skill names, URLs, CSS classes). Never mixed (not ‘Piaf’); the only exception is code identifiers the language forces to capitalise (React component names, the JS namespace).
- **Rhythm.** Short, declarative. Often two beats joined by a period. Pull-quotes are first-person, italic.
- **Bilingual.** EN & Traditional Chinese as equals. ZH serif for titles, sans for body.
- **Numbers.** Quiet and factual — “50 min”, “8 mats”, “2 spots left”, “HK$280”. No vanity stats.
- **Emoji.** Never. No exclamation stacking, no hype, no urgency.

**Do:**

- Feel lighter. Move freely.
- Movement is the language of freedom.
- Small classes. Considered cues.
- I came for the Pilates. I stayed for how it made me feel.

**Don't:**

- UNLOCK YOUR BEST BODY NOW!!
- Crush your goals 💪🔥
- The #1 studio in HK
- Limited spots!!! Book before it's gone!

Disciplines (bilingual, as equals): Reformer Pilates 彼拉提斯 · Yoga 瑜珈 · Barre 芭蕾塑形 · Sound Healing 頌缽音療.

## Components

Six core components, styled entirely via CSS variables (semantic tokens) so they flip with
`[data-theme]`. Icons are Lucide at 1.5px stroke, used sparingly; the brand glyph is the
interlocking P/A monogram (PIAF ships no icon set).

- **Button** — Quiet terracotta fill with deep-espresso text (AA). One primary per view; secondary (outline) and ghost carry the rest. Hover lifts one step lighter.
- **Card** — Calm surface container — soft 22px corners, warm low shadow. Optional media header.
- **Tag** — Uppercase micro-label pill for class metadata (soft / outline / neutral).
- **Input** — Labelled field with optional bilingual label, helper and error states.
- **Switch** — Calm toggle — terracotta when on, stone track when off. Always give it an accessible name.
- **Avatar** — Instructor / member portrait with a Canela monogram fallback.

## Using this

- Reference **semantic tokens** (`--surface`, `--text-muted`, `--accent`), never raw ramp stops.
- Verify both light and dark via `[data-theme]`, and set EN + Traditional Chinese as equals.
- Need the real tokens CSS, fonts, and components? Install the **piaf-design** skill —
  <https://brand.piaf.studio/resources>. The skill self-updates from the live site, so it
  stays in lockstep with this brief.
