juan-all-hands commited on
Commit
cd40c70
·
verified ·
1 Parent(s): 8bc4971

Add OpenHands design assets from kosmonautical/openhands-index-paul

Browse files

Add design files from kosmonautical/openhands-index-paul:

- OpenHands-Design/ folder with design system files
- New logo assets (logotype-design.svg, logotype-on-dark.svg, logotype-on-light.svg)

This PR also includes the previously synced staging fixes:
- Show all labels toggle for scatter plots
- Logo zoom behavior fixes

OpenHands-Design/DESIGN.md ADDED
@@ -0,0 +1,597 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OpenHands UI Design System
2
+
3
+ ## 1. Visual Theme & Atmosphere
4
+
5
+ OpenHands is a dark-first AI agent platform built on a near-black monochrome canvas. The entire experience lives on a `0 0% 5%` HSL background — effectively `#0d0d0d` — with `0 0% 98%` foreground text that reads as warm off-white. Every surface is a shade of neutral grey scaled in 2–5% lightness increments, creating depth through tonal variation rather than color. The only chromatic moments are semantic: green for success, red-orange for danger, amber for warnings, and blue for informational states.
6
+
7
+ Typography is carried by **Inter** (sans-serif) for all UI text and **JetBrains Mono** for code, terminals, and technical labels. The type system is weight-restrained — `font-medium` (500) is the workhorse, `font-semibold` (600) for headings and emphasis, and `font-normal` (400) for body. Bold (700) is rare and reserved for maximum emphasis.
8
+
9
+ The UI framework is **React + Tailwind CSS + Radix primitives** (shadcn/ui pattern). All colors flow through CSS custom properties declared in `:root` and consumed via `hsl(var(--token))` in the Tailwind config. This means every color in the system is overridable by changing a single HSL triplet.
10
+
11
+ **Key characteristics:**
12
+ - Near-black monochrome canvas (`#0d0d0d` background, `#fafafa` foreground)
13
+ - Neutral grey surface scale in 2–5% lightness increments (5% → 7% → 8% → 12% → 14% → 18%)
14
+ - Inter + JetBrains Mono dual-font system
15
+ - HSL-based CSS custom property architecture for full theme overridability
16
+ - Tailwind utility-first styling with Radix UI headless primitives
17
+ - `transition-colors` as the dominant transition (958 uses) — UI feels responsive but not animated
18
+ - Dark-only primary mode; light and sepia modes exist as secondary via class-map theming
19
+
20
+ ---
21
+
22
+ ## 2. Color Palette & Roles
23
+
24
+ All colors are declared as HSL triplets (without the `hsl()` wrapper) in CSS custom properties. Tailwind maps them as `hsl(var(--token))`.
25
+
26
+ ### Core Surfaces
27
+
28
+ | Token | HSL | Hex | Role |
29
+ |-------|-----|-----|------|
30
+ | `--background` | `0 0% 5%` | `#0d0d0d` | Page background, app shell |
31
+ | `--card` | `0 0% 7%` | `#121212` | Card surfaces, elevated containers |
32
+ | `--secondary` | `0 0% 8%` | `#141414` | Secondary surfaces, sidebar accent |
33
+ | `--popover` | `0 0% 7%` | `#121212` | Dropdown menus, popovers |
34
+ | `--muted` | `0 0% 12%` | `#1f1f1f` | Muted backgrounds, hover fills, badges, **tooltip surfaces** |
35
+ | `--border` / `--input` | `0 0% 14%` | `#242424` | Borders, input borders, dividers |
36
+ | `--muted-hover` | `0 0% 18%` | `#2e2e2e` | Hover state for muted surfaces |
37
+ | `--modal-background` | Inherits `--background` | `#0d0d0d` | Dialogs, sheets, modals (can diverge) |
38
+
39
+ ### Core Text
40
+
41
+ | Token | HSL | Hex | Role |
42
+ |-------|-----|-----|------|
43
+ | `--foreground` | `0 0% 98%` | `#fafafa` | Primary text, headings |
44
+ | `--muted-foreground` | `0 0% 55%` | `#8c8c8c` | Secondary text, labels, placeholders, icons |
45
+ | `--primary` | `0 0% 100%` | `#ffffff` | Maximum emphasis text, primary buttons |
46
+ | `--primary-foreground` | `0 0% 0%` | `#000000` | Text on primary (white) surfaces |
47
+ | `--accent` | `0 0% 100%` | `#ffffff` | Accent elements (matches primary in dark) |
48
+
49
+ ### Sidebar (inherits core but isolated for overridability)
50
+
51
+ | Token | HSL | Role |
52
+ |-------|-----|------|
53
+ | `--sidebar-background` | `0 0% 5%` | Sidebar background |
54
+ | `--sidebar-foreground` | `0 0% 98%` | Sidebar text |
55
+ | `--sidebar-accent` | `0 0% 8%` | Sidebar hover/active background |
56
+ | `--sidebar-border` | `0 0% 14%` | Sidebar dividers |
57
+ | `--sidebar-ring` | `0 0% 50%` | Sidebar focus ring |
58
+
59
+ ### Semantic / Status
60
+
61
+ | Token | HSL | Hex | Role |
62
+ |-------|-----|-----|------|
63
+ | `--success` | `142 71% 45%` | `#22c55e` | Success states, running indicators |
64
+ | `--success-foreground` | `142 71% 76%` | `#86efac` | Success text on dark surfaces |
65
+ | `--warning` | `38 92% 50%` | `#f59e0b` | Warning states, caution badges |
66
+ | `--info` | `217 91% 60%` | `#3b82f6` | Informational states, links |
67
+ | `--destructive` | `0 72% 51%` | `#dc2626` | Error states, danger actions, delete |
68
+ | `--destructive-foreground` | `0 0% 98%` | `#fafafa` | Text on destructive surfaces |
69
+ | `--ring` | `0 0% 80%` | `#cccccc` | Focus rings (1px, keyboard-only via `focus-visible:`) |
70
+
71
+ ### Gradients & Decorative
72
+
73
+ | Token | Value | Role |
74
+ |-------|-------|------|
75
+ | `--gradient-card-hover` | `linear-gradient(180deg, hsl(0 0% 9%) 0%, hsl(0 0% 7%) 100%)` | Subtle card hover gradient |
76
+ | `--shadow-card` | `0 1px 2px 0 hsl(0 0% 0% / 0.3)` | Default card shadow |
77
+
78
+ ### Hover Backgrounds
79
+
80
+ | Surface | Hover Token | Use |
81
+ |---------|-------------|-----|
82
+ | Dark surfaces (cards, nav items, menus, rows) | `hover:bg-muted/60` | **Standard hover** — the single canonical dark-surface hover |
83
+ | White/primary buttons | `hover:bg-primary/85` | Light grey hover on white buttons (85% opacity white) |
84
+
85
+ **Canonical dark-surface hover: `hover:bg-muted/60`** — used consistently across the codebase. Do **not** mix `/40`, `/50`, `/70` variants.
86
+ **Canonical primary-button hover: `hover:bg-primary/85`** — never use `hover:bg-muted/60` on a `bg-primary`/`bg-white` button (causes dark flash).
87
+
88
+ ---
89
+
90
+ ## 3. Typography Rules
91
+
92
+ ### Font Families
93
+
94
+ | Role | Family | CSS Variable | Tailwind Class | Fallbacks |
95
+ |------|--------|-------------|----------------|-----------|
96
+ | UI / Body | Inter | `--font-sans` | `font-sans` | `system-ui, sans-serif` |
97
+ | Code / Technical | JetBrains Mono | `--font-mono` | `font-mono` | `monospace` |
98
+
99
+ Fonts are loaded via Google Fonts `@import` in `index.css`.
100
+
101
+ ### Type Scale
102
+
103
+ The app uses Tailwind's default type scale. These are the **canonical sizes** ordered by frequency of use:
104
+
105
+ | Tailwind Class | Size | Uses | Role |
106
+ |----------------|------|------|------|
107
+ | `text-sm` | 14px / 0.875rem | 711 | **Primary body text**, labels, button text, descriptions |
108
+ | `text-xs` | 12px / 0.75rem | 427 | **Secondary text**, metadata, badges, menu items, captions |
109
+ | `text-base` | 16px / 1rem | 52 | Larger body text, input text, chat messages |
110
+ | `text-lg` | 18px / 1.125rem | 67 | Section sub-headings, dialog titles |
111
+ | `text-xl` | 20px / 1.25rem | 28 | Page sub-headings |
112
+ | `text-2xl` | 24px / 1.5rem | 31 | Page headings, modal titles |
113
+ | `text-3xl` | 30px / 1.875rem | 12 | Hero headings, landing sections |
114
+
115
+ ### Arbitrary Font Sizes (to normalize)
116
+
117
+ These arbitrary sizes appear frequently and should be migrated to the standard scale or formalized as tokens:
118
+
119
+ | Arbitrary | Count | Recommended Replacement |
120
+ |-----------|-------|------------------------|
121
+ | `text-[11px]` | 46 | `text-xs` (12px) — or formalize as `--text-2xs` if 11px is intentional |
122
+ | `text-[10px]` | 20 | `text-xs` (12px) — or formalize as `--text-2xs` |
123
+ | `text-[12px]` | 8 | `text-xs` (already 12px — use the utility) |
124
+ | `text-[40px]` | 5 | `text-4xl` (36px) or formalize as hero display size |
125
+ | `text-[28px]` | 3 | `text-3xl` (30px) or formalize |
126
+ | `text-[32px]` | 1 | `text-3xl` (30px) or `text-4xl` (36px) |
127
+ | `text-[8px]` | 1 | Likely a micro label — evaluate if needed |
128
+
129
+ ### Font Weight Scale
130
+
131
+ | Tailwind Class | Weight | Uses | Role |
132
+ |----------------|--------|------|------|
133
+ | `font-medium` | 500 | 304 | Labels, nav items, badges (note: buttons use `font-normal`) |
134
+ | `font-semibold` | 600 | 229 | **Headings**, section titles, strong emphasis |
135
+ | `font-normal` | 400 | 106 | **Body text**, descriptions, long-form content |
136
+ | `font-bold` | 700 | 29 | Maximum emphasis (use sparingly) |
137
+ | `font-light` | 300 | 13 | De-emphasized text (use sparingly) |
138
+
139
+ ### Line Height
140
+
141
+ | Tailwind Class | Uses | Role |
142
+ |----------------|------|------|
143
+ | `leading-4` | 38 | Tight — compact UI, badges |
144
+ | `leading-6` | 34 | Standard — body text |
145
+ | `leading-relaxed` | 33 | Comfortable — long-form, descriptions |
146
+ | `leading-5` | 28 | Medium — labels, short text |
147
+ | `leading-tight` | 27 | Condensed — headings |
148
+ | `leading-snug` | 17 | Slightly condensed |
149
+ | `leading-none` | 16 | No leading — single-line elements |
150
+
151
+ ### Letter Spacing
152
+
153
+ | Tailwind Class | Uses | Role |
154
+ |----------------|------|------|
155
+ | `tracking-wide` | 28 | Uppercase labels, section headers |
156
+ | `tracking-wider` | 20 | Small-caps metadata |
157
+ | `tracking-tight` | 19 | Display headings |
158
+
159
+ ### Canonical Patterns
160
+
161
+ **Body text:** `text-sm font-normal text-foreground`
162
+ **Label:** `text-sm font-medium text-foreground`
163
+ **Secondary text:** `text-sm text-muted-foreground`
164
+ **Metadata/caption:** `text-xs text-muted-foreground`
165
+ **Uppercase category:** `text-[11px] font-medium uppercase tracking-wide text-muted-foreground`
166
+ **Heading (page):** `text-2xl font-semibold text-foreground`
167
+ **Heading (section):** `text-lg font-semibold text-foreground`
168
+ **Code/mono:** `text-sm font-mono`
169
+
170
+ ---
171
+
172
+ ## 4. Component Stylings
173
+
174
+ ### Buttons (`Button` component — `src/components/ui/button.tsx`)
175
+
176
+ **Base classes (all variants):**
177
+ `inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-normal ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.97] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0`
178
+
179
+ | Variant | Background | Text | Border | Hover | Use |
180
+ |---------|-----------|------|--------|-------|-----|
181
+ | `default` | `bg-primary` | `text-primary-foreground` | — | `hover:bg-primary/85` | Primary CTA (white button, black text) |
182
+ | `destructive` | `bg-destructive` | `text-destructive-foreground` | — | `hover:bg-destructive/85` | Delete, danger actions |
183
+ | `outline` | `bg-background` | — | `border border-input` | `hover:bg-muted hover:text-foreground` | Secondary actions (most used — 53 instances) |
184
+ | `light` | `bg-primary` | `text-primary-foreground` | `border border-input` | `hover:bg-primary/85` | High-contrast primary on dark bg (token-based, no raw `bg-white`) |
185
+ | `secondary` | `bg-secondary` | `text-secondary-foreground` | — | `hover:bg-muted-hover` | Tertiary actions |
186
+ | `muted` | `bg-muted` | `text-muted-foreground` | — | `hover:bg-muted-hover hover:text-foreground` | Subdued actions |
187
+ | `ghost` | transparent | — | — | `hover:bg-muted hover:text-foreground` | Minimal chrome actions |
188
+ | `link` | transparent | `text-primary underline-offset-4` | — | `hover:underline` | Inline links |
189
+
190
+ **Primary button convention:** All white/primary buttons use `bg-primary text-primary-foreground hover:bg-primary/85`. Never use `bg-white text-black hover:bg-muted/60` inline — the dark hover on a white button is incorrect. Use the `Button` component or match its tokens.
191
+
192
+ | Size | Height | Padding | Font |
193
+ |------|--------|---------|------|
194
+ | `default` | `h-10` | `px-4 py-2` | `text-sm` |
195
+ | `sm` | `h-10` | `px-3` | `text-sm` |
196
+ | `xs` | `h-10` | `px-3` | `text-xs` |
197
+ | `lg` | `h-11` | `px-8` | `text-sm` |
198
+ | `icon` | `h-10 w-10` | — | — |
199
+
200
+ ### Cards & Containers
201
+
202
+ There is no dedicated `Card` primitive — cards are composed with utilities.
203
+
204
+ **Standard card recipe:**
205
+ ```
206
+ bg-card border border-border rounded-lg p-4
207
+ ```
208
+
209
+ **Elevated card:**
210
+ ```
211
+ bg-card border border-border rounded-xl p-6 shadow-lg
212
+ ```
213
+
214
+ **Interactive card:**
215
+ ```
216
+ bg-card border border-border rounded-lg p-4 transition-colors hover:border-white/30
217
+ ```
218
+
219
+ **Glass / backdrop card:**
220
+ ```
221
+ bg-card/70 border border-border/60 rounded-lg p-6 shadow-lg backdrop-blur-xl supports-[backdrop-filter]:bg-card/50
222
+ ```
223
+
224
+ ### Inputs (`Input` component — `src/components/ui/input.tsx`)
225
+
226
+ **Standard input:**
227
+ ```
228
+ h-10 w-full rounded-md border border-border bg-muted/40 px-3 py-2 text-base md:text-sm
229
+ ring-offset-background focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring
230
+ focus-visible:ring-offset-2 focus-visible:bg-muted/60 hover:bg-muted/60
231
+ placeholder:text-muted-foreground
232
+ disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-muted/30
233
+ ```
234
+
235
+ **Canonical focus style (all inputs, textareas, selects must match):**
236
+ ```
237
+ ring-offset-background focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:bg-muted/60
238
+ ```
239
+
240
+ Key rules:
241
+ - Always use `focus-visible:` (keyboard-only), never `focus:` (fires on click too)
242
+ - Always include `ring-offset-background` and `focus-visible:ring-offset-2`
243
+ - Always include `focus-visible:bg-muted/60` for the subtle fill on focus
244
+ - Search inputs (`type="search"`) have `appearance: none` in global CSS to strip browser default focus chrome
245
+
246
+ **Size variants (via SearchInput wrapper):**
247
+ - `sm`: `h-9` + `pl-8 pr-8` (icon padding)
248
+ - `default`: `h-10` + `pl-9 pr-9`
249
+ - `lg`: `h-11` + `pl-10 pr-10`
250
+
251
+ ### Dropdown Menus (`DropdownMenu` — Radix-based)
252
+
253
+ **Menu content:**
254
+ ```
255
+ z-[100] min-w-[8rem] overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md
256
+ ```
257
+
258
+ **Menu item:**
259
+ ```
260
+ group relative flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm
261
+ transition-colors focus:bg-muted/60 data-[highlighted]:bg-muted/60
262
+ ```
263
+
264
+ **Icon treatment in menu items:**
265
+ - Default: `[&_svg]:text-muted-foreground` (grey)
266
+ - Hover/highlight: `group-hover:[&_svg]:!text-foreground` (white)
267
+
268
+ ### Popover
269
+
270
+ **Content:**
271
+ ```
272
+ z-50 max-h-[min(24rem,calc(100dvh-2rem))] shadow-md rounded-[12px] border border-border
273
+ bg-sidebar p-6 text-sidebar-foreground overflow-y-auto
274
+ ```
275
+
276
+ ### Navigation (LeftNav sidebar)
277
+
278
+ - Collapsed: 56px wide icon rail
279
+ - Expanded: 240px+ with text labels
280
+ - Items: `flex items-center gap-2 rounded-md px-3 py-1.5 text-xs transition-colors`
281
+ - Icons: `w-4 h-4 text-muted-foreground group-hover:text-white`
282
+ - Active: `bg-muted/60 text-foreground`
283
+ - Hover: `hover:bg-muted/60 hover:text-white`
284
+
285
+ ### Scrollbar Variants
286
+
287
+ | Class | Width | Behavior | Use |
288
+ |-------|-------|----------|-----|
289
+ | `.dropdown-scroll` | 6px thin | Always visible | Menus, popovers |
290
+ | `.custom-scrollbar` | 8px thin | Always visible | Chat, main content |
291
+ | `.scrollbar-on-hover` | 8px thin | Visible on hover only | Chat threads |
292
+ | `.hide-scrollbar` | hidden | Hidden | Horizontal scroll areas |
293
+
294
+ All scrollbar thumbs: `hsl(var(--muted-foreground) / 0.5)` with hover at `0.7`.
295
+
296
+ ### Tooltips
297
+
298
+ All tooltips use `bg-muted` for a lighter surface that visually separates from the dark page background.
299
+
300
+ **Standard tooltip (rounded-md):**
301
+ ```
302
+ whitespace-nowrap rounded-md bg-muted px-2 py-1 text-xs text-foreground shadow-md
303
+ ```
304
+
305
+ **Pill tooltip (rounded-full):**
306
+ ```
307
+ bg-muted text-foreground text-xs rounded-full shadow-lg px-3 py-1
308
+ ```
309
+
310
+ ### Dialog Close Button
311
+
312
+ The dialog close "×" button has no focus ring (focus ring removed to avoid visual noise on click):
313
+ ```
314
+ absolute right-4 top-4 inline-flex h-7 w-7 items-center justify-center rounded-md opacity-70
315
+ ring-offset-background transition-colors hover:opacity-100 hover:bg-muted/60 focus:outline-none
316
+ ```
317
+
318
+ ---
319
+
320
+ ## 5. Layout Principles
321
+
322
+ ### Spacing System
323
+
324
+ The app uses Tailwind's default 4px-based spacing scale. These are the most common values by usage:
325
+
326
+ **Gaps (flex/grid):**
327
+
328
+ | Class | Px | Uses | Context |
329
+ |-------|-----|------|---------|
330
+ | `gap-2` | 8px | 414 | **Standard gap** — between items in rows, icon + label |
331
+ | `gap-3` | 12px | 144 | Comfortable gap — form groups, card content |
332
+ | `gap-4` | 16px | 110 | Generous gap — section spacing, grid layouts |
333
+ | `gap-1` | 4px | 86 | Tight gap — inline badges, compact lists |
334
+ | `gap-1.5` | 6px | 59 | Between tight and standard |
335
+ | `gap-6` | 24px | 50 | Large gap — major sections |
336
+
337
+ **Padding:**
338
+
339
+ | Class | Px | Uses | Context |
340
+ |-------|-----|------|---------|
341
+ | `px-4` | 16px | 216 | **Standard horizontal padding** — buttons, cards |
342
+ | `px-3` | 12px | 212 | Compact horizontal padding — menu items, inputs |
343
+ | `py-2` | 8px | 200 | **Standard vertical padding** — buttons, rows |
344
+ | `px-2` | 8px | 198 | Tight horizontal padding — badges, pills |
345
+ | `py-1` | 4px | 138 | Compact vertical padding |
346
+ | `py-1.5` | 6px | 76 | Slightly more than compact |
347
+ | `p-4` | 16px | 89 | Uniform card/container padding |
348
+ | `p-6` | 24px | 26 | Generous container/dialog padding |
349
+
350
+ ### Grid & Container
351
+
352
+ - Max container width: `1400px` (via Tailwind `container` config with `2rem` padding)
353
+ - Primary layout: sidebar (56–240px) + main content area
354
+ - Settings layout: custom CSS vars for independent nav/main vertical inset
355
+ - `--settings-nav-padding-top/bottom`: `2rem`
356
+ - `--settings-main-padding-top/bottom`: `2rem`
357
+
358
+ ### Whitespace Philosophy
359
+
360
+ - **Dense but breathable**: The app uses `text-sm` (14px) as the default with `gap-2` (8px) standard spacing — dense enough for a productivity tool, but never cramped.
361
+ - **Consistent rhythm**: Sections are separated by `border-t border-border` dividers with `my-3` (12px) vertical margin. No heavy horizontal rules.
362
+ - **Surface differentiation over spacing**: Rather than using large whitespace to separate areas, the app uses background color shifts (`bg-background` → `bg-card` → `bg-muted`) to create visual sections.
363
+
364
+ ### Border Radius Scale
365
+
366
+ Defined via CSS custom properties and Tailwind mapping:
367
+
368
+ | Token | Value | Tailwind | Uses | Role |
369
+ |-------|-------|----------|------|------|
370
+ | `--radius` | `0.375rem` (6px) | `rounded-lg` | 112 | **Standard container radius** — cards, panels |
371
+ | `calc(--radius - 2px)` | `0.25rem` (4px) | `rounded-md` | 501 | **Default element radius** — buttons, inputs, menu items |
372
+ | `calc(--radius - 4px)` | `0.125rem` (2px) | `rounded-sm` | 12 | Subtle radius — small inline elements |
373
+ | `--radius-modal` | `0.75rem` (12px) | `rounded-modal` | — | Modal/dialog/popover radius |
374
+ | — | — | `rounded-xl` | 90 | Larger cards, featured containers |
375
+ | — | — | `rounded-2xl` | 23 | Hero elements, large cards |
376
+ | — | — | `rounded-full` | 185 | Avatars, pills, circular buttons, badges |
377
+
378
+ **Arbitrary radii to normalize:**
379
+
380
+ | Arbitrary | Count | Recommended |
381
+ |-----------|-------|-------------|
382
+ | `rounded-[6px]` | 20 | `rounded-lg` (already 6px via `--radius`) |
383
+ | `rounded-[100px]` | 15 | `rounded-full` (same visual effect) |
384
+ | `rounded-[12px]` | 8 | `rounded-modal` or `rounded-xl` (12px) |
385
+ | `rounded-[4px]` | 4 | `rounded-md` (already 4px) |
386
+
387
+ ---
388
+
389
+ ## 6. Depth & Elevation
390
+
391
+ ### Shadow Scale
392
+
393
+ | Tailwind | Uses | Role |
394
+ |----------|------|------|
395
+ | `shadow-sm` | 21 | Subtle elevation — small cards, badges |
396
+ | `shadow` | 22 | Default — standalone cards |
397
+ | `shadow-md` | 31 | Medium — dropdown menus, popovers |
398
+ | `shadow-lg` | 49 | **Most used** — modals, dialogs, elevated panels |
399
+ | `shadow-xl` | 14 | High emphasis — floating panels |
400
+ | `shadow-2xl` | 5 | Maximum — overlay dialogs |
401
+ | `shadow-inner` | 8 | Inset — pressed buttons, input focus |
402
+ | `shadow-none` | 19 | Reset — flat elements |
403
+
404
+ ### Custom Shadows
405
+
406
+ | Token | Value | Role |
407
+ |-------|-------|------|
408
+ | `--shadow-card` | `0 1px 2px 0 hsl(0 0% 0% / 0.3)` | Card resting shadow |
409
+
410
+ ### Elevation Levels
411
+
412
+ | Level | Treatment | Use |
413
+ |-------|-----------|-----|
414
+ | 0 — Flat | No shadow, `bg-background` | Page background |
415
+ | 1 — Surface | `bg-card` + `border border-border` | Cards, content panels |
416
+ | 2 — Raised | `shadow-md` + `border` | Dropdown menus, popovers |
417
+ | 3 — Floating | `shadow-lg` + `border` | Modals, dialogs, sheets |
418
+ | 4 — Overlay | `shadow-xl` or `shadow-2xl` | Full-screen overlays, drawers |
419
+
420
+ ### Border System
421
+
422
+ - **Standard border:** `border border-border` (1px solid `hsl(0 0% 14%)`)
423
+ - **Subtle border:** `border border-border/60` (reduced opacity)
424
+ - **Interactive hover:** `hover:border-white/30` or `hover:border-muted-foreground/30`
425
+ - **Section divider:** `border-t border-border` (horizontal rule) or `border-t border-sidebar-border` (in sidebar)
426
+ - **Focus ring:** `ring-1 ring-ring ring-offset-2 ring-offset-background` (1px, `focus-visible:` only)
427
+
428
+ ---
429
+
430
+ ## 7. Do's and Don'ts
431
+
432
+ ### Colors
433
+
434
+ | Do | Don't |
435
+ |----|-------|
436
+ | Use `text-foreground` for primary text | Use `text-white` for primary text (278 instances to migrate) |
437
+ | Use `text-muted-foreground` for secondary text | Use `text-stone-400` or `text-gray-400` (raw palette) |
438
+ | Use `bg-background` for page surfaces | Use `bg-black` or hardcoded `bg-[#0d0d0d]` |
439
+ | Use `bg-card` for elevated surfaces | Use `bg-stone-800` or `bg-neutral-900` |
440
+ | Use `bg-muted` for subtle backgrounds | Use `bg-stone-700` or `bg-gray-800` |
441
+ | Use `border-border` for all borders | Use `border-stone-700` or `border-gray-700` |
442
+ | Use `text-success-foreground` for success text | Use `text-emerald-400` or `text-green-400` |
443
+ | Use `text-destructive` for error text | Use `text-red-500` or `text-rose-500` |
444
+ | Use `hover:text-foreground` for hover text brightening | Use `hover:text-white` except in sidebar context |
445
+
446
+ **Semantic status colors:** Use `text-success` / `bg-success`, `text-warning` / `bg-warning`, `text-info` / `bg-info`, `text-destructive` / `bg-destructive` — never raw chromatic palette classes like `text-green-500`, `bg-amber-400`, `text-blue-500`, etc.
447
+
448
+ **Current debt:** `themeAppClassMap.ts` and `NewUserExperienceFlowchart.tsx` still use raw `stone-*` / `rgb()` values (theme definition maps — intentionally deferred; requires per-theme CSS variable architecture). `ChatThread.tsx` `messageTypeColors` has 4 remaining raw palette colors (`orange-500`, `indigo-500`, `purple-500`, `pink-500`) for categorical distinctness — no semantic tokens defined for these yet.
449
+
450
+ ### Typography
451
+
452
+ | Do | Don't |
453
+ |----|-------|
454
+ | Use `text-sm` (14px) as default body size | Use `text-[14px]` or arbitrary pixel values |
455
+ | Use `text-xs` (12px) for small/meta text | Use arbitrary pixel sizes for general text |
456
+ | Use Tailwind scale (`text-lg`, `text-xl`, `text-2xl`) | Use arbitrary sizes like `text-[28px]`, `text-[40px]` |
457
+ | Use `font-medium` as default weight | Use `font-bold` for general emphasis |
458
+ | Keep heading hierarchy: `2xl` → `xl` → `lg` → `base` | Skip levels or invert the scale |
459
+
460
+ ### Border Radius
461
+
462
+ | Do | Don't |
463
+ |----|-------|
464
+ | Use `rounded-md` (4px) for buttons, inputs, menu items | Use `rounded-[4px]` (same value, less maintainable) |
465
+ | Use `rounded-lg` (6px) for cards, containers | Use `rounded-[6px]` (use the token) |
466
+ | Use `rounded-xl` or `rounded-modal` for dialogs | Use `rounded-[12px]` (use the token) |
467
+ | Use `rounded-full` for pills and avatars | Use `rounded-[100px]` (use `rounded-full`) |
468
+
469
+ ### Spacing
470
+
471
+ | Do | Don't |
472
+ |----|-------|
473
+ | Use `gap-2` (8px) as standard item gap | Use arbitrary gap values |
474
+ | Use `px-3`/`px-4` for horizontal padding | Mix `px-2.5` and `px-3.5` without reason |
475
+ | Use `p-4` for card padding, `p-6` for dialogs | Use `p-[24px]` (same as `p-6`) |
476
+ | Use `my-3` for section divider spacing | Use inconsistent vertical margins around dividers |
477
+
478
+ ### Hover & Interaction
479
+
480
+ | Do | Don't |
481
+ |----|-------|
482
+ | Use `hover:bg-muted/60` as standard hover bg on dark surfaces | Mix `/40`, `/50`, `/60`, `/70` without hierarchy |
483
+ | Use `hover:bg-primary/85` for white/primary buttons | Use `hover:bg-muted/60` on white buttons (creates dark hover) |
484
+ | Use `transition-colors` for color-only changes | Use `transition-all` when only color changes |
485
+ | Use `duration-200` as standard transition speed | Mix `duration-150`, `duration-200`, `duration-300` randomly |
486
+ | Use `group` + `group-hover:` for parent-child hover | Apply hover to each child independently |
487
+ | Use `active:scale-[0.97]` for button press feedback | Use `active:scale-95` (inconsistent with Button component) |
488
+
489
+ ### Icons
490
+
491
+ | Do | Don't |
492
+ |----|-------|
493
+ | Use `w-4 h-4` as standard icon size in menus/buttons | Use `w-3 h-3` or `w-5 h-5` without size hierarchy reason |
494
+ | Set icon color to `text-muted-foreground` by default | Leave icons inheriting parent text color (appears too bright) |
495
+ | Brighten on hover: `group-hover:text-foreground` or `group-hover:text-white` | Omit icon hover transitions |
496
+ | Use `shrink-0` on icons in flex layouts | Let icons squish when text wraps |
497
+
498
+ ---
499
+
500
+ ## 8. Responsive Behavior
501
+
502
+ ### Breakpoints (Tailwind defaults)
503
+
504
+ | Prefix | Min Width | Key Changes |
505
+ |--------|-----------|-------------|
506
+ | (none) | 0px | Mobile-first base styles |
507
+ | `sm` | 640px | Wider cards, more padding |
508
+ | `md` | 768px | Multi-column layouts begin, `md:text-sm` on inputs |
509
+ | `lg` | 1024px | Full sidebar visible, expanded grid |
510
+ | `xl` | 1280px | Maximum content width, full feature layout |
511
+ | `2xl` | 1400px | Container max-width ceiling |
512
+
513
+ ### Touch Targets
514
+ - Minimum interactive height: `h-10` (40px) for buttons and inputs
515
+ - Small variant: `h-9` (36px) for compact contexts
516
+ - Icon buttons: `h-10 w-10` (40×40px)
517
+ - Menu items: `py-1.5` (6px) vertical padding at `text-sm` yields ~32px touch target
518
+
519
+ ### Collapsing Strategy
520
+ - Sidebar: collapses from expanded (labels) to icon-only rail on narrow viewports
521
+ - Navigation menus: horizontal → hamburger on mobile
522
+ - Grid layouts: multi-column → single-column stacked
523
+ - Container padding: reduces from `p-6` → `p-4` → `p-3` at smaller breakpoints
524
+
525
+ ---
526
+
527
+ ## 9. Interaction & Motion
528
+
529
+ ### Transitions
530
+
531
+ | Pattern | Uses | When |
532
+ |---------|------|------|
533
+ | `transition-colors` | 958 | **Default** — use for any color/bg/border change |
534
+ | `transition-opacity` | 96 | Fade in/out |
535
+ | `transition-all` | 96 | Multiple properties changing simultaneously |
536
+ | `transition-transform` | 59 | Scale/translate animations |
537
+
538
+ ### Duration
539
+
540
+ | Duration | Uses | When |
541
+ |----------|------|------|
542
+ | `duration-200` | ~48 | **Standard** — local, small feedback: toggles, chevron rotation, sidebar width, card/row hovers, opacity on hover, dialogs |
543
+ | `duration-300` | ~34 | **Layout motion** — panel/drawer resize, sheet exit, canvas split, login/marketing card hover, grid row animations |
544
+
545
+ ### Easing
546
+
547
+ | Easing | Uses | When |
548
+ |--------|------|------|
549
+ | `ease-in-out` | 111 | **Default** — smooth symmetrical transitions |
550
+ | `ease-out` | 52 | Enter animations — elements arriving |
551
+
552
+ ### Framer Motion Patterns (23 files)
553
+ - `AnimatePresence` for mount/unmount transitions
554
+ - Standard enter: `initial={{ opacity: 0 }}` → `animate={{ opacity: 1 }}`
555
+ - Standard exit: `exit={{ opacity: 0 }}`
556
+ - Duration: typically `0.2s`–`0.3s`
557
+ - Used for: panel reveals, notification toasts, drawer slides, loading states
558
+
559
+ ### Interactive Feedback
560
+ - **Button press:** `active:scale-[0.97]` (slight shrink on click)
561
+ - **Card hover:** `hover:scale-[1.02]` (subtle grow, 12 uses)
562
+ - **Focus:** `focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2` (1px ring, keyboard-only)
563
+
564
+ ---
565
+
566
+ ## 10. Agent Prompt Guide
567
+
568
+ ### Quick Color Reference
569
+ - Page background: `bg-background` → `hsl(0 0% 5%)` → `#0d0d0d`
570
+ - Primary text: `text-foreground` → `hsl(0 0% 98%)` → `#fafafa`
571
+ - Secondary text: `text-muted-foreground` → `hsl(0 0% 55%)` → `#8c8c8c`
572
+ - Card surface: `bg-card` → `hsl(0 0% 7%)` → `#121212`
573
+ - Border: `border-border` → `hsl(0 0% 14%)` → `#242424`
574
+ - Hover background: `bg-muted/60` → `hsl(0 0% 12% / 0.6)`
575
+ - Success: `text-success-foreground` → `hsl(142 71% 76%)` → `#86efac`
576
+ - Error: `text-destructive` → `hsl(0 72% 51%)` → `#dc2626`
577
+
578
+ ### Example Component Prompts
579
+
580
+ - **"Create a settings card"**: `bg-card border border-border rounded-lg p-4`. Title at `text-lg font-semibold text-foreground`. Description at `text-sm text-muted-foreground`. Action button: `<Button variant="outline">`.
581
+ - **"Create a sidebar menu item"**: `group flex items-center gap-2 rounded-md px-3 py-1.5 text-xs text-sidebar-foreground hover:text-white hover:bg-muted/60 transition-colors`. Icon: `w-4 h-4 shrink-0 text-muted-foreground transition-colors group-hover:text-white`.
582
+ - **"Create a dropdown menu"**: Use `DropdownMenu` + `DropdownMenuTrigger` + `DropdownMenuContent` + `DropdownMenuItem` from `src/components/ui/dropdown-menu.tsx`. Icons auto-styled grey → white on hover via the component's built-in `[&_svg]` selectors.
583
+ - **"Create a form field"**: Label at `text-sm font-medium text-foreground mb-1.5`. Use `<Input>` component (never inline raw `<input>` with custom focus styles). Help text at `text-xs text-muted-foreground mt-1`.
584
+ - **"Create a tooltip"**: `bg-muted text-foreground text-xs rounded-md px-2 py-1 shadow-md`. For pill-style: use `rounded-full` instead of `rounded-md`.
585
+ - **"Create a status badge"**: `inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium`. Success: `bg-success/10 text-success-foreground`. Error: `bg-destructive/10 text-destructive`.
586
+
587
+ ### Iteration Guide
588
+
589
+ 1. **Always use semantic color tokens** — never raw palette colors (`stone-*`, `gray-*`, `slate-*`). Every color should trace back to a `--css-variable`.
590
+ 2. **`text-sm` is the default** — don't reach for `text-base` unless the context genuinely needs larger text (e.g., chat messages, hero content).
591
+ 3. **`rounded-md` for elements, `rounded-lg` for containers** — this is the consistent radius hierarchy. Dialogs get `rounded-xl` or `rounded-modal`.
592
+ 4. **`gap-2` is the standard** — 8px between items in any flex/grid layout. Use `gap-4` for major sections.
593
+ 5. **Icons are always `text-muted-foreground`** by default and brighten to `text-foreground` or `text-white` on hover via `group` + `group-hover:`.
594
+ 6. **`transition-colors duration-200`** is the standard animation. Don't add `transition-all` unless multiple property types are actually changing.
595
+ 7. **`hover:bg-muted/60`** is the canonical hover background. Use it consistently across menus, nav items, and interactive rows.
596
+ 8. **The `Button` component handles its own variants** — don't rebuild button styles from scratch. Use `variant="outline"` for most secondary actions.
597
+
OpenHands-Design/NORMALIZATION_LOG.md ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Token Normalization Log
2
+
3
+ Tracking the migration from raw Tailwind palette classes and arbitrary values to semantic design tokens.
4
+
5
+ ## Completed
6
+
7
+ - [x] `.dark` CSS block now declares all variables from `:root` (`--modal-background`, `--radius-*`, `--success`, `--warning`, `--info`, `--gradient-*`, `--shadow-*`, `--font-*`, `--settings-*`)
8
+ - [x] Migrated ~160 raw `stone-*` utility classes across 17 component files to semantic tokens (excluding `themeAppClassMap.ts`, `index.ts`, and scrollbar utilities)
9
+ - [x] Migrated ~44 raw `gray-*` utility classes across 10 files to semantic tokens
10
+ - [x] Migrated ~83 raw `neutral-*` classes across 3 files to semantic tokens (preserving VS Code diff mock borders)
11
+ - [x] Replaced 47 arbitrary border radius values (`rounded-[6px]` → `rounded-lg`, `rounded-[100px]` → `rounded-full`, `rounded-[12px]` → `rounded-xl`, `rounded-[4px]` → `rounded-md`, `rounded-r-[100px]` → `rounded-r-full`)
12
+ - [x] Replaced 74 arbitrary font sizes (`text-[11px]` → `text-xs`, `text-[10px]` → `text-xs`, `text-[12px]` → `text-xs`)
13
+ - [x] Standardized 57 `hover:bg-muted` opacity variants (`/40`, `/50`, `/70`, `/80`) to canonical `/60`
14
+ - [x] Replaced 6 unsafe `text-white` usages with semantic tokens (`text-foreground`, `text-card-foreground`)
15
+ - [x] Replaced `bg-[#141414]` → `bg-secondary` (2 instances)
16
+ - [x] Migrated ~100+ chromatic palette classes to semantic tokens: `amber/yellow` → `warning`, `blue/sky` → `info`, `green/emerald` → `success`, `red` → `destructive`
17
+ - [x] Unified tooltip backgrounds from `bg-popover`/`bg-card` to `bg-muted` across all 6 tooltip instances
18
+ - [x] Fixed 33 inline white buttons (`bg-white text-black hover:bg-muted/60` → `bg-primary text-primary-foreground hover:bg-primary/85`)
19
+ - [x] Fixed Button `light` variant from `bg-white text-black hover:bg-zinc-200` to `bg-primary text-primary-foreground hover:bg-primary/85`
20
+ - [x] Removed Dialog `--ring` inline override (`0 0% 95%`) that caused inconsistent focus ring color in modals
21
+ - [x] Updated global `--ring` from `0 0% 50%` to `0 0% 80%` for better visibility
22
+ - [x] Normalized ~50 inline input/textarea/select focus styles to canonical `focus-visible:` pattern (from mixed `focus:`/`focus-visible:` with missing offsets)
23
+ - [x] Changed all focus rings from `ring-2` to `ring-1` site-wide (~97 instances across 39 files)
24
+ - [x] Added `appearance: none` on `input[type="search"]` to strip browser default focus chrome
25
+ - [x] Removed focus ring from dialog close button
26
+ - [x] Consolidated `active:scale-95` (3 uses) → `active:scale-[0.97]` to match Button standard
27
+ - [x] Migrated `ChatThread.tsx` `messageTypeColors`: `yellow-500` → `warning`, `blue-500` → `info` (3 categories). Remaining categorical colors (`orange-500`, `indigo-500`, `purple-500`, `pink-500`) kept as raw palette — no semantic equivalent for multi-category distinctness
28
+ - [x] Migrated 14 remaining `bg-white` usages in non-button contexts to semantic tokens: toggles → `bg-primary`, resize grips → `bg-foreground`, badge → `bg-primary`, attachment previews → `bg-foreground/5`, CTA buttons → `bg-primary text-primary-foreground hover:bg-primary/85`, ghost hover buttons → `hover:bg-primary hover:text-primary-foreground`
29
+ - [x] Documented `duration-200` vs `duration-300` convention (200ms = local feedback, 300ms = layout/panel motion)
30
+ - [x] ~~Migrate legacy `index.ts`~~ — invalid; `screens/index.ts` and `components/workflow/index.ts` are barrel files with zero raw color classes
31
+
32
+ ## Deferred by Design
33
+
34
+ - [ ] `themeAppClassMap.ts` and `NewUserExperienceFlowchart.tsx` use raw `stone-*` / `rgb()` values — these are **theme definition maps** that intentionally encode per-theme palettes (dark/light/sepia). Migrating requires defining CSS variables for each theme mode, which is an architectural change
35
+ - [ ] `sepia` theme in `themeAppClassMap.ts` uses hardcoded `rgb()` — requires defining a `.theme-sepia` CSS variable block before semantic classes can replace arbitrary values
36
+ - [ ] `ChatThread.tsx` categorical palette (`orange-500`, `indigo-500`, `purple-500`, `pink-500`) for `bug`, `docs`, `dependency`, `git` message types — no semantic tokens exist for multi-category distinctness; would need new `--chart-*` or `--category-*` CSS variables
OpenHands-Design/README.md ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OpenHands Design System
2
+
3
+ A portable design system extracted from the OpenHands UI. Drop it into any React + Tailwind project to get a consistent dark-first interface with semantic color tokens, pre-built components, and a comprehensive style guide.
4
+
5
+ ## What's Included
6
+
7
+ ```
8
+ OpenHands-Design/
9
+ DESIGN.md # Full design system specification
10
+ README.md # This file
11
+ tailwind.config.js # Tailwind theme (colors, radii, fonts, animations)
12
+ src/
13
+ globals.css # CSS custom properties (design tokens) + base resets
14
+ lib/
15
+ utils.ts # cn() helper (clsx + tailwind-merge)
16
+ components/ui/
17
+ button.tsx # Button with 8 variants (default, destructive, outline, light, secondary, muted, ghost, link)
18
+ input.tsx # Text input with unified focus style
19
+ search-input.tsx # Search input with icon, clear button, and 3 sizes
20
+ native-select.tsx # Native <select> with consistent styling
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ### Install with npx
26
+
27
+ From your project root:
28
+
29
+ ```bash
30
+ npx openhands-design
31
+ ```
32
+
33
+ This adds `./OpenHands-Design/` (including `DESIGN.md`, tokens, and UI components). Then ask your AI assistant to use **`DESIGN.md`** for UI work. If the folder already exists, run `npx openhands-design --force` to replace it.
34
+
35
+ ### 1. Install dependencies
36
+
37
+ ```bash
38
+ npm install clsx tailwind-merge class-variance-authority @radix-ui/react-slot lucide-react tailwindcss-animate
39
+ ```
40
+
41
+ ### 2. Copy files into your project
42
+
43
+ ```bash
44
+ # Copy the design tokens and global CSS
45
+ cp OpenHands-Design/src/globals.css your-project/src/globals.css
46
+
47
+ # Copy the Tailwind config (or merge into your existing one)
48
+ cp OpenHands-Design/tailwind.config.js your-project/tailwind.config.js
49
+
50
+ # Copy the utility helper
51
+ cp OpenHands-Design/src/lib/utils.ts your-project/src/lib/utils.ts
52
+
53
+ # Copy the UI components
54
+ cp -r OpenHands-Design/src/components/ui/ your-project/src/components/ui/
55
+ ```
56
+
57
+ ### 3. Import globals.css
58
+
59
+ In your app entry point (e.g., `main.tsx` or `App.tsx`):
60
+
61
+ ```tsx
62
+ import './globals.css';
63
+ ```
64
+
65
+ ### 4. Add the dark class
66
+
67
+ The system is dark-first. Add the `dark` class to your `<html>` tag:
68
+
69
+ ```html
70
+ <html lang="en" class="dark">
71
+ ```
72
+
73
+ ### 5. Start using components
74
+
75
+ ```tsx
76
+ import { Button } from './components/ui/button';
77
+ import { Input } from './components/ui/input';
78
+ import { SearchInput } from './components/ui/search-input';
79
+ import { NativeSelect } from './components/ui/native-select';
80
+
81
+ function Example() {
82
+ return (
83
+ <div className="flex flex-col gap-4 bg-background p-6 text-foreground">
84
+ <h1 className="text-2xl font-semibold">Settings</h1>
85
+ <p className="text-sm text-muted-foreground">Manage your account.</p>
86
+
87
+ <Input placeholder="Your name" />
88
+
89
+ <NativeSelect>
90
+ <option>Option A</option>
91
+ <option>Option B</option>
92
+ </NativeSelect>
93
+
94
+ <div className="flex gap-2">
95
+ <Button>Save</Button>
96
+ <Button variant="outline">Cancel</Button>
97
+ <Button variant="destructive">Delete</Button>
98
+ </div>
99
+ </div>
100
+ );
101
+ }
102
+ ```
103
+
104
+ ## Using with AI Agents (Cursor, Copilot, etc.)
105
+
106
+ The `DESIGN.md` file is structured as an AI-readable specification. Two ways to use it:
107
+
108
+ ### Option A: Cursor Rule (recommended)
109
+
110
+ Create `.cursor/rules/design-system.md` in your project:
111
+
112
+ ```markdown
113
+ When building UI components, follow the design system in /DESIGN.md.
114
+
115
+ Key rules:
116
+ - Use semantic color tokens (bg-card, text-foreground, border-border) — never raw palette classes
117
+ - Use the Button, Input, SearchInput, and NativeSelect components — never raw HTML with inline styles
118
+ - Hover on dark surfaces: hover:bg-muted/60
119
+ - Hover on white/primary buttons: hover:bg-primary/85
120
+ - Focus rings: focus-visible:ring-1 (keyboard-only, 1px)
121
+ - Default text: text-sm font-normal text-foreground
122
+ - Secondary text: text-sm text-muted-foreground
123
+ - Standard gap: gap-2 (8px)
124
+ - Standard card: bg-card border border-border rounded-lg p-4
125
+ ```
126
+
127
+ Every Cursor conversation will now follow your design system automatically.
128
+
129
+ ### Option B: Direct prompt
130
+
131
+ Paste this at the start of a conversation:
132
+
133
+ > Build this feature following the design system in DESIGN.md. Use semantic tokens for all colors, the Button component for actions, and the Input component for form fields.
134
+
135
+ ## Token Architecture
136
+
137
+ All colors are HSL triplets stored as CSS custom properties. Tailwind maps them via `hsl(var(--token))`.
138
+
139
+ ```
140
+ Background scale (darkest → lightest):
141
+ --background 5% #0d0d0d Page background
142
+ --card 7% #121212 Cards, elevated surfaces
143
+ --secondary 8% #141414 Secondary surfaces
144
+ --muted 12% #1f1f1f Hover fills, badges, tooltips
145
+ --border 14% #242424 Borders, dividers
146
+ --muted-hover 18% #2e2e2e Hover on muted surfaces
147
+
148
+ Text scale:
149
+ --foreground 98% #fafafa Primary text
150
+ --muted-foreground 55% #8c8c8c Secondary text, placeholders
151
+ --primary 100% #ffffff Maximum emphasis, button bg
152
+ --primary-foreground 0% #000000 Text on white buttons
153
+
154
+ Semantic colors:
155
+ --success hsl(142 71% 45%) Green — success states
156
+ --warning hsl(38 92% 50%) Amber — warnings, in-progress
157
+ --info hsl(217 91% 60%) Blue — links, informational
158
+ --destructive hsl(0 72% 51%) Red — errors, danger
159
+ ```
160
+
161
+ ## Button Variants
162
+
163
+ | Variant | Look | Use |
164
+ |---------|------|-----|
165
+ | `default` | White bg, black text | Primary CTA |
166
+ | `destructive` | Red bg, white text | Delete, danger |
167
+ | `outline` | Transparent, border | Secondary actions |
168
+ | `light` | White bg, border | High-contrast primary |
169
+ | `secondary` | Dark bg | Tertiary actions |
170
+ | `muted` | Muted bg, grey text | Subdued actions |
171
+ | `ghost` | Transparent, no border | Minimal chrome |
172
+ | `link` | Underline on hover | Inline links |
173
+
174
+ ## Customization
175
+
176
+ ### Changing the color scheme
177
+
178
+ Edit the HSL values in `globals.css`. Every UI element updates automatically:
179
+
180
+ ```css
181
+ :root {
182
+ --background: 220 20% 5%; /* Add a blue tint */
183
+ --card: 220 15% 8%;
184
+ --border: 220 10% 16%;
185
+ }
186
+ ```
187
+
188
+ ### Adding a light theme
189
+
190
+ Create a new class block in `globals.css` with inverted values:
191
+
192
+ ```css
193
+ .light {
194
+ --background: 0 0% 100%;
195
+ --foreground: 0 0% 5%;
196
+ --card: 0 0% 97%;
197
+ --border: 0 0% 88%;
198
+ /* ... */
199
+ }
200
+ ```
201
+
202
+ Then toggle `class="light"` on the `<html>` element.
203
+
204
+ ## Reference
205
+
206
+ See [DESIGN.md](./DESIGN.md) for the complete specification including:
207
+
208
+ 1. Visual theme and atmosphere
209
+ 2. Full color palette with hex values
210
+ 3. Typography rules and type scale
211
+ 4. Component styling recipes
212
+ 5. Layout principles and spacing system
213
+ 6. Depth and elevation system
214
+ 7. Do's and Don'ts
215
+ 8. Responsive behavior
216
+ 9. Interaction and motion patterns
217
+ 10. AI agent prompt guide
218
+ 11. Normalization backlog
219
+
220
+ ## License
221
+
222
+ MIT
OpenHands-Design/index.html ADDED
@@ -0,0 +1,396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>OpenHands Design System</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
9
+ <style>
10
+ *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
11
+
12
+ :root{
13
+ --bg:hsl(0 0% 5%);
14
+ --card:hsl(0 0% 7%);
15
+ --secondary:hsl(0 0% 8%);
16
+ --muted:hsl(0 0% 12%);
17
+ --border:hsl(0 0% 14%);
18
+ /* DESIGN.md: interactive border emphasis (e.g. card/button hover) */
19
+ --border-hover:hsl(0 0% 24%);
20
+ --muted-hover:hsl(0 0% 18%);
21
+ --fg:hsl(0 0% 98%);
22
+ --fg-muted:hsl(0 0% 55%);
23
+ --primary:hsl(0 0% 100%);
24
+ --primary-fg:hsl(0 0% 0%);
25
+ --success:#22c55e;
26
+ --success-fg:#86efac;
27
+ --warning:#f59e0b;
28
+ --info:#3b82f6;
29
+ --destructive:#dc2626;
30
+ --destructive-fg:#fafafa;
31
+ --ring:#cccccc;
32
+ --shadow-card:0 1px 2px 0 hsl(0 0% 0% / 0.3);
33
+ --font-sans:'Inter',system-ui,sans-serif;
34
+ --font-mono:'JetBrains Mono',monospace;
35
+ }
36
+
37
+ html{scroll-behavior:smooth}
38
+ body{font-family:var(--font-sans);background:var(--bg);color:var(--fg);line-height:1.6;-webkit-font-smoothing:antialiased}
39
+
40
+ /* Nav */
41
+ .nav{position:sticky;top:0;z-index:50;display:flex;align-items:center;flex-wrap:nowrap;gap:16px;padding:0 24px 0 16px;height:56px;background:hsl(0 0% 5% / 0.85);backdrop-filter:blur(12px);border-bottom:1px solid var(--border);overflow:hidden}
42
+ .nav-start{display:flex;align-items:center;flex-wrap:nowrap;gap:12px;flex-shrink:0;min-width:0}
43
+ .nav-github{display:inline-flex;align-items:center;gap:6px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;color:var(--fg-muted);text-decoration:none;padding:4px 10px;border-radius:6px;border:1px solid var(--border);transition:all 0.2s;flex-shrink:0}
44
+ .nav-github:hover{background:var(--muted);color:var(--fg);border-color:var(--border-hover)}
45
+ .nav-links{display:flex;flex:1;justify-content:flex-end;gap:4px;list-style:none;margin:0;padding:0;min-width:0;flex-wrap:nowrap}
46
+ .nav-links a{font-size:13px;color:var(--fg-muted);text-decoration:none;padding:6px 12px;border-radius:6px;transition:all 0.2s}
47
+ .nav-links a:hover{color:var(--fg);background:var(--muted)}
48
+ .nav-logo{display:flex;align-items:center;flex-shrink:0;opacity:0.85;transition:opacity 0.2s}
49
+ .nav-logo:hover{opacity:1}
50
+ .nav-logo svg{height:22px;width:auto;display:block}
51
+ /* Hero */
52
+ .hero{text-align:center;padding:80px 24px 64px;max-width:720px;margin:0 auto}
53
+ .hero h1{font-size:48px;font-weight:600;line-height:1.1;letter-spacing:-1.5px;margin-bottom:16px}
54
+ .hero p{font-size:16px;color:var(--fg-muted);line-height:1.6;max-width:520px;margin:0 auto 32px}
55
+ .hero-buttons{display:flex;gap:12px;justify-content:center;flex-wrap:wrap}
56
+
57
+ /* Buttons */
58
+ .btn-primary{display:inline-flex;align-items:center;justify-content:center;height:40px;padding:0 20px;font-size:14px;font-weight:400;border-radius:6px;text-decoration:none;transition:all 0.2s;background:var(--secondary);color:var(--fg);border:1px solid var(--border)}
59
+ .btn-primary:hover{background:var(--muted-hover);border-color:var(--border-hover)}
60
+ .btn-dark{display:inline-flex;align-items:center;justify-content:center;height:40px;padding:0 20px;font-size:14px;font-weight:400;border-radius:6px;text-decoration:none;transition:all 0.2s;background:var(--primary);color:var(--primary-fg)}
61
+ .btn-dark:hover{opacity:0.85}
62
+ .btn-ghost{display:inline-flex;align-items:center;justify-content:center;height:40px;padding:0 20px;font-size:14px;font-weight:400;border-radius:6px;text-decoration:none;transition:all 0.2s;color:var(--fg-muted);background:transparent}
63
+ .btn-ghost:hover{color:var(--fg);background:var(--muted)}
64
+ .btn-destructive{display:inline-flex;align-items:center;justify-content:center;height:40px;padding:0 20px;font-size:14px;font-weight:400;border-radius:6px;text-decoration:none;transition:all 0.2s;background:var(--destructive);color:var(--destructive-fg)}
65
+ .btn-destructive:hover{opacity:0.85}
66
+ .btn-outline{display:inline-flex;align-items:center;justify-content:center;height:40px;padding:0 20px;font-size:14px;font-weight:400;border-radius:6px;text-decoration:none;transition:all 0.2s;color:var(--fg);background:var(--bg);border:1px solid var(--border)}
67
+ .btn-outline:hover{background:var(--muted);color:var(--fg)}
68
+ .btn-muted{display:inline-flex;align-items:center;justify-content:center;height:40px;padding:0 20px;font-size:14px;font-weight:400;border-radius:6px;text-decoration:none;transition:all 0.2s;color:var(--fg-muted);background:var(--muted)}
69
+ .btn-muted:hover{background:var(--muted-hover);color:var(--fg)}
70
+ .btn-pill{display:inline-flex;align-items:center;justify-content:center;height:28px;padding:0 12px;font-size:12px;font-weight:500;border-radius:9999px;text-decoration:none;transition:all 0.2s;background:var(--muted);color:var(--fg-muted)}
71
+ .btn-pill:hover{color:var(--fg);background:var(--muted-hover)}
72
+
73
+ /* Sections */
74
+ .section{max-width:1100px;margin:0 auto;padding:64px 24px}
75
+ .section-label{font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:1.5px;color:var(--fg-muted);margin-bottom:8px}
76
+ .section-title{font-size:28px;font-weight:600;letter-spacing:-0.5px;margin-bottom:40px}
77
+ .section-divider{border:none;border-top:1px solid var(--border);margin:0}
78
+
79
+ /* Color swatches */
80
+ .color-group-label{font-size:13px;font-weight:500;color:var(--fg-muted);margin-bottom:12px;margin-top:32px}
81
+ .color-group-label:first-of-type{margin-top:0}
82
+ .color-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:12px;margin-bottom:24px}
83
+ .color-swatch{border-radius:10px;overflow:hidden;border:1px solid var(--border);background:var(--card);transition:transform 0.2s}
84
+ .color-swatch:hover{transform:translateY(-2px)}
85
+ .color-swatch-block{height:80px}
86
+ .color-swatch-info{padding:10px 12px}
87
+ .color-swatch-name{font-size:13px;font-weight:500;margin-bottom:2px}
88
+ .color-swatch-hex{font-family:var(--font-mono);font-size:11px;color:var(--fg-muted)}
89
+ .color-swatch-role{font-size:11px;color:var(--fg-muted);margin-top:4px}
90
+
91
+ /* Typography */
92
+ .type-sample{padding:20px 0;border-bottom:1px solid var(--border)}
93
+ .type-sample:last-child{border-bottom:none}
94
+ .type-meta{font-size:12px;color:var(--fg-muted);margin-top:8px;font-family:var(--font-mono)}
95
+
96
+ /* Buttons section */
97
+ .button-row{display:flex;flex-wrap:wrap;gap:24px;align-items:flex-start}
98
+ .button-item{display:flex;flex-direction:column;align-items:center;gap:8px}
99
+ .button-label{font-size:11px;color:var(--fg-muted);text-align:center}
100
+
101
+ /* Cards */
102
+ .card-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:16px}
103
+ .card{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:24px;transition:all 0.2s}
104
+ .card:hover{border-color:var(--border-hover)}
105
+ .card h3{font-size:16px;font-weight:600;margin-bottom:8px}
106
+ .card p{font-size:14px;color:var(--fg-muted);line-height:1.6}
107
+ .card-badge{display:inline-block;font-size:11px;font-weight:500;padding:2px 8px;border-radius:9999px;margin-bottom:12px}
108
+
109
+ /* Forms */
110
+ .form-group{max-width:480px;margin-bottom:24px}
111
+ .form-label{display:block;font-size:14px;font-weight:500;margin-bottom:6px}
112
+ .form-input,.form-textarea{width:100%;height:40px;padding:0 12px;font-size:14px;font-family:var(--font-sans);color:var(--fg);background:hsl(0 0% 12% / 0.4);border:1px solid var(--border);border-radius:6px;outline:none;transition:all 0.2s}
113
+ .form-input::placeholder,.form-textarea::placeholder{color:var(--fg-muted)}
114
+ .form-input:hover,.form-textarea:hover{background:hsl(0 0% 12% / 0.6)}
115
+ .form-input:focus,.form-textarea:focus{background:hsl(0 0% 12% / 0.6);box-shadow:0 0 0 1px var(--ring),0 0 0 3px var(--bg)}
116
+ .form-input--focus{background:hsl(0 0% 12% / 0.6) !important;box-shadow:0 0 0 1px var(--ring),0 0 0 3px var(--bg) !important}
117
+ .form-input--error{border-color:var(--destructive) !important;box-shadow:0 0 0 1px var(--destructive),0 0 0 3px var(--bg) !important}
118
+ .form-textarea{height:auto;min-height:80px;padding:10px 12px;resize:vertical}
119
+ .form-state-label{font-size:11px;color:var(--fg-muted);margin-top:6px}
120
+
121
+ /* Spacing */
122
+ .spacing-row{display:flex;flex-wrap:wrap;gap:16px;align-items:flex-end}
123
+ .spacing-item{display:flex;flex-direction:column;align-items:center;gap:8px}
124
+ .spacing-block{height:40px;background:var(--primary);border-radius:3px;min-width:2px}
125
+ .spacing-value{font-family:var(--font-mono);font-size:11px;color:var(--fg-muted)}
126
+
127
+ /* Radius */
128
+ .radius-row{display:flex;flex-wrap:wrap;gap:24px;align-items:flex-start}
129
+ .radius-item{display:flex;flex-direction:column;align-items:center;gap:8px}
130
+ .radius-box{width:64px;height:64px;border:2px solid var(--fg-muted);background:var(--card)}
131
+ .radius-label{font-family:var(--font-mono);font-size:12px;color:var(--fg)}
132
+ .radius-context{font-size:11px;color:var(--fg-muted)}
133
+
134
+ /* Elevation */
135
+ .elevation-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px}
136
+ .elevation-card{background:var(--card);border-radius:10px;padding:24px;min-height:100px;display:flex;flex-direction:column;justify-content:flex-end}
137
+ .elevation-label{font-size:13px;font-weight:500;margin-bottom:4px}
138
+ .elevation-desc{font-size:12px;color:var(--fg-muted)}
139
+
140
+ /* Footer */
141
+ .footer{text-align:center;padding:48px 24px;font-size:13px;color:var(--fg-muted);border-top:1px solid var(--border)}
142
+ .footer a{color:var(--fg-muted);text-decoration:none;transition:color 0.2s}
143
+ .footer a:hover{color:var(--fg)}
144
+
145
+ /* Responsive */
146
+ @media(max-width:768px){
147
+ .nav-links{display:none}
148
+ .hero h1{font-size:32px}
149
+ .color-grid{grid-template-columns:repeat(2,1fr)}
150
+ .card-grid{grid-template-columns:1fr}
151
+ }
152
+ </style>
153
+ </head>
154
+ <body>
155
+
156
+ <nav class="nav">
157
+ <div class="nav-start">
158
+ <a class="nav-logo" href="https://github.com/FraterCCCLXIII/OpenHands-Design.md" target="_blank" rel="noopener noreferrer" aria-label="OpenHands">
159
+ <svg viewBox="0 0 599.09 99.17" fill="#fff" aria-hidden="true"><path d="M159.74,53.71c0-18.39,11.81-31.21,28.17-31.21s28.17,12.82,28.17,31.21-11.81,31.21-28.17,31.21-28.17-12.82-28.17-31.21ZM205.29,53.71c0-13.16-7.17-21.68-17.38-21.68s-17.38,8.52-17.38,21.68,7.17,21.68,17.38,21.68,17.38-8.52,17.38-21.68Z"/><path d="M246.07,84.92c-5.74,0-9.95-2.28-12.74-5.57v19.82h-10.12v-59.47h10.12v4.72c2.78-3.29,7-5.57,12.74-5.57,12.4,0,19.48,10.46,19.48,23.03s-7.09,23.03-19.48,23.03ZM233.08,60.63v2.61c0,8.18,4.72,12.82,10.97,12.82,7.34,0,11.3-5.74,11.3-14.17s-3.96-14.17-11.3-14.17c-6.24,0-10.97,4.56-10.97,12.91Z"/><path d="M291.26,84.92c-12.65,0-21.51-9.36-21.51-23.03s8.77-23.03,21.09-23.03,19.65,9.7,19.65,21.85v3.37h-31.04c.76,7.59,5.32,12.23,11.81,12.23,4.98,0,8.94-2.53,10.29-7.09l8.69,3.29c-3.12,7.76-10.12,12.4-18.98,12.4ZM290.76,47.38c-5.23,0-9.28,3.12-10.8,9.11h20.33c-.08-4.89-3.12-9.11-9.53-9.11Z"/><path d="M317.25,83.99v-44.29h10.12v4.72c2.53-2.95,6.49-5.57,12.23-5.57,9.28,0,14.85,6.41,14.85,15.94v29.19h-10.12v-26.23c0-5.48-2.19-9.45-7.76-9.45-4.55,0-9.19,3.37-9.19,9.7v25.98h-10.12Z"/><path d="M404.17,23.43h10.8v60.57h-10.8v-26.49h-29.02v26.49h-10.8V23.43h10.8v24.63h29.02v-24.63Z"/><path d="M436.93,84.75c-8.43,0-14.93-5.15-14.93-13.07,0-8.44,6.33-12.15,14.85-13.92l12.23-2.53v-.76c0-4.22-2.19-6.83-7.59-6.83-4.81,0-7.34,2.19-8.52,6.5l-9.53-2.19c2.19-7.34,8.69-13.07,18.47-13.07,10.63,0,17.04,5.06,17.04,15.27v19.06c0,2.53,1.1,3.29,3.88,2.95v7.84c-7.34.84-11.22-.59-12.74-4.22-2.78,3.12-7.42,4.98-13.16,4.98ZM449.08,68.39v-5.4l-9.53,2.02c-4.3.93-7.51,2.28-7.51,6.24,0,3.46,2.53,5.4,6.41,5.4,5.4,0,10.63-2.87,10.63-8.27Z"/><path d="M469.17,83.99v-44.29h10.12v4.72c2.53-2.95,6.49-5.57,12.23-5.57,9.28,0,14.85,6.41,14.85,15.94v29.19h-10.12v-26.23c0-5.48-2.19-9.45-7.76-9.45-4.56,0-9.2,3.37-9.2,9.7v25.98h-10.12Z"/><path d="M532.56,84.92c-12.4,0-19.48-10.46-19.48-23.03s7.08-23.03,19.48-23.03c5.74,0,9.95,2.28,12.74,5.57v-21h10.12v60.57h-10.12v-4.64c-2.78,3.29-7,5.57-12.74,5.57ZM545.55,60.63c0-8.35-4.72-12.91-10.96-12.91-7.34,0-11.3,5.74-11.3,14.17s3.96,14.17,11.3,14.17c6.24,0,10.96-4.64,10.96-12.82v-2.61Z"/><path d="M560.54,75.56l7.59-6.07c2.62,4.3,7.68,7.17,12.82,7.17,4.3,0,8.27-1.52,8.27-5.48s-3.71-4.22-10.71-5.65c-7-1.43-15.01-3.21-15.01-12.65,0-8.1,7.09-14,17.29-14,7.76,0,14.68,3.46,17.88,8.35l-6.83,6.16c-2.53-3.96-6.75-6.24-11.64-6.24-4.13,0-6.83,1.86-6.83,4.81,0,3.21,3.2,3.8,8.77,4.98,7.51,1.6,16.95,3.21,16.95,13.33,0,8.94-8.18,14.68-18.22,14.68-8.18,0-16.36-3.29-20.33-9.36Z"/><path d="M64.97,14.8V1.93c0-1.07.86-1.93,1.93-1.93s1.93.86,1.93,1.93v12.87c0,1.07-.86,1.93-1.93,1.93s-1.93-.86-1.93-1.93Z"/><path d="M74.95,16.72l6.43-11.15c.53-.92,1.71-1.24,2.64-.71.92.53,1.24,1.71.71,2.64l-6.43,11.15c-.53.92-1.71,1.24-2.64.71-.92-.53-1.24-1.71-.71-2.64Z"/><path d="M58.85,16.72l-6.43-11.15c-.53-.92-1.71-1.24-2.64-.71-.92.53-1.24,1.71-.71,2.64l6.43,11.15c.53.92,1.71,1.24,2.64.71.92-.53,1.24-1.71.71-2.64Z"/><path d="M128.77,56.65c0-3.35.9-13.3,1.19-16.58.19-2.22-.07-3.44-.43-4.06-.26-.46-.67-.78-1.66-.84-.71-.05-1.49.16-2.07.68-.54.49-1.15,1.48-1.15,3.47v.11s-.89,15.12-.89,15.12c-.03.54-.29,1.05-.72,1.39-.42.34-.97.49-1.51.4l-9.29-1.47-10.02-1.33c-.93-.12-1.63-.89-1.67-1.82l-.55-11.95v-.1c-.25-4.76-.49-9.1-.49-10.44,0-3.75-.63-5.33-1.19-5.99-.44-.53-1.08-.76-2.44-.76-.49,0-.83.1-1.09.25-.25.15-.54.41-.82.94-.59,1.12-1.02,3.22-.86,6.88.21,4.76.53,8.31.85,11.51.32,3.2.63,6.1.81,9.47.27,5.28.25,8.92.03,11.39-.11,1.23-.27,2.23-.48,3.02-.2.75-.51,1.51-1.04,2.07-.64.69-1.56,1.02-2.52.79-.76-.18-1.29-.66-1.58-.97-.61-.64-1.04-1.46-1.21-1.89-.98-2.47-4.01-8.22-8.12-11.46-1.2-.95-2.07-1.22-2.62-1.26-.52-.04-.89.11-1.19.35-.33.26-.57.63-.69.99-.04.13-.06.22-.07.27,1.11,1.88,5.53,8.77,7.61,15.76,1.55,5.21,5.29,10.52,8.09,12.8,2.71,2.2,7.57,3.57,13.05,3.84,5.42.27,11.01-.57,14.95-2.33,7.6-3.41,9.14-10.91,9.84-14.16.54-2.52.55-5.22.4-7.72-.07-1.25-.18-2.41-.27-3.49-.09-1.04-.17-2.05-.17-2.88ZM110.59,24.28c0-1.17-.31-2.21-.83-2.91-.47-.63-1.16-1.07-2.26-1.07-.91,0-1.52.11-1.94.29-.39.16-.71.42-1,.9-.68,1.1-1.18,3.3-1.18,7.69l.48,10.39c.18,3.47.37,7.22.49,10.35l6.25.83v-26.47ZM114.45,51.31l5.58.88.76-12.93v-9.97c0-1.37-.56-2.21-1.22-2.74-.74-.6-1.6-.81-2-.81-.74,0-1.5.11-2.05.5-.42.3-1.07,1.01-1.07,3.05v22.01ZM124.65,32c1.15-.58,2.39-.76,3.48-.69,1.97.13,3.71.96,4.75,2.77.95,1.65,1.15,3.83.93,6.31-.3,3.43-1.18,13.11-1.18,16.25,0,.63.06,1.47.16,2.54.09,1.05.21,2.28.28,3.6.15,2.63.16,5.72-.48,8.75-.67,3.15-2.49,12.6-12.03,16.88-4.64,2.08-10.87,2.95-16.72,2.66-5.79-.28-11.64-1.73-15.29-4.7-3.44-2.8-7.59-8.79-9.35-14.69-1.99-6.67-6.29-13.24-7.36-15.11-.63-1.1-.43-2.4-.14-3.27.33-.98.98-2,1.94-2.77,1-.79,2.32-1.29,3.88-1.18,1.53.12,3.11.81,4.72,2.08,4.14,3.27,7.18,8.43,8.67,11.59.02-.15.03-.3.05-.46.19-2.21.23-5.65-.04-10.86-.17-3.26-.47-6.05-.79-9.29-.32-3.24-.65-6.87-.87-11.72-.17-3.88.23-6.82,1.31-8.86.56-1.06,1.32-1.9,2.28-2.46.96-.56,2.01-.78,3.04-.78,1.53,0,3.43.22,4.95,1.66.13-.29.28-.56.44-.81.7-1.13,1.63-1.93,2.77-2.42,1.1-.47,2.29-.6,3.46-.6,2.36,0,4.19,1.04,5.36,2.63.76,1.03,1.22,2.23,1.44,3.46,1.25-.57,2.51-.64,3.28-.64,1.31,0,3.02.53,4.43,1.68,1.49,1.21,2.65,3.11,2.65,5.74v2.71Z"/><path d="M5.12,56.65c0-3.35-.9-13.3-1.19-16.58-.19-2.22.07-3.44.43-4.06.26-.46.67-.78,1.66-.84.71-.05,1.49.16,2.07.68.54.49,1.15,1.48,1.15,3.47v.11s.89,15.12.89,15.12c.03.54.29,1.05.72,1.39.42.34.97.49,1.51.4l9.29-1.47,10.02-1.33c.93-.12,1.63-.89,1.67-1.82l.55-11.95v-.1c.25-4.76.48-9.1.48-10.44,0-3.75.63-5.33,1.19-5.99.44-.53,1.08-.76,2.44-.76.49,0,.83.1,1.09.25.25.15.54.41.82.94.59,1.12,1.02,3.22.86,6.88-.21,4.76-.53,8.31-.85,11.51-.32,3.2-.63,6.1-.81,9.47-.27,5.28-.25,8.92-.03,11.39.11,1.23.27,2.23.48,3.02.2.75.51,1.51,1.04,2.07.65.69,1.56,1.02,2.52.79.76-.18,1.29-.66,1.58-.97.61-.64,1.04-1.46,1.21-1.89.98-2.47,4.01-8.22,8.12-11.46,1.2-.95,2.07-1.22,2.62-1.26.52-.04.89.11,1.19.35.33.26.57.63.69.99.04.13.06.22.07.27-1.11,1.88-5.53,8.77-7.61,15.76-1.55,5.21-5.29,10.52-8.09,12.8-2.71,2.2-7.57,3.57-13.05,3.84-5.43.27-11.01-.57-14.95-2.33-7.6-3.41-9.15-10.91-9.84-14.16-.54-2.52-.55-5.22-.4-7.72.07-1.25.18-2.41.27-3.49.09-1.04.17-2.05.17-2.88ZM23.29,24.28c0-1.17.31-2.21.83-2.91.47-.63,1.16-1.07,2.26-1.07.91,0,1.52.11,1.95.29.39.16.71.42,1,.9.68,1.1,1.18,3.3,1.18,7.69l-.48,10.39c-.18,3.47-.37,7.22-.49,10.35l-6.25.83v-26.47ZM19.43,51.31l-5.58.88-.76-12.93v-9.97c0-1.37.56-2.21,1.22-2.74.74-.6,1.59-.81,2-.81.74,0,1.5.11,2.05.5.42.3,1.07,1.01,1.07,3.05v22.01ZM9.24,32c-1.15-.58-2.39-.76-3.48-.69-1.97.13-3.7.96-4.75,2.77-.95,1.65-1.15,3.83-.93,6.31.3,3.43,1.18,13.11,1.18,16.25,0,.63-.07,1.47-.16,2.54-.09,1.05-.21,2.28-.28,3.6-.15,2.63-.16,5.72.48,8.75.67,3.15,2.49,12.6,12.04,16.88,4.64,2.08,10.87,2.95,16.72,2.66,5.79-.28,11.65-1.73,15.29-4.7,3.44-2.8,7.59-8.79,9.35-14.69,1.99-6.67,6.29-13.24,7.36-15.11.63-1.1.43-2.4.14-3.27-.33-.98-.98-2-1.94-2.77-1-.79-2.32-1.29-3.88-1.18-1.53.12-3.11.81-4.72,2.08-4.14,3.27-7.18,8.43-8.67,11.59-.02-.15-.03-.3-.05-.46-.19-2.21-.23-5.65.04-10.86.17-3.26.47-6.05.79-9.29.32-3.24.65-6.87.87-11.72.17-3.88-.23-6.82-1.31-8.86-.56-1.06-1.32-1.9-2.28-2.46-.96-.56-2.01-.78-3.04-.78-1.53,0-3.43.22-4.95,1.66-.13-.29-.28-.56-.44-.81-.7-1.13-1.63-1.93-2.77-2.42-1.1-.47-2.28-.6-3.46-.6-2.36,0-4.19,1.04-5.36,2.63-.76,1.03-1.22,2.23-1.44,3.46-1.25-.57-2.51-.64-3.27-.64-1.31,0-3.02.53-4.43,1.68-1.49,1.21-2.64,3.11-2.64,5.74v2.71Z"/></svg>
160
+ </a>
161
+ <a class="nav-github" href="https://github.com/FraterCCCLXIII/OpenHands-Design.md" target="_blank" rel="noopener noreferrer" aria-label="OpenHands-Design.md on GitHub">
162
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2 .37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>
163
+ OpenHands-Design.md
164
+ </a>
165
+ </div>
166
+ <ul class="nav-links">
167
+ <li><a href="#colors">Colors</a></li>
168
+ <li><a href="#typography">Typography</a></li>
169
+ <li><a href="#buttons">Buttons</a></li>
170
+ <li><a href="#cards">Cards</a></li>
171
+ <li><a href="#forms">Forms</a></li>
172
+ <li><a href="#spacing">Spacing</a></li>
173
+ <li><a href="#radius">Radius</a></li>
174
+ <li><a href="#elevation">Elevation</a></li>
175
+ </ul>
176
+ </nav>
177
+
178
+ <section class="hero">
179
+ <h1>OpenHands<br>Design System</h1>
180
+ <p>A design token catalog generated from DESIGN.md. Every color, font, component, and spacing value, visualized on the near-black monochrome canvas.</p>
181
+ <div class="hero-buttons">
182
+ <a class="btn-dark" href="https://github.com/FraterCCCLXIII/OpenHands-Design.md" target="_blank">View Repository</a>
183
+ <a class="btn-primary" href="#colors">Explore Tokens</a>
184
+ </div>
185
+ </section>
186
+
187
+ <hr class="section-divider">
188
+
189
+ <!-- ==================== COLORS ==================== -->
190
+ <section class="section" id="colors">
191
+ <div class="section-label">01 / Colors</div>
192
+ <h2 class="section-title">Color Palette</h2>
193
+
194
+ <div class="color-group-label">Core Surfaces</div>
195
+ <div class="color-grid">
196
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#0d0d0d"></div><div class="color-swatch-info"><div class="color-swatch-name">background</div><div class="color-swatch-hex">#0d0d0d</div><div class="color-swatch-role">Page background, app shell</div></div></div>
197
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#121212"></div><div class="color-swatch-info"><div class="color-swatch-name">card</div><div class="color-swatch-hex">#121212</div><div class="color-swatch-role">Card surfaces, elevated containers</div></div></div>
198
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#141414"></div><div class="color-swatch-info"><div class="color-swatch-name">secondary</div><div class="color-swatch-hex">#141414</div><div class="color-swatch-role">Secondary surfaces, sidebar accent</div></div></div>
199
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#1f1f1f"></div><div class="color-swatch-info"><div class="color-swatch-name">muted</div><div class="color-swatch-hex">#1f1f1f</div><div class="color-swatch-role">Hover fills, badges, tooltips</div></div></div>
200
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#242424"></div><div class="color-swatch-info"><div class="color-swatch-name">border</div><div class="color-swatch-hex">#242424</div><div class="color-swatch-role">Borders, input borders, dividers</div></div></div>
201
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#2e2e2e"></div><div class="color-swatch-info"><div class="color-swatch-name">muted-hover</div><div class="color-swatch-hex">#2e2e2e</div><div class="color-swatch-role">Hover on muted surfaces</div></div></div>
202
+ </div>
203
+
204
+ <div class="color-group-label">Core Text</div>
205
+ <div class="color-grid">
206
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#fafafa"></div><div class="color-swatch-info"><div class="color-swatch-name">foreground</div><div class="color-swatch-hex">#fafafa</div><div class="color-swatch-role">Primary text, headings</div></div></div>
207
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#8c8c8c"></div><div class="color-swatch-info"><div class="color-swatch-name">muted-foreground</div><div class="color-swatch-hex">#8c8c8c</div><div class="color-swatch-role">Secondary text, labels, placeholders</div></div></div>
208
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#ffffff;border-bottom:1px solid hsl(0 0% 14%)"></div><div class="color-swatch-info"><div class="color-swatch-name">primary</div><div class="color-swatch-hex">#ffffff</div><div class="color-swatch-role">Maximum emphasis, button bg</div></div></div>
209
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#000000"></div><div class="color-swatch-info"><div class="color-swatch-name">primary-foreground</div><div class="color-swatch-hex">#000000</div><div class="color-swatch-role">Text on white buttons</div></div></div>
210
+ </div>
211
+
212
+ <div class="color-group-label">Semantic / Status</div>
213
+ <div class="color-grid">
214
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#22c55e"></div><div class="color-swatch-info"><div class="color-swatch-name">success</div><div class="color-swatch-hex">#22c55e</div><div class="color-swatch-role">Success states, running</div></div></div>
215
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#86efac"></div><div class="color-swatch-info"><div class="color-swatch-name">success-foreground</div><div class="color-swatch-hex">#86efac</div><div class="color-swatch-role">Success text on dark</div></div></div>
216
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#f59e0b"></div><div class="color-swatch-info"><div class="color-swatch-name">warning</div><div class="color-swatch-hex">#f59e0b</div><div class="color-swatch-role">Warning, caution badges</div></div></div>
217
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#3b82f6"></div><div class="color-swatch-info"><div class="color-swatch-name">info</div><div class="color-swatch-hex">#3b82f6</div><div class="color-swatch-role">Informational, links</div></div></div>
218
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#dc2626"></div><div class="color-swatch-info"><div class="color-swatch-name">destructive</div><div class="color-swatch-hex">#dc2626</div><div class="color-swatch-role">Error, danger, delete</div></div></div>
219
+ <div class="color-swatch"><div class="color-swatch-block" style="background:#cccccc"></div><div class="color-swatch-info"><div class="color-swatch-name">ring</div><div class="color-swatch-hex">#cccccc</div><div class="color-swatch-role">Focus rings (1px, keyboard-only)</div></div></div>
220
+ </div>
221
+
222
+ <div class="color-group-label">Surface Scale (5% &rarr; 18% lightness)</div>
223
+ <div style="display:flex;border-radius:10px;overflow:hidden;height:64px;border:1px solid var(--border);margin-bottom:24px">
224
+ <div style="flex:1;background:#0d0d0d" title="5% — background"></div>
225
+ <div style="flex:1;background:#121212" title="7% — card"></div>
226
+ <div style="flex:1;background:#141414" title="8% — secondary"></div>
227
+ <div style="flex:1;background:#1f1f1f" title="12% — muted"></div>
228
+ <div style="flex:1;background:#242424" title="14% — border"></div>
229
+ <div style="flex:1;background:#2e2e2e" title="18% — muted-hover"></div>
230
+ </div>
231
+ <div style="display:flex;justify-content:space-between;font-family:var(--font-mono);font-size:11px;color:var(--fg-muted);margin-bottom:8px">
232
+ <span>5%</span><span>7%</span><span>8%</span><span>12%</span><span>14%</span><span>18%</span>
233
+ </div>
234
+ </section>
235
+
236
+ <hr class="section-divider">
237
+
238
+ <!-- ==================== TYPOGRAPHY ==================== -->
239
+ <section class="section" id="typography">
240
+ <div class="section-label">02 / Typography</div>
241
+ <h2 class="section-title">Typography Scale</h2>
242
+
243
+ <div class="type-sample"><div style="font-size:30px;font-weight:600;line-height:1.2;letter-spacing:-0.5px">Hero Heading (text-3xl)</div><div class="type-meta">30px / 600 / 1.2 / -0.5px / Inter</div></div>
244
+ <div class="type-sample"><div style="font-size:24px;font-weight:600;line-height:1.25;letter-spacing:-0.3px">Page Heading (text-2xl)</div><div class="type-meta">24px / 600 / 1.25 / -0.3px / Inter</div></div>
245
+ <div class="type-sample"><div style="font-size:20px;font-weight:600;line-height:1.3">Sub-heading (text-xl)</div><div class="type-meta">20px / 600 / 1.3 / Inter</div></div>
246
+ <div class="type-sample"><div style="font-size:18px;font-weight:600;line-height:1.4">Section Title (text-lg)</div><div class="type-meta">18px / 600 / 1.4 / Inter</div></div>
247
+ <div class="type-sample"><div style="font-size:16px;font-weight:400;line-height:1.5">Body Large — Larger body text for chat messages and hero content. (text-base)</div><div class="type-meta">16px / 400 / 1.5 / Inter</div></div>
248
+ <div class="type-sample"><div style="font-size:14px;font-weight:400;line-height:1.5">Body — Standard UI text for labels, descriptions, and interface elements. (text-sm)</div><div class="type-meta">14px / 400 / 1.5 / Inter — primary body size (711 uses)</div></div>
249
+ <div class="type-sample"><div style="font-size:14px;font-weight:500;line-height:1.5">Label — Form labels, nav items, and badges. (text-sm font-medium)</div><div class="type-meta">14px / 500 / 1.5 / Inter — label weight (304 uses)</div></div>
250
+ <div class="type-sample"><div style="font-size:12px;font-weight:400;line-height:1.5;color:var(--fg-muted)">Secondary — Metadata, captions, and small labels. (text-xs)</div><div class="type-meta">12px / 400 / 1.5 / Inter — secondary size (427 uses)</div></div>
251
+ <div class="type-sample"><div style="font-family:var(--font-mono);font-size:14px;font-weight:400;line-height:1.6">const design = await openHands.init({ tokens: true });</div><div class="type-meta">14px / 400 / 1.6 / JetBrains Mono — code / technical text</div></div>
252
+ <div class="type-sample"><div style="font-size:11px;font-weight:500;line-height:1.27;text-transform:uppercase;letter-spacing:1.5px;color:var(--fg-muted)">SYSTEM CATEGORY</div><div class="type-meta">11px / 500 / uppercase / tracking-wide — section labels</div></div>
253
+ </section>
254
+
255
+ <hr class="section-divider">
256
+
257
+ <!-- ==================== BUTTONS ==================== -->
258
+ <section class="section" id="buttons">
259
+ <div class="section-label">03 / Buttons</div>
260
+ <h2 class="section-title">Button Variants</h2>
261
+ <div class="button-row">
262
+ <div class="button-item"><a class="btn-dark" href="#">Save Changes</a><div class="button-label">default</div></div>
263
+ <div class="button-item"><a class="btn-destructive" href="#">Delete</a><div class="button-label">destructive</div></div>
264
+ <div class="button-item"><a class="btn-outline" href="#">Cancel</a><div class="button-label">outline</div></div>
265
+ <div class="button-item"><a class="btn-primary" href="#">Settings</a><div class="button-label">secondary</div></div>
266
+ <div class="button-item"><a class="btn-muted" href="#">Archive</a><div class="button-label">muted</div></div>
267
+ <div class="button-item"><a class="btn-ghost" href="#">Learn More</a><div class="button-label">ghost</div></div>
268
+ <div class="button-item"><a href="#" style="font-size:14px;color:var(--primary);text-decoration:none;text-underline-offset:4px" onmouseover="this.style.textDecoration='underline'" onmouseout="this.style.textDecoration='none'">View docs</a><div class="button-label">link</div></div>
269
+ </div>
270
+
271
+ <div style="margin-top:40px">
272
+ <div class="color-group-label">Status Pills</div>
273
+ <div class="button-row">
274
+ <div class="button-item"><span style="display:inline-block;background:hsl(142 71% 45% / 0.1);color:var(--success-fg);padding:3px 10px;border-radius:9999px;font-size:12px;font-weight:500">Success</span><div class="button-label">success</div></div>
275
+ <div class="button-item"><span style="display:inline-block;background:hsl(38 92% 50% / 0.15);color:var(--warning);padding:3px 10px;border-radius:9999px;font-size:12px;font-weight:500">Warning</span><div class="button-label">warning</div></div>
276
+ <div class="button-item"><span style="display:inline-block;background:hsl(217 91% 60% / 0.15);color:var(--info);padding:3px 10px;border-radius:9999px;font-size:12px;font-weight:500">Info</span><div class="button-label">info</div></div>
277
+ <div class="button-item"><span style="display:inline-block;background:hsl(0 72% 51% / 0.1);color:var(--destructive);padding:3px 10px;border-radius:9999px;font-size:12px;font-weight:500">Error</span><div class="button-label">destructive</div></div>
278
+ </div>
279
+ </div>
280
+ </section>
281
+
282
+ <hr class="section-divider">
283
+
284
+ <!-- ==================== CARDS ==================== -->
285
+ <section class="section" id="cards">
286
+ <div class="section-label">04 / Cards</div>
287
+ <h2 class="section-title">Card Examples</h2>
288
+ <div class="card-grid">
289
+ <div class="card">
290
+ <div class="card-badge" style="background:hsl(142 71% 45% / 0.1);color:var(--success-fg)">Standard</div>
291
+ <h3>Standard Card</h3>
292
+ <p>bg-card border border-border rounded-lg p-4. The workhorse container for settings panels, content sections, and list items.</p>
293
+ </div>
294
+ <div class="card" style="box-shadow:var(--shadow-card);border-radius:12px;padding:24px">
295
+ <div class="card-badge" style="background:hsl(217 91% 60% / 0.15);color:var(--info)">Elevated</div>
296
+ <h3>Elevated Card</h3>
297
+ <p>bg-card border border-border rounded-xl p-6 shadow-lg. For modals, dialogs, and featured content that needs to float above the surface.</p>
298
+ </div>
299
+ <div class="card" style="border-color:var(--border-hover)">
300
+ <div class="card-badge" style="background:hsl(38 92% 50% / 0.15);color:var(--warning)">Interactive</div>
301
+ <h3>Interactive Card</h3>
302
+ <p>hover:border-white/30. Cards that respond to hover with a subtle border brightening to indicate they are clickable.</p>
303
+ </div>
304
+ </div>
305
+ </section>
306
+
307
+ <hr class="section-divider">
308
+
309
+ <!-- ==================== FORMS ==================== -->
310
+ <section class="section" id="forms">
311
+ <div class="section-label">05 / Forms</div>
312
+ <h2 class="section-title">Form Elements</h2>
313
+ <div class="form-group"><label class="form-label">Project Name</label><input class="form-input" type="text" placeholder="my-openhands-project"><div class="form-state-label">Default (border-border, bg-muted/40)</div></div>
314
+ <div class="form-group"><label class="form-label">Repository</label><input class="form-input form-input--focus" type="text" value="openhands/agent"><div class="form-state-label">Focus (ring-1, ring-ring, bg-muted/60)</div></div>
315
+ <div class="form-group"><label class="form-label">API Key</label><input class="form-input form-input--error" type="text" value="invalid-key-123"><div class="form-state-label">Error (border-destructive)</div></div>
316
+ <div class="form-group"><label class="form-label">Instructions</label><textarea class="form-textarea" placeholder="Describe the task for the agent..."></textarea></div>
317
+ <div class="form-group">
318
+ <label class="form-label">Framework</label>
319
+ <div style="position:relative">
320
+ <select class="form-input" style="appearance:none;padding-right:36px;cursor:pointer">
321
+ <option>React + Tailwind</option>
322
+ <option>Next.js</option>
323
+ <option>Vue</option>
324
+ </select>
325
+ <svg style="position:absolute;right:12px;top:50%;transform:translateY(-50%);pointer-events:none" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m6 9 6 6 6-6"/></svg>
326
+ </div>
327
+ <div class="form-state-label">NativeSelect (appearance: none, chevron overlay)</div>
328
+ </div>
329
+ </section>
330
+
331
+ <hr class="section-divider">
332
+
333
+ <!-- ==================== SPACING ==================== -->
334
+ <section class="section" id="spacing">
335
+ <div class="section-label">06 / Spacing</div>
336
+ <h2 class="section-title">Spacing Scale</h2>
337
+ <div class="spacing-row">
338
+ <div class="spacing-item"><div class="spacing-block" style="width:4px"></div><div class="spacing-value">4 (gap-1)</div></div>
339
+ <div class="spacing-item"><div class="spacing-block" style="width:6px"></div><div class="spacing-value">6 (gap-1.5)</div></div>
340
+ <div class="spacing-item"><div class="spacing-block" style="width:8px"></div><div class="spacing-value">8 (gap-2)</div></div>
341
+ <div class="spacing-item"><div class="spacing-block" style="width:12px"></div><div class="spacing-value">12 (gap-3)</div></div>
342
+ <div class="spacing-item"><div class="spacing-block" style="width:16px"></div><div class="spacing-value">16 (gap-4)</div></div>
343
+ <div class="spacing-item"><div class="spacing-block" style="width:24px"></div><div class="spacing-value">24 (gap-6)</div></div>
344
+ <div class="spacing-item"><div class="spacing-block" style="width:32px"></div><div class="spacing-value">32 (gap-8)</div></div>
345
+ <div class="spacing-item"><div class="spacing-block" style="width:48px"></div><div class="spacing-value">48 (gap-12)</div></div>
346
+ </div>
347
+
348
+ <div style="margin-top:40px">
349
+ <div class="color-group-label">Padding Patterns</div>
350
+ <div style="display:flex;flex-wrap:wrap;gap:16px;margin-top:12px">
351
+ <div style="background:var(--card);border:1px solid var(--border);border-radius:6px;padding:8px 12px;font-size:12px;color:var(--fg-muted)">px-3 py-2 <span style="color:var(--fg)">compact</span></div>
352
+ <div style="background:var(--card);border:1px solid var(--border);border-radius:6px;padding:8px 16px;font-size:12px;color:var(--fg-muted)">px-4 py-2 <span style="color:var(--fg)">standard</span></div>
353
+ <div style="background:var(--card);border:1px solid var(--border);border-radius:6px;padding:16px;font-size:12px;color:var(--fg-muted)">p-4 <span style="color:var(--fg)">card</span></div>
354
+ <div style="background:var(--card);border:1px solid var(--border);border-radius:6px;padding:24px;font-size:12px;color:var(--fg-muted)">p-6 <span style="color:var(--fg)">dialog</span></div>
355
+ </div>
356
+ </div>
357
+ </section>
358
+
359
+ <hr class="section-divider">
360
+
361
+ <!-- ==================== RADIUS ==================== -->
362
+ <section class="section" id="radius">
363
+ <div class="section-label">07 / Radius</div>
364
+ <h2 class="section-title">Border Radius Scale</h2>
365
+ <div class="radius-row">
366
+ <div class="radius-item"><div class="radius-box" style="border-radius:2px"></div><div class="radius-label">2px</div><div class="radius-context">rounded-sm</div></div>
367
+ <div class="radius-item"><div class="radius-box" style="border-radius:4px"></div><div class="radius-label">4px</div><div class="radius-context">rounded-md</div></div>
368
+ <div class="radius-item"><div class="radius-box" style="border-radius:6px"></div><div class="radius-label">6px</div><div class="radius-context">rounded-lg</div></div>
369
+ <div class="radius-item"><div class="radius-box" style="border-radius:12px"></div><div class="radius-label">12px</div><div class="radius-context">rounded-modal</div></div>
370
+ <div class="radius-item"><div class="radius-box" style="border-radius:16px"></div><div class="radius-label">16px</div><div class="radius-context">rounded-2xl</div></div>
371
+ <div class="radius-item"><div class="radius-box" style="border-radius:9999px"></div><div class="radius-label">9999px</div><div class="radius-context">rounded-full</div></div>
372
+ </div>
373
+ </section>
374
+
375
+ <hr class="section-divider">
376
+
377
+ <!-- ==================== ELEVATION ==================== -->
378
+ <section class="section" id="elevation">
379
+ <div class="section-label">08 / Elevation</div>
380
+ <h2 class="section-title">Elevation &amp; Depth</h2>
381
+ <div class="elevation-grid">
382
+ <div class="elevation-card" style="border:1px solid var(--border)"><div class="elevation-label">Level 0: Flat</div><div class="elevation-desc">No shadow, bg-background</div></div>
383
+ <div class="elevation-card" style="border:1px solid var(--border);box-shadow:0 1px 2px 0 hsl(0 0% 0% / 0.3)"><div class="elevation-label">Level 1: Surface</div><div class="elevation-desc">shadow-card + border</div></div>
384
+ <div class="elevation-card" style="border:1px solid var(--border);box-shadow:0 4px 6px -1px hsl(0 0% 0% / 0.3),0 2px 4px -2px hsl(0 0% 0% / 0.3)"><div class="elevation-label">Level 2: Raised</div><div class="elevation-desc">shadow-md — dropdowns, popovers</div></div>
385
+ <div class="elevation-card" style="border:1px solid var(--border);box-shadow:0 10px 15px -3px hsl(0 0% 0% / 0.3),0 4px 6px -4px hsl(0 0% 0% / 0.3)"><div class="elevation-label">Level 3: Floating</div><div class="elevation-desc">shadow-lg — modals, dialogs</div></div>
386
+ <div class="elevation-card" style="border:1px solid var(--border);box-shadow:0 20px 25px -5px hsl(0 0% 0% / 0.3),0 8px 10px -6px hsl(0 0% 0% / 0.3)"><div class="elevation-label">Level 4: Overlay</div><div class="elevation-desc">shadow-xl — full-screen overlays</div></div>
387
+ <div class="elevation-card" style="border:1px solid var(--border);box-shadow:0 0 0 1px var(--ring),0 0 0 3px var(--bg)"><div class="elevation-label">Focus Ring</div><div class="elevation-desc">ring-1 ring-ring ring-offset-2</div></div>
388
+ </div>
389
+ </section>
390
+
391
+ <footer class="footer">
392
+ <a href="https://github.com/FraterCCCLXIII/OpenHands-Design.md" target="_blank" rel="noopener noreferrer">OpenHands-Design.md</a> &mdash; Design tokens for the OpenHands UI
393
+ </footer>
394
+
395
+ </body>
396
+ </html>
OpenHands-Design/src/components/ui/button.tsx ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as React from 'react';
2
+ import { Slot } from '@radix-ui/react-slot';
3
+ import { cva, type VariantProps } from 'class-variance-authority';
4
+
5
+ import { cn } from '../../lib/utils';
6
+
7
+ const buttonVariants = cva(
8
+ 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-normal ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.97] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: 'bg-primary text-primary-foreground hover:bg-primary/85',
13
+ destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/85',
14
+ outline: 'border border-input bg-background hover:bg-muted hover:text-foreground',
15
+ light: 'border border-input bg-primary text-primary-foreground hover:bg-primary/85',
16
+ secondary: 'bg-secondary text-secondary-foreground hover:bg-muted-hover',
17
+ muted: 'bg-muted text-muted-foreground hover:bg-muted-hover hover:text-foreground',
18
+ ghost: 'hover:bg-muted hover:text-foreground',
19
+ link: 'text-primary underline-offset-4 hover:underline',
20
+ },
21
+ size: {
22
+ default: 'h-10 px-4 py-2',
23
+ sm: 'h-10 rounded-md px-3',
24
+ xs: 'h-10 rounded-md px-3 text-xs',
25
+ lg: 'h-10 rounded-md px-8',
26
+ icon: 'h-10 w-10',
27
+ },
28
+ },
29
+ defaultVariants: {
30
+ variant: 'default',
31
+ size: 'default',
32
+ },
33
+ }
34
+ );
35
+
36
+ export interface ButtonProps
37
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
38
+ VariantProps<typeof buttonVariants> {
39
+ asChild?: boolean;
40
+ }
41
+
42
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
43
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
44
+ const Comp = asChild ? Slot : 'button';
45
+ return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;
46
+ }
47
+ );
48
+ Button.displayName = 'Button';
49
+
50
+ export { Button, buttonVariants };
OpenHands-Design/src/components/ui/input.tsx ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as React from 'react';
2
+
3
+ import { cn } from '../../lib/utils';
4
+
5
+ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
6
+ ({ className, type, ...props }, ref) => {
7
+ return (
8
+ <input
9
+ type={type}
10
+ className={cn(
11
+ 'flex h-10 w-full rounded-md border border-border bg-muted/40 px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:bg-muted/60 hover:bg-muted/60 disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-muted/30 md:text-sm',
12
+ className
13
+ )}
14
+ ref={ref}
15
+ {...props}
16
+ />
17
+ );
18
+ }
19
+ );
20
+ Input.displayName = 'Input';
21
+
22
+ export { Input };
OpenHands-Design/src/components/ui/native-select.tsx ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as React from 'react';
2
+ import { ChevronDown } from 'lucide-react';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ const nativeSelectClassName =
7
+ 'h-10 w-full appearance-none rounded-md border border-border bg-muted/40 py-2 pl-3 pr-10 text-sm text-foreground ring-offset-background hover:bg-muted/60 focus-visible:bg-muted/60 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:bg-muted/30 disabled:opacity-50';
8
+
9
+ export type NativeSelectProps = React.ComponentPropsWithoutRef<'select'> & {
10
+ wrapperClassName?: string;
11
+ };
12
+
13
+ export const NativeSelect = React.forwardRef<HTMLSelectElement, NativeSelectProps>(
14
+ ({ className, wrapperClassName, children, ...props }, ref) => (
15
+ <div className={cn('relative w-full', wrapperClassName)}>
16
+ <select ref={ref} className={cn(nativeSelectClassName, className)} {...props}>
17
+ {children}
18
+ </select>
19
+ <ChevronDown
20
+ className="pointer-events-none absolute right-3 top-1/2 h-5 w-5 -translate-y-1/2 text-muted-foreground"
21
+ aria-hidden
22
+ />
23
+ </div>
24
+ )
25
+ );
26
+ NativeSelect.displayName = 'NativeSelect';
OpenHands-Design/src/components/ui/search-input.tsx ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as React from 'react';
2
+ import { Search, XCircle } from 'lucide-react';
3
+ import { Input } from './input';
4
+ import { cn } from '../../lib/utils';
5
+
6
+ type InputProps = React.ComponentProps<typeof Input>;
7
+ export type SearchInputProps = Omit<InputProps, 'type' | 'size'> & {
8
+ value: string;
9
+ onValueChange: (value: string) => void;
10
+ /** Size: sm (h-9), default (h-10), lg (h-11) */
11
+ size?: 'sm' | 'default' | 'lg';
12
+ };
13
+
14
+ const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(
15
+ (
16
+ {
17
+ value,
18
+ onValueChange,
19
+ placeholder,
20
+ 'aria-label': ariaLabel,
21
+ className,
22
+ size = 'default',
23
+ ...props
24
+ },
25
+ ref
26
+ ) => {
27
+ const sizeClasses = {
28
+ sm: 'h-9 pl-9 pr-9',
29
+ default: 'h-10 pl-10 pr-10',
30
+ lg: 'h-11 pl-11 pr-11 text-base',
31
+ };
32
+ const iconSizes = {
33
+ sm: 'h-4 w-4',
34
+ default: 'h-4 w-4',
35
+ lg: 'h-5 w-5',
36
+ };
37
+ const hasValue = value.length > 0;
38
+
39
+ return (
40
+ <div className={cn('relative w-full', className)}>
41
+ <Search
42
+ className={cn(
43
+ 'absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground pointer-events-none',
44
+ iconSizes[size]
45
+ )}
46
+ aria-hidden
47
+ />
48
+ <Input
49
+ ref={ref}
50
+ type="search"
51
+ value={value}
52
+ onChange={(e) => onValueChange(e.target.value)}
53
+ placeholder={placeholder}
54
+ aria-label={ariaLabel}
55
+ className={cn(sizeClasses[size])}
56
+ {...props}
57
+ />
58
+ {hasValue && (
59
+ <button
60
+ type="button"
61
+ onClick={() => onValueChange('')}
62
+ className="absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1 text-muted-foreground hover:bg-muted hover:text-foreground focus:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2"
63
+ aria-label="Clear search"
64
+ >
65
+ <XCircle className={cn(iconSizes[size])} strokeWidth={2} />
66
+ </button>
67
+ )}
68
+ </div>
69
+ );
70
+ }
71
+ );
72
+ SearchInput.displayName = 'SearchInput';
73
+
74
+ export { SearchInput };
OpenHands-Design/src/globals.css ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Inter:wght@400;500;600;700&display=swap');
2
+ @tailwind base;
3
+ @tailwind components;
4
+ @tailwind utilities;
5
+
6
+ @layer base {
7
+ :root {
8
+ --background: 0 0% 5%;
9
+ --modal-background: var(--background);
10
+ --foreground: 0 0% 98%;
11
+
12
+ --card: 0 0% 7%;
13
+ --card-foreground: 0 0% 98%;
14
+
15
+ --popover: 0 0% 7%;
16
+ --popover-foreground: 0 0% 98%;
17
+
18
+ --primary: 0 0% 100%;
19
+ --primary-foreground: 0 0% 0%;
20
+
21
+ --secondary: 0 0% 8%;
22
+ --secondary-foreground: 0 0% 98%;
23
+
24
+ --muted: 0 0% 12%;
25
+ --muted-foreground: 0 0% 55%;
26
+ --muted-hover: 0 0% 18%;
27
+
28
+ --accent: 0 0% 100%;
29
+ --accent-foreground: 0 0% 0%;
30
+
31
+ --destructive: 0 72% 51%;
32
+ --destructive-foreground: 0 0% 98%;
33
+
34
+ --border: 0 0% 14%;
35
+ --input: 0 0% 14%;
36
+ --ring: 0 0% 80%;
37
+
38
+ --radius: 0.375rem;
39
+ --radius-sm: 0.25rem;
40
+ --radius-modal: 0.75rem;
41
+
42
+ --success: 142 71% 45%;
43
+ --success-foreground: 142 71% 76%;
44
+ --warning: 38 92% 50%;
45
+ --info: 217 91% 60%;
46
+ --gradient-card-hover: linear-gradient(180deg, hsl(0 0% 9%) 0%, hsl(0 0% 7%) 100%);
47
+
48
+ --shadow-card: 0 1px 2px 0 hsl(0 0% 0% / 0.3);
49
+
50
+ --font-sans: 'Inter', system-ui, sans-serif;
51
+ --font-mono: 'JetBrains Mono', monospace;
52
+
53
+ --sidebar-background: 0 0% 5%;
54
+ --sidebar-foreground: 0 0% 98%;
55
+ --sidebar-primary: 0 0% 100%;
56
+ --sidebar-primary-foreground: 0 0% 0%;
57
+ --sidebar-accent: 0 0% 8%;
58
+ --sidebar-accent-foreground: 0 0% 98%;
59
+ --sidebar-border: 0 0% 14%;
60
+ --sidebar-ring: 0 0% 50%;
61
+ }
62
+
63
+ .dark {
64
+ --background: 0 0% 5%;
65
+ --modal-background: var(--background);
66
+ --foreground: 0 0% 98%;
67
+
68
+ --card: 0 0% 7%;
69
+ --card-foreground: 0 0% 98%;
70
+
71
+ --popover: 0 0% 7%;
72
+ --popover-foreground: 0 0% 98%;
73
+
74
+ --primary: 0 0% 100%;
75
+ --primary-foreground: 0 0% 0%;
76
+
77
+ --secondary: 0 0% 8%;
78
+ --secondary-foreground: 0 0% 98%;
79
+
80
+ --muted: 0 0% 12%;
81
+ --muted-foreground: 0 0% 55%;
82
+ --muted-hover: 0 0% 18%;
83
+
84
+ --accent: 0 0% 100%;
85
+ --accent-foreground: 0 0% 0%;
86
+
87
+ --destructive: 0 72% 51%;
88
+ --destructive-foreground: 0 0% 98%;
89
+
90
+ --border: 0 0% 14%;
91
+ --input: 0 0% 14%;
92
+ --ring: 0 0% 80%;
93
+
94
+ --radius: 0.375rem;
95
+ --radius-sm: 0.25rem;
96
+ --radius-modal: 0.75rem;
97
+
98
+ --success: 142 71% 45%;
99
+ --success-foreground: 142 71% 76%;
100
+ --warning: 38 92% 50%;
101
+ --info: 217 91% 60%;
102
+ --gradient-card-hover: linear-gradient(180deg, hsl(0 0% 9%) 0%, hsl(0 0% 7%) 100%);
103
+
104
+ --shadow-card: 0 1px 2px 0 hsl(0 0% 0% / 0.3);
105
+
106
+ --font-sans: 'Inter', system-ui, sans-serif;
107
+ --font-mono: 'JetBrains Mono', monospace;
108
+
109
+ --sidebar-background: 0 0% 5%;
110
+ --sidebar-foreground: 0 0% 98%;
111
+ --sidebar-primary: 0 0% 100%;
112
+ --sidebar-primary-foreground: 0 0% 0%;
113
+ --sidebar-accent: 0 0% 8%;
114
+ --sidebar-accent-foreground: 0 0% 98%;
115
+ --sidebar-border: 0 0% 14%;
116
+ --sidebar-ring: 0 0% 50%;
117
+ }
118
+ }
119
+
120
+ /* Strip native search chrome so focus ring matches all other inputs */
121
+ input[type="search"] {
122
+ -webkit-appearance: none;
123
+ appearance: none;
124
+ }
125
+ input[type="search"]::-webkit-search-cancel-button {
126
+ -webkit-appearance: none;
127
+ appearance: none;
128
+ display: none;
129
+ }
130
+ input[type="search"]::-webkit-search-decoration,
131
+ input[type="search"]::-webkit-search-results-button,
132
+ input[type="search"]::-webkit-search-results-decoration {
133
+ -webkit-appearance: none;
134
+ appearance: none;
135
+ }
OpenHands-Design/tailwind.config.js ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ darkMode: ["class"],
4
+ content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
5
+ theme: {
6
+ container: {
7
+ center: true,
8
+ padding: "2rem",
9
+ screens: {
10
+ "2xl": "1400px",
11
+ },
12
+ },
13
+ extend: {
14
+ fontFamily: {
15
+ sans: ["Inter", "system-ui", "sans-serif"],
16
+ mono: ["JetBrains Mono", "monospace"],
17
+ },
18
+ colors: {
19
+ border: "hsl(var(--border))",
20
+ input: "hsl(var(--input))",
21
+ ring: "hsl(var(--ring))",
22
+ background: "hsl(var(--background))",
23
+ modal: "hsl(var(--modal-background))",
24
+ foreground: "hsl(var(--foreground))",
25
+ primary: {
26
+ DEFAULT: "hsl(var(--primary))",
27
+ foreground: "hsl(var(--primary-foreground))",
28
+ },
29
+ secondary: {
30
+ DEFAULT: "hsl(var(--secondary))",
31
+ foreground: "hsl(var(--secondary-foreground))",
32
+ },
33
+ destructive: {
34
+ DEFAULT: "hsl(var(--destructive) / <alpha-value>)",
35
+ foreground: "hsl(var(--destructive-foreground) / <alpha-value>)",
36
+ },
37
+ muted: {
38
+ DEFAULT: "hsl(var(--muted))",
39
+ foreground: "hsl(var(--muted-foreground))",
40
+ hover: "hsl(var(--muted-hover))",
41
+ },
42
+ accent: {
43
+ DEFAULT: "hsl(var(--accent))",
44
+ foreground: "hsl(var(--accent-foreground))",
45
+ },
46
+ popover: {
47
+ DEFAULT: "hsl(var(--popover))",
48
+ foreground: "hsl(var(--popover-foreground))",
49
+ },
50
+ card: {
51
+ DEFAULT: "hsl(var(--card))",
52
+ foreground: "hsl(var(--card-foreground))",
53
+ },
54
+ sidebar: {
55
+ DEFAULT: "hsl(var(--sidebar-background))",
56
+ foreground: "hsl(var(--sidebar-foreground))",
57
+ primary: "hsl(var(--sidebar-primary))",
58
+ "primary-foreground": "hsl(var(--sidebar-primary-foreground))",
59
+ accent: "hsl(var(--sidebar-accent))",
60
+ "accent-foreground": "hsl(var(--sidebar-accent-foreground))",
61
+ border: "hsl(var(--sidebar-border))",
62
+ ring: "hsl(var(--sidebar-ring))",
63
+ },
64
+ success: {
65
+ DEFAULT: "hsl(var(--success) / <alpha-value>)",
66
+ foreground: "hsl(var(--success-foreground) / <alpha-value>)",
67
+ },
68
+ warning: "hsl(var(--warning) / <alpha-value>)",
69
+ info: "hsl(var(--info) / <alpha-value>)",
70
+ },
71
+ borderRadius: {
72
+ modal: "var(--radius-modal)",
73
+ lg: "var(--radius)",
74
+ md: "calc(var(--radius) - 2px)",
75
+ sm: "calc(var(--radius) - 4px)",
76
+ },
77
+ keyframes: {
78
+ "accordion-down": {
79
+ from: { height: "0" },
80
+ to: { height: "var(--radix-accordion-content-height)" },
81
+ },
82
+ "accordion-up": {
83
+ from: { height: "var(--radix-accordion-content-height)" },
84
+ to: { height: "0" },
85
+ },
86
+ "pulse-glow": {
87
+ "0%, 100%": { opacity: "1" },
88
+ "50%": { opacity: "0.5" },
89
+ },
90
+ },
91
+ animation: {
92
+ "accordion-down": "accordion-down 0.2s ease-out",
93
+ "accordion-up": "accordion-up 0.2s ease-out",
94
+ "pulse-glow": "pulse-glow 2s ease-in-out infinite",
95
+ },
96
+ },
97
+ },
98
+ plugins: [require("tailwindcss-animate")],
99
+ };
assets/openhands-logotype-design.svg ADDED
assets/openhands-logotype-on-dark.svg ADDED
assets/openhands-logotype-on-light.svg ADDED