# Watchover — Design System

> A trust layer for kids' video. Parents build a whitelist of approved YouTube /
> TikTok / Instagram channels; an AI vets new channels and discovers safe,
> high-quality content so the platform algorithm never decides what a child
> watches. **One phone per family:** the child holds it in a safe feed; the
> parent unlocks a control mode with a PIN.

This repository is the Watchover design language: color, type, spacing, motion
tokens, reusable React components, and high-fidelity UI kits. It exists so design
agents can produce on-brand Watchover interfaces and assets quickly and
consistently.

---

## 1. Product context

**Watchover** is "Airbnb-style trust + Spotify-style curated discovery, for
parenting." It is a **redesign** of an existing prototype that was a deliberate
YouTube look-alike (ink-black + signal-red, Roboto, flat fills, pill buttons).
The job of this system is to **keep the familiarity** that makes video feel
native — video cards, bottom nav, a red/coral play accent, a feed that reads like
YouTube — while **elevating it** into Watchover's own premium-trust brand:
refined, warm, confident, calm. Reference feel: **Airbnb** (trust), **Notion**
(clarity), **Headspace** (calm). It is *not* a literal kids' app, and *not* a
generic SaaS dashboard.

### Who it's for
**Megan, a "Gentle Parent"** — mom of two (ages 5–12), $80k–180k household,
knowledge worker, not anti-tech. Her goal isn't "block the bad," it's "**give
them the good**." She's time-poor and wants to feel in control without constant
policing.

### Two modes, one app
The single most important idea in this system. The same app contains two
experiences that must feel **visibly different**:

| | **Parent mode** | **Child mode** |
|---|---|---|
| Feeling | Calm, premium, high-trust | Playful, bright, simple, safe |
| Type | Editorial, generous spacing | Big, friendly, fewer words |
| Color | Restrained — pine + stone, coral used sparingly | Warmer — marigold + sky alongside coral |
| Radii | Tighter (`--r-md` / `--r-lg`) | Rounder (`--r-2xl`, pills) |
| Density | Information-rich: scores, evidence, decisions | Spacious: big thumbnails, one thing at a time |
| Purpose | Money + control decisions live here | Safe watching lives here |
| Entry | Default; PIN-protected control mode | The resting state of the family phone |

### Design principles
1. **Trust over engagement.** Always show *why* content is safe — AI Check
   scores, evidence, who approved it.
2. **Curated, not algorithmic.** The whitelist is the hero object, not a feed
   the algorithm controls.
3. **No dark patterns, anywhere.** No infinite scroll, no autoplay traps, no
   attention-engineering. That restraint *is* the brand.
4. **Mobile-first** (Flutter, iOS + Android). Single column, thumb-friendly.
5. **Accessible.** WCAG AA contrast, ≥44px tap targets, legible at a glance.

### Sources
This system was authored from a written product brief (no codebase or Figma was
attached). The pre-existing prototype referenced above — the YouTube look-alike —
was described, not provided. If you have access to the current Flutter codebase
or any Figma files, add the links here and reconcile component names.

---

## 2. Content fundamentals (voice & tone)

Watchover speaks like a **calm, competent friend who happens to be an expert** —
the tone of a good pediatrician or a trusted babysitter, never a nanny-state and
never a hype-y consumer app.

- **Warm, plain, confident.** Short sentences. Real words. We explain, we don't
  alarm. "This channel teaches early reading through songs." Not "DANGER: unvetted
  content detected."
- **"You" and "your child."** Address the parent directly. First person plural
  ("we checked," "we recommend") for Watchover's own actions, so the AI feels
  accountable. In child mode, address the child gently and rarely — mostly we just
  show the videos.
- **Evidence, not adjectives.** Prefer specifics over praise. "Reviewed 240
  videos · no ads · creator verified" beats "Amazing safe content!"
- **Sentence case everywhere.** Buttons, titles, nav labels. The only ALL-CAPS is
  the small tracked eyebrow/overline (`.wo-eyebrow`), used sparingly.
