| version | alpha | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| name | Clawnify Apps | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description | The shared design system for every app built on the Clawnify app builder (template-app-internal: Hono + React + Vite + tRPC + Tailwind + shadcn/ui). This file is the single source of truth for visuals. Every deployed app inherits it; an app or agency overrides individual tokens below to rebrand without touching component code. Lint with `npx @google/design.md lint DESIGN.md`; export to a Tailwind v4 @theme block with `npx @google/design.md export --format css-tailwind DESIGN.md > theme.css`. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| colors |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typography |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rounded |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| spacing |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| components |
|
Clawnify apps are internal tools and management platforms for mid-market companies: catalogs, quote-to-invoice queues, CRMs, project trackers, client portals, admin panels. The buyer is an operations person or the agency serving them, not a consumer. So the look is dense, quiet, and engineered — the tier of Linear, Attio, and Ramp, not the tier of a vibe-coded demo.
The job of this file is twofold. First, a floor: enough opinion to eliminate the generic "AI-generated interface" aesthetic (purple gradients, glowing buttons, emoji section headers, oversized hero type). Second, a signature: a small set of recognizable moves — codified from the Clawnify pricing cards (apps/web/src/app/pricing/page.tsx), the most detailed surface we've shipped — so that every app, whatever its domain, is identifiably a Clawnify app the way every Linear screen is identifiably Linear.
The format follows the Google Labs DESIGN.md spec, same as the websites' docs/DESIGN.md. Tokens in frontmatter give agents and tooling exact values; the prose explains why.
Five moves, applied everywhere. An app missing these looks generic; an app with all five looks like ours.
A Clawnify container is anatomy, not a padded box. Cards, panels, and detail views are divided into stacked zones by hairline border dividers (card-zone), and every zone opens with an eyebrow — an 11px uppercase tracked label in muted naming what the zone contains:
┌──────────────────────────────────┐
│ INVOICE │ ← eyebrow
│ Q3-0042 · Meridian GmbH │
│ $4,820.00 [⬛ Mark paid] │
├──────────────────────────────────┤ ← hairline divider
│ LINE ITEMS │ ← eyebrow
│ … │
├──────────────────────────────────┤
│ ACTIVITY │
│ … │
└──────────────────────────────────┘
This is the single highest-leverage move. Generic AI UIs ship one <h3> and a wall of content; a sectioned, self-labeled card reads as deliberately engineered. Forms group fields under eyebrows. Sidebars title their nav groups with eyebrows. Detail panes split summary / fields / history into zones.
The primary button is Clawnify coral (primary = #DD5164) — and there is exactly one per screen. It darkens on hover (primary-hover), never lightens. This is the same coral the dashboard uses for its primary CTA, so a generated app and the dashboard read as one product — that single shared hue is what makes the whole platform feel like one SaaS. Coral is the default; an app or agency can override primary/primary-hover to its own brand color (see Overriding This File) and every button reflows.
Everything else in the chrome stays monochrome. The coral is rationed to that one CTA; color elsewhere is reserved for:
- Blue (
ring/link) — focus rings and inline text links. Never buttons, never fills. - Status tones —
success/warning/danger, tinted badges and validation only.
So the rule isn't "no color in the chrome" — it's one colored action, monochrome everything else, and color otherwise belongs to the data (status badges, category pills, charts). Secondary and ghost actions stay neutral; a screen with two coral buttons has none. That discipline — a single brand CTA against an otherwise gray-white, ink-text interface — is what keeps a coral-buttoned app reading as a serious tool rather than a vibe-coded gradient demo.
Numbers are treated as instrumentation, not text:
- Every numeric column, KPI, and price uses
data/data-lgwith tabular figures ("tnum"), right-aligned in tables so digits and totals stack. - Key numbers carry a fine-print meta line beneath (
stat-meta): a delta, a comparison, a strikethrough former value ("$580/mo· billed yearly"). Give the meta line a fixed height so toggling state never shifts layout — the pricing page'sh-4trick. - Numeric tables show a footer aggregate (sum / avg / count).
Enumerable values — plan names, model tiers, file types, tags shown as facts rather than statuses — render as chips: fine type, surface-sunken fill, hairline border, sm radius. Status that demands attention gets a badge instead: full radius, tinted background (success-tint/warning-tint/danger-tint), colored text. Chips are facts; badges are signals. Don't conflate them.
Icons are 12–16px lucide-react line icons, always paired with text, never decorative. Small confirmation checks use strokeWidth={2.5} so they stay legible at 12px. No emoji, no filled icon sets, no icon-only primary actions.
Neutral-dominant; the full palette ships in light and dark (*-dark applies under prefers-color-scheme: dark / .dark). The dark palette is GitHub-dim (#0D1117 canvas) rather than pure black — easier on the eyes for all-day tools.
background(#F8F9FA): the canvas. A hair off white sosurfacecards read raised without shadows.surface(#FFFFFF): cards, tables, panels, popovers. Content lives here.surface-sunken(#F1F5F9): table-header fills, hovered rows, chips, inset wells, the active sidebar item. The "one step back" tone.foreground(#1A202C): all primary text and data values — the ink. Never pure#000.muted(#475569): secondary text. Deliberately darker than the usual slate-500 so it passes WCAG AA (4.5:1) even onsurface-sunken— table headers and eyebrows must stay readable.faint(#94A3B8): placeholders, disabled states, decorative icons. Never for text that must be read.border(#E2E8F0): the workhorse — card outlines, zone dividers, table separators, input borders.primary(#DD5164) /primary-hover(#C53A4E): Clawnify coral — the single brand CTA per screen, shared with the dashboard. Darkens on hover. The default; overridable per app.ring/link(#2563EB): the only chromatic blue, confined to focus indication and inline links — never a button.- Status triplets: each of
success/warning/dangerhas a text tone and a*-tintbackground, both with dark variants. Tints exist so components never hardcode a hex —button-danger-hoverand the badges reference them.
One family — Inter (fallback: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif). Hierarchy comes from size and weight contrast, not color or family changes. The roles that separate a real tool from a generic one:
eyebrow— 11px / 600 / 0.08em tracking, uppercase,muted. The zone-naming device (signature #1).label— 12px / 600 / 0.04em. Column headers and field labels, set inmuted.data/data-lg— tabular figures for every number (signature #3).fine— 11px fine print: meta lines, deltas, chip text, footnotes.heading-1is only 20px. Internal tools keep titles small; the content is the star. A 48px hero is a marketing-site move and instantly reads as "not a real tool."display(28px) exists for the rare empty-product splash and nothing else.
A 1200px max-width container for table/list apps; a full-bleed flex layout with a fixed 260px sidebar for navigation-heavy apps (CRM, multi-section dashboards). Spacing follows a strict 8px scale with a 4px half-step — consistent rhythm is most of what makes an interface feel designed.
Standard chrome:
- Toolbar — sticky top bar, page title (
heading-1) left, actions right,borderunderneath. - Sidebar —
surface,borderon the right edge, nav groups titled witheyebrow, rows assidebar-itemwith the active row insidebar-item-active(sunken fill + ink text — no blue tint). - Cards use
zone-padding(20px) per zone so grouped content breathes; table rows stay tight (8–10px vertical). Cards relax; tables compress.
The interface is nearly flat. Hierarchy comes from border and the background → surface → surface-sunken tonal steps, not shadows. Shadows are reserved for elements that genuinely float:
- Resting cards/tables: no shadow — a
borderonly. - Popovers, dropdowns, menus:
0 4px 12px rgba(0,0,0,0.12). - Modals, toasts:
0 8px 24px rgba(0,0,0,0.16).
No glows, no colored shadows, no layered drop-shadows on static content. If everything is elevated, nothing is.
Soft-but-engineered: 6px on interactive atoms (buttons, inputs, chips), 8px on containers, 12px on modals; avatars, badges, and toggles are full. Don't mix a sharp 2px corner and a pill in the same view.
Transitions are quick and functional: 0.15s ease on background/border/color. No bounce, no spring, no decorative motion. Hover states are barely visible — a one-step tonal shift to surface-sunken, never a scale or color jump.
Built on shadcn/ui primitives, restyled to these tokens. The shadcn defaults are a fine skeleton but ship too rounded and too gray-flat; the tokens above pull them to this tier.
- Buttons —
button-primary(coral, the one CTA per screen),button-secondary(white, bordered — the default for most actions),button-ghost(toolbar/row actions),button-danger(red text,danger-tinthover). Min height 36px (40px in agent mode). Icon + label, never icon-only for a primary action. - Inputs — bordered
surfacefill; focus swaps the border toringplus a 2px low-opacity blue halo. No heavy glow. - Cards —
cardshell + stackedcard-zones, each opened by aneyebrow(signature #1). A one-zone card is fine; it still gets its eyebrow. - Tables —
surface-sunkenheader inlabeltype,borderbetween rows, hover insurface-sunken, numeric columns indataright-aligned, footer aggregate. - Chips vs badges — see signature #4.
- Stats / KPIs —
statvalue + fixed-heightstat-metaline (signature #3). - Empty states — never a bare "No data." One line of explanation plus the primary action: "No invoices yet. Generate your first from a quote." Render the empty state borderless — quiet centered text + the one action floating in generous whitespace, not wrapped in a bordered/
cardbox. An empty bordered box reads as a broken or unloaded component; the border only earns its place once there are rows to contain. Apply the border (and zone anatomy) to the populated list/table, and swap to plain centered space when the count is zero.
Categorical data values (tags, owners, company names) get a stable color by hashing the value to one of ten muted pairs — the same value always maps to the same color across the app. This is the one place chroma is welcome, because it's data, not chrome. Background / text (light mode):
#FEF2F2/#DC2626 · #ECFDF5/#059669 · #EFF6FF/#2563EB · #FFFBEB/#D97706 · #F5F3FF/#7C3AED · #F0FDFA/#0D9488 · #FDF2F8/#DB2777 · #FFF7ED/#EA580C · #FAF5FF/#9333EA · #F0FDF4/#16A34A
In dark mode, render the same text color over a 12%-opacity background of itself (color-mix(in srgb, <text> 12%, transparent)) — don't ship light pastel fills onto dark surfaces.
function pillColor(value: string) {
let hash = 0;
for (let i = 0; i < value.length; i++) hash = ((hash << 5) - hash + value.charCodeAt(i)) | 0;
return PILL_COLORS[Math.abs(hash) % PILL_COLORS.length];
}The signature is not reserved for big apps. The simplest possible request — "make me a todo app" — must still come out looking engineered. The minimum any Clawnify app ships with, however trivial the brief:
┌─ Toolbar ──────────────────────────────────────┐
│ Todos [▣ Add task]│ ← heading-1 + coral CTA, border below
└────────────────────────────────────────────────┘
┌─ Card ─────────────────────────────────────────┐
│ TASKS · 4 OPEN │ ← eyebrow with live count
│ ☐ Send Q3 invoices ⬡ today │ ← 36px rows, chip for metadata
│ ☐ Review supplier quote ⬡ tomorrow │
│ ☑ Book freight pickup │ ← done: muted + strikethrough
├────────────────────────────────────────────────┤
│ COMPLETED THIS WEEK 3 │ ← second zone, tabular count
└────────────────────────────────────────────────┘
Concretely, the non-negotiables for a minimal app:
- A toolbar with the app name in
heading-1and the single primary action as a coralbutton-primary. Never a floating centered<h1>. - Content in a
cardwith eyebrow-labeled zones — even one list gets its eyebrow (TASKS · 4 OPEN). The count in the eyebrow is the cheapest way to make a list feel instrumented. - A real empty state — "No tasks yet. Add your first above." — not a blank card.
- Metadata as chips, dates/counts in
datatype, completed items inmutedwith strikethrough. - The canvas/surface split —
backgroundpage,surfacecard with aborder. Never content floating directly on the canvas. - Both modes — dark palette via
prefers-color-scheme, agent mode viadata-agent. These come free from the tokens and template; don't strip them "because it's simple."
If the brief is trivial, spend the saved effort on these six, not on inventing layout. A todo app with a labeled, counted, chip-annotated zone card reads as a tool; the same data in a centered max-w-md gradient card reads as a demo.
Every Clawnify app runs for two callers: a human in the dashboard and an agent driving a browser. Detect agent mode (?agent / mode=agent) and set data-agent on <html>. In agent mode: bump interactive targets to tap-target-agent (40–44px), make every action a visible <button> with a descriptive aria-label, and hide hover-only affordances (drag handles, ellipsis menus, click-to-edit). Never gate an action behind hover or right-click in agent mode. Use semantic HTML (<table>/<th>/<td>, real <button>s, correct <input type>); never alert()/confirm()/prompt() or localStorage.
This is the platform default that ships inside template-app-internal. An individual app — or an agency white-labeling client work — overrides tokens here (swap the coral primary for the app's own brand color, the font, the radii) and every component reflows through the Tailwind utilities already in the markup. No component file ever contains a raw hex code, font name, or fixed pixel value — including tint backgrounds and active states; if a recipe needs a tone, it gets a token first. That rule is what makes one-file rebranding actually work.
- Do open every card zone, form group, and sidebar section with an
eyebrow. Don't ship a padded blob with one heading. - Do keep the primary button coral (
primary, the brand default) — exactly one per screen, hover darkens. Don't paint buttons blue (blue is links and focus only) or ship two coral buttons in one view. - Do set numeric columns in tabular figures, right-aligned, with footer aggregates. Don't let digits jitter between rows.
- Do give key numbers a fixed-height meta line (delta, comparison). Don't let state toggles shift layout.
- Do use chips for facts and tinted badges for signals. Don't use a red badge as decoration.
- Do convey hierarchy with borders and tonal steps. Don't add shadows to resting cards or use colored/glowing shadows.
- Do keep headings small (20px page title). Don't ship a 48px marketing hero inside an internal tool.
- Don't use gradients anywhere — especially the purple/indigo gradient that flags AI-generated UI.
- Don't use emoji as section headers or icons; use
lucide-reactline icons at 12–16px. - Do write real empty states with a next action. Don't leave a bare "No data."
- Do keep hover states one tonal step. Don't scale, glow, or color-shift on hover.
- Do maintain WCAG AA (4.5:1 body text) —
mutedis tuned to pass even onsurface-sunken. Don't usefaintfor anything that must be read. - Do stay responsive: stack columns on mobile, keep tap targets ≥
tap-target, let tables scroll horizontally. Don't ship a desktop-only grid. - Do change branding by editing tokens in this file. Don't hardcode a hex, font, or pixel value in a component — tints and active states included.
Known lint warnings:
npx @google/design.md lintflagsborder/borderTopcomponent sub-tokens (the spec doesn't model borders yet — we keep them because borders carry the hierarchy here) and every*-darkcolor as unreferenced (the spec doesn't model dark mode). Both are spec gaps, shared with the websites'docs/DESIGN.md. Any other warning — contrast, orphan light-mode tokens, raw hex — is a real defect; fix it.
apps/web/src/app/pricing/page.tsx— the canonical exemplar of the structural signature (zoned cards, eyebrows, engineered numbers, chips). Its CTA predates the coral-primary default; follow the tokens for button color, this file for everything else.docs/DESIGN.md— the websites' platform-default brand (same spec, marketing tier).docs/template-strategy.md— why there is exactly one app template.- Google Labs DESIGN.md spec — upstream format.