DESIGN.md · git:20261027.aa3130f · 2026-10-27 · sha256 6b0de0c85696fe53

DESIGN.md git:20261027.aa3130fA

Immutable. This exact content never changes and is served at /api/v1/blob/6b0de0c85696fe53.

# ClawHub Design System

This document outlines the design rules, patterns, and guidelines for the ClawHub platform to ensure consistency, accessibility, and maintainability across all components.

For OpenClaw and OpenClaw Foundation logos, see the [brand kit](https://github.com/openclaw/carapace/tree/main/brand-kit).

---

## Color System

### Brand Palette (OpenClaw)

ClawHub uses a strict **3-5 color palette** based on the OpenClaw brand:

| Token           | Light Mode | Dark Mode | Usage                                           |
| --------------- | ---------- | --------- | ----------------------------------------------- |
| `--accent`      | `#dc2626`  | `#dc2626` | Primary actions, interactive elements, emphasis |
| `--accent-deep` | `#b91c1c`  | `#ef4444` | Hover states, secondary emphasis                |
| `--ink`         | `#0a0a0a`  | `#fafafa` | Primary text                                    |
| `--ink-soft`    | `#525252`  | `#a1a1a1` | Secondary text, descriptions                    |
| `--surface`     | `#ffffff`  | `#121212` | Card backgrounds, elevated surfaces             |
| `--bg`          | `#fafafa`  | `#0a0a0a` | Page background                                 |

### Rules

1. **Never exceed 5 colors** without explicit design approval
2. **Never use purple/violet prominently** unless explicitly requested
3. **Always override text color** when changing background color to ensure contrast
4. **Use semantic tokens** (`--accent`, `--ink`, `--surface`) instead of raw colors

---

## Typography

### Font Stack

```css
--font-sans: "Geist", system-ui, sans-serif;
--font-mono: "Geist Mono", monospace;
--font-display: "Geist", system-ui, sans-serif;
```

### Scale

| Token       | Size            | Usage                    |
| ----------- | --------------- | ------------------------ |
| `--fs-xs`   | 0.75rem (12px)  | Labels, badges, metadata |
| `--fs-sm`   | 0.875rem (14px) | Body text, descriptions  |
| `--fs-base` | 1rem (16px)     | Default body text        |
| `--fs-md`   | 1.125rem (18px) | Subheadings              |
| `--fs-lg`   | 1.25rem (20px)  | Section titles           |
| `--fs-xl`   | 1.5rem (24px)   | Page headings            |

### Rules

1. **Maximum 2 font families** per page
2. **Line height 1.4-1.6** for body text (use `leading-relaxed`)
3. **Never use decorative fonts** for body text
4. **Minimum font size: 14px** for readability
5. Use `text-balance` or `text-pretty` for titles

---

## Layout

### Method Priority

Use this hierarchy for layout decisions:

1. **Flexbox** - Default for most layouts
2. **CSS Grid** - Only for complex 2D layouts (cards, galleries)
3. **Never use floats** or absolute positioning unless absolutely necessary

### Spacing Scale

```css
--space-1: 0.25rem /* 4px */ --space-2: 0.5rem /* 8px */ --space-3: 0.75rem /* 12px */
  --space-4: 1rem /* 16px */ --space-5: 1.5rem /* 24px */ --space-6: 2rem /* 32px */;
```

### Grid Patterns

#### Auto-fit Grid (Recommended for Cards)

```css
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
```

- Automatically adjusts columns based on container width
- Prevents orphan items on partial rows
- Maintains consistent card widths

#### Fixed Grid (When exact columns needed)

```css
/* 3-column at desktop, 2 at tablet, 1 at mobile */
grid-template-columns: repeat(3, minmax(0, 1fr));

@media (max-width: 860px) {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 520px) {
  grid-template-columns: 1fr;
}
```

### Container Widths

| Size    | Max Width               | Usage                   |
| ------- | ----------------------- | ----------------------- |
| Default | `--page-max` (1200px)   | Standard pages          |
| Narrow  | `--page-narrow` (720px) | Reading content, forms  |
| Wide    | Full width              | Dashboards, data tables |

---

## Components

### Cards

```css
.card {
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
}
```

**Rules:**

- Always use `display: flex; flex-direction: column;` for consistent height
- Add `flex: 1` to content area for equal-height cards in grids
- Include hover state with `border-color` and subtle `box-shadow`

### Buttons

| Variant       | Usage                                 |
| ------------- | ------------------------------------- |
| `primary`     | Main actions (Submit, Save, Download) |
| `secondary`   | Alternative actions                   |
| `ghost`       | Tertiary actions, navigation          |
| `destructive` | Delete, remove, dangerous actions     |

**Rules:**

- Always include visible focus state
- Minimum touch target: 44x44px on mobile
- Include `aria-label` when icon-only

### Form Controls

- Labels above inputs (not inline)
- Error states use `--status-error-fg`
- Focus rings use `--accent` with 0.2 opacity
- Minimum input height: 40px

---

## Responsive Breakpoints

```css
/* Mobile first - base styles for mobile */

@media (min-width: 520px) {
  /* Small tablets, large phones */
}

@media (min-width: 640px) {
  /* Tablets */
}

@media (min-width: 860px) {
  /* Small desktops, landscape tablets */
}

@media (min-width: 1024px) {
  /* Desktops */
}

@media (min-width: 1280px) {
  /* Large desktops */
}
```

### Rules

1. **Mobile-first approach** - Base styles target mobile
2. **Progressive enhancement** - Add complexity as viewport increases
3. **Test intermediate breakpoints** - Avoid jarring layout jumps
4. **Never hide critical content** on mobile

---

## Accessibility

### Color Contrast

- Normal text: Minimum 4.5:1 ratio
- Large text (18px+): Minimum 3:1 ratio
- Interactive elements: Minimum 3:1 ratio

### Focus States

```css
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}
```

### Screen Readers

- Use `sr-only` class for visually hidden but accessible text
- Always include `alt` text for images (empty `alt=""` for decorative)
- Use semantic HTML elements (`main`, `nav`, `article`, `section`)
- Proper heading hierarchy (h1 > h2 > h3, no skipping)

### Motion

```css
/* Respect user preference */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
```

---

## Animation

### Timing

```css
--transition-fast: 150ms;
--transition-base: 200ms;
--transition-slow: 300ms;
```

### Easing

- Use `ease` or `ease-out` for most transitions
- Use `ease-in-out` for enter/exit animations
- Never use `linear` except for continuous animations

### Rules

1. **Subtle by default** - Avoid flashy animations
2. **Purpose-driven** - Animation should provide feedback
3. **Respect preferences** - Support `prefers-reduced-motion`
4. **Performance** - Use `transform` and `opacity` only

---

## Icons

### Usage

- Use Lucide icons consistently
- Standard sizes: 14px, 16px, 20px, 24px
- Include `aria-hidden="true"` for decorative icons
- Never use emojis as icons

### Placement

- Left of labels in buttons and navigation
- Right of labels for external links or dropdowns
- Centered when used alone with `aria-label`

---

## Dark Mode

### Implementation

```css
[data-theme="dark"] {
  /* Dark mode overrides */
}
```

### Rules

1. Never use pure white (`#ffffff`) on dark backgrounds
2. Reduce shadow intensity in dark mode
3. Adjust image brightness if needed
4. Test contrast ratios in both modes

---

## Performance

### CSS

1. Use CSS custom properties for theming
2. Avoid deeply nested selectors (max 3 levels)
3. Use `will-change` sparingly
4. Prefer `transform` over `top/left` for animations

### Images

1. Always specify `width` and `height` attributes
2. Use `loading="lazy"` for below-fold images
3. Use appropriate formats (WebP with fallbacks)
4. Include placeholder or skeleton states

---

## Code Style

### CSS Class Naming

```css
/* Component */
.component-name {
}

/* Component modifier */
.component-name.variant {
}

/* Component child */
.component-name-child {
}

/* State */
.component-name.is-active {
}
.component-name[data-state="open"] {
}
```

### File Organization

```
src/
  components/
    ui/           # Primitive components (Button, Input, Card)
    layout/       # Layout components (Container, Header)
  styles.css      # Global styles and design tokens
  lib/
    theme.ts      # Theme utilities
    preferences.ts # User preference management
```

---

## Checklist

Before shipping any UI changes, verify:

- [ ] Color contrast meets WCAG AA standards
- [ ] Focus states are visible
- [ ] Layout works at all breakpoints
- [ ] Animations respect `prefers-reduced-motion`
- [ ] Text is readable at default browser zoom
- [ ] Interactive elements have 44px minimum touch target
- [ ] Semantic HTML is used appropriately
- [ ] Dark mode has been tested