- **No exclamation-point inflation.** At most one, in genuinely celebratory child
  moments ("All caught up — nice work."). Parent mode earns trust with a level
  voice.
- **No emoji in parent mode.** Child mode may use a *very* small, curated set as
  category wayfinding (not decoration) — but prefer icons. When in doubt, no emoji.
- **Numbers are reassuring, not gamified.** Scores, counts and "approved by"
  carry weight precisely because we never inflate them. Never invent stats to fill
  space.

**Examples**
- Primary button: `Approve channel` · `Add to whitelist` · `Unlock with PIN`
- AI Check verdict: `Safe to watch` / `Worth a look` / `Needs your review`
- Empty state (parent): `Nothing waiting on you. We'll surface new channels here
  as we find them.`
- Child nudge (rare): `That's everything for now.` (No "watch more!" CTA — the
  restraint is the point.)
- Eyebrow: `AI CHECK` · `THIS WEEK` · `APPROVED BY YOU`

---

## 3. Visual foundations

### Color
A **warm, premium-trust palette** built around three families on a warm neutral
spine. Nothing is pure black, pure white, or neon.

- **Stone** (`--stone-50…900`) — the warm neutral spine. `--paper (#FBF8F3)` is
  the app canvas (a warm cream, *not* white); `--ink (#211D18)` is the warm
  near-black for text. White is reserved for cards floating on cream.
- **Pine** (`--pine-*`, role `--brand`) — the **trust / parent** color. Deep,
  calm, credible green. This is where money and control decisions are signed off.
- **Coral** (`--coral-*`, role `--play`) — the refined descendant of YouTube's
  signal-red. The **play / video / energy** accent. Used on play affordances and
  sparingly as emphasis — never as a large fill in parent mode.
- **Marigold** (`--gold-*`) and **Sky** (`--sky-*`) — child-mode warmth/cool
  accents. Largely absent from parent mode.
- **Scores** are calm, not neon: `--safe-500` (pine-leaning green), `--caution-500`
  (amber), `--flag-500` (brick red), each with a soft tint background.

Always reference **semantic aliases** in components (`--surface-card`,
`--text-body`, `--brand`, `--play`) rather than raw ramp steps.

### Type
One distinctive pairing, deliberately **not** Roboto/Inter:
- **Bricolage Grotesque** (`--font-display`) — display, headlines, the wordmark,
  big numbers. A contemporary grotesque with warmth and a little character; carries
  the "premium editorial" feel. Optical-size + weight variable.
- **Hanken Grotesk** (`--font-text`) — all UI and body. Highly legible, friendly,
  neutral-warm. Tabular lining figures for scores and counts (`.wo-num`).

Scale is mobile-first (see `themes/<active>/typography.css`): display 40 / h1 32 / h2 24 /
h3 20 / body 16 / sm 14 / caption 13 / micro 12. Headlines use tight tracking
(`--track-tight`); the only tracked-out type is the all-caps eyebrow
(`--track-caps`). Never set body text below 13px; tap-target labels stay ≥12px.

### Spacing, radii, layout
- **4px base grid** (`--sp-1`…`--sp-16`). Generous in parent mode, comfortable in
  child mode.
- **Radii ladder:** `--r-sm 8` → `--r-md 12` → `--r-lg 16` → `--r-xl 20` →
  `--r-2xl 28` → `--r-pill`. **Parent mode uses the smaller end (12–16);** child
  mode leans on `2xl` and pills. This radius difference is a primary mode signal.
- **Mobile-first container** `--container: 420px`, single column. Sticky header
  (`--header-h 56`) and bottom nav (`--bottomnav-h 64`). Minimum tap target
  `--tap-min 44`.

### Surfaces, borders, shadows
- **Canvas is warm cream** (`--paper`); **cards are white** with a hairline warm
  border (`--border-soft`) and a **warm-tinted shadow** — shadows are brown alpha
  (`rgba(33,29,24,…)`), *never* pure black. Shadow ladder: `--shadow-xs` →
  `--shadow-sm` → `--shadow-card` (the default for resting cards) → `--shadow-lg`
  (sheets, popovers) → `--shadow-pop` (modals).
- Cards read **calm and floaty**, not boxed: soft shadow + hairline border +
  12–16px radius in parent mode, 28px in child mode. No heavy 1px-black borders,
  no left-accent-border cards.
- Dividers are a warm hairline (`--divider`).

### Imagery
- **Video/channel thumbnails** are the only place imagery is loud. They should
  feel warm and high-quality — natural light, friendly, real kids' content (story
  time, science, music, crafts). Avoid cold/blue stock and avoid manipulative
  thumbnail tropes (shocked faces, arrows, MAXIMUM-CAPS overlays). When real images
  aren't available, use a **warm gradient placeholder** with a category glyph — it
  should look intentional, never gray.
- A **protection treatment**: thumbnails carry a small AI-Check badge and a
  bottom scrim (a subtle dark→transparent gradient) only where text sits over the
  image, for legibility.

### Motion
Calm and physical, never bouncy-for-the-sake-of-it.
- Easing: `--ease-out` for entrances, `--ease-in-out` for moves, `--ease-spring`
  reserved for small playful child-mode moments (a thumb-tap bounce on a big
  thumbnail).
- Durations: `--dur-fast 140` (hover/press), `--dur-base 220` (most), `--dur-slow
  360` (sheets/overlays). Honor `prefers-reduced-motion` (handled in `base.css`).
- **Press:** scale down ~2% + slight darken. **Hover (where pointers exist):**
  raise shadow one step or lighten 4–6%, never a color flip. No infinite
  decorative loops.

### Transparency & blur
Used sparingly: a translucent blurred header/bottom-nav (`backdrop-filter`) over
scrolling content; sheet scrims at ~`rgba(33,29,24,0.4)`. Blur is a system
affordance, not decoration.

---

## 4. Iconography

**Library: [Lucide](https://lucide.dev)** (loaded from CDN). Chosen for its
rounded line terminals, even ~2px stroke and friendly-but-serious tone — it
matches the calm/premium feel and reads clearly at small sizes on a phone.

> ⚠️ **Substitution flag:** No icon set was provided in the brief, so Watchover
> standardizes on Lucide as the closest match to the intended feel. If the real
> Flutter app ships a specific icon set (e.g. a custom set or Material Symbols
> Rounded), replace this and document it here.

**Usage**
- Default stroke icons at **20px** (inline/nav) and **24px** (primary actions);
  stroke inherits `currentColor`. Keep the 2px stroke — don't mix weights.
- **Play** is the one place a *filled* coral triangle appears (the play
  affordance / brand link to video). Everything else is line work.
- **Score/verdict icons** pair with the AI-Check colors: `shield-check` (safe),
  `search` / `eye` (worth a look), `flag` (needs review).
- **`kid`** (child silhouette: smaller head, compact body) marks the parent
  bottom-nav "Profiles" entry (child switcher) — distinct from the adult `user`.
- **No emoji as UI icons** in parent mode. Child-mode category chips may use a
  small curated glyph set, but prefer Lucide.
- Load via CDN:
  `<script src="https://unpkg.com/lucide@latest"></script>` then `lucide.createIcons()`,
  or use inline `<i data-lucide="shield-check"></i>`.

**Logo & marks** (in `assets/logo/`)
- `watchover-mark.svg` — the brand mark: a pine **protection shield** with a
  **coral play triangle** (trust × video). Use on cream/white.
- `watchover-mark-light.svg` — cream mark for dark/photo surfaces.
- The **wordmark** is "Watchover" set in Bricolage Grotesque SemiBold, tight
  tracking, usually mark + wordmark locked up horizontally (see the Brand cards).

---

## 5. Index / manifest

**Root**
- `styles.css` — the single entry point consumers link. Import manifest only:
  active theme → base → the 8 component group CSS files.
- `index.html` — local gallery of every specimen card (foundations + component
  groups) with sticky navigation; open directly in a browser, no server needed.
- `themes/<name>/` — `theme.css` (manifest), `fonts.css`, `colors.css`,
  `typography.css`, `spacing.css`. All custom properties per theme; the token
  contract every theme must satisfy is `themes/THEME-CONTRACT.md`. The active
  theme is the single `@import` in `themes/active.css`.
- `base.css` — theme-agnostic element defaults + reduced-motion; consumes only
  semantic aliases.
- `readme.md` — this guide. `SKILL.md` — Agent-Skills entry point.
- `assets/logo/` — brand marks. `assets/fonts/` — **self-hosted variable woff2**
  (Bricolage Grotesque 200–800, Hanken Grotesk 100–900; latin + latin-ext,
  OFL, downloaded from Google Fonts 2026-06-12). No external font requests.

**Foundation cards** (`cards/`) — specimen tiles rendered in the Design System
tab: color ramps, semantic roles, score colors, type specimens, spacing/radii,
shadows, the logo lockup.

**Components** (`components/`) — reusable React primitives. Each folder has
`<group>.css` (all the group's `wo-*` styles, imported by `styles.css`), and per
component `<Name>.jsx`, `<Name>.d.ts`, `<Name>.prompt.md`, plus one `@dsCard`
HTML per group. The full target set (47 components, 8 groups) was derived from
a component inventory of the clickable prototype
(`artifacts/demo/prototype-r2_v4/`, 25 screens) plus the R4 spec delta — it
covers **100% of prototype screens** so new prototype iterations compose from
the system instead of inventing one-off CSS. **All 47 are implemented
(2026-06-12):**

- `core/` — `Button`, `IconButton`, `Badge`, `Tag`, `Avatar`, `Switch`,
  `Input`, `SearchField`, `PinInput`, `ProgressSteps`
- `forms/` — `OptionCard`, `KidCard`, `ProfileChip`, `AddCard`
- `trust/` — `AICheckScore` (the signature evidence component), `ScoreRing`,
  `EvidenceRow`, `ProcessLog`, `Mascot`
- `media/` — `VideoCard`, `ChannelCard`, `ChannelHero`, `VideoPlayer`,
  `VideoRow`
- `navigation/` — `BottomNav`, `AppHeader`, `ModePill`, `TokenBalance`
  (the single token balance), `Subtabs`
- `commerce/` — `PlanCard`, `TokenPackRow`, `CoinMedallion`, `CreditCost`,
  `GuaranteeBox`, `BeforeAfterGrid`, `FeaturePillar`, `ReviewCard`, `FAQItem`
- `overlays/` — `BottomSheet`, `Toast`, `EmptyState`, `SearchOverlay`
- `layout/` — `SectionHeader`, `SettingsRow`, `SwipeRow`, `RequestRow`,
  `StickyFooter`

> Note: the claude.ai design-environment compiler artifacts (`_ds_bundle.js`,
> `_ds_manifest.json`, `_adherence.oxlintrc.json`) are deliberately not
> generated in this repo — cards are static HTML composed from the `wo-*` CSS
> classes, and the JSX files are reference implementations. See the deviation
> note in `DESIGN-SYSTEM-OVERVIEW.md`.

See `DESIGN-SYSTEM-OVERVIEW.md` for the per-component table: anatomy, variants,
and which prototype screens each component must cover.

**Component rules**
- Every new prototype screen must be composed from these components; if a screen
  needs a pattern that isn't here, **add the component to the system first**,
  then use it — don't fork styles inside the screen.
- All components consume **semantic tokens only** (`--surface-card`, `--brand`,
  `--play`…), never raw ramp steps; parent/child mode differences are expressed
  through variants, not separate components.
- Commerce components (`PlanCard`, `TokenPackRow`, `CreditCost`, `TokenBalance`)
  share one currency concept: a **single token balance** — never two separate
  counters.

**UI kits** (`ui_kits/`)
- `watchover-app/` — the family phone: **parent mode** (whitelist, AI-Check
  review, channel detail) and **child mode** (safe feed, watch screen). Interactive
  click-through with a PIN unlock between modes.

Start from `styles.css` for tokens; compose screens from `components/`; consult
the Brand cards and this readme for voice and visual rules.
