@whykusanagi/corrupted-theme 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +253 -0
- package/README.md +97 -7
- package/docs/CAPABILITIES.md +209 -0
- package/docs/CHARACTER_LEVEL_CORRUPTION.md +264 -0
- package/docs/COMPONENTS_REFERENCE.md +295 -8
- package/docs/CORRUPTION_PHRASES.md +529 -0
- package/docs/FUTURE_WORK.md +189 -0
- package/docs/IMPLEMENTATION_VALIDATION.md +401 -0
- package/docs/LLM_PROVIDERS.md +345 -0
- package/docs/PERSONALITY.md +128 -0
- package/docs/ROADMAP.md +266 -0
- package/docs/ROUTING.md +324 -0
- package/docs/STYLE_GUIDE.md +605 -0
- package/docs/brand/BRAND_OVERVIEW.md +413 -0
- package/docs/brand/COLOR_SYSTEM.md +583 -0
- package/docs/brand/DESIGN_TOKENS.md +1009 -0
- package/docs/brand/TRANSLATION_FAILURE_AESTHETIC.md +525 -0
- package/docs/brand/TYPOGRAPHY.md +624 -0
- package/docs/components/ANIMATION_GUIDELINES.md +901 -0
- package/docs/components/COMPONENT_LIBRARY.md +1061 -0
- package/docs/components/GLASSMORPHISM.md +602 -0
- package/docs/components/INTERACTIVE_STATES.md +766 -0
- package/docs/governance/CONTRIBUTION_GUIDELINES.md +593 -0
- package/docs/governance/DESIGN_SYSTEM_GOVERNANCE.md +451 -0
- package/docs/governance/VERSION_MANAGEMENT.md +447 -0
- package/docs/governance/VERSION_REFERENCES.md +229 -0
- package/docs/platforms/CLI_IMPLEMENTATION.md +1025 -0
- package/docs/platforms/COMPONENT_MAPPING.md +579 -0
- package/docs/platforms/NPM_PACKAGE.md +854 -0
- package/docs/platforms/WEB_IMPLEMENTATION.md +1221 -0
- package/docs/standards/ACCESSIBILITY.md +715 -0
- package/docs/standards/ANTI_PATTERNS.md +554 -0
- package/docs/standards/SPACING_SYSTEM.md +549 -0
- package/examples/assets/celeste-avatar.png +0 -0
- package/examples/button.html +22 -10
- package/examples/card.html +22 -9
- package/examples/extensions-showcase.html +716 -0
- package/examples/form.html +22 -9
- package/examples/index.html +619 -396
- package/examples/layout.html +22 -8
- package/examples/nikke-team-builder.html +23 -9
- package/examples/showcase-complete.html +884 -28
- package/examples/showcase.html +21 -8
- package/package.json +14 -5
- package/src/css/components.css +676 -0
- package/src/css/extensions.css +933 -0
- package/src/css/theme.css +6 -74
- package/src/css/typography.css +5 -0
- package/src/lib/character-corruption.js +563 -0
- package/src/lib/components.js +283 -0
- package/src/lib/countdown-widget.js +609 -0
- package/src/lib/gallery.js +481 -0
|
@@ -0,0 +1,766 @@
|
|
|
1
|
+
# Celeste Brand System - Interactive States
|
|
2
|
+
|
|
3
|
+
**Version**: 1.0.0
|
|
4
|
+
**Last Updated**: 2025-12-13
|
|
5
|
+
**Status**: 🟠 **HIGH PRIORITY DOCUMENT**
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Interactive states provide **visual feedback** for user interactions across all components. Consistent state styling creates predictable, accessible user experiences.
|
|
12
|
+
|
|
13
|
+
**Core principle**: Every interactive element must have distinct visual states for hover, focus, active, and disabled.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## State Hierarchy
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
Component Lifecycle
|
|
21
|
+
├── Default (Resting) # No interaction
|
|
22
|
+
├── Hover (Mouse over) # Pointer over element
|
|
23
|
+
├── Focus (Keyboard selected) # Tab/click focus
|
|
24
|
+
├── Active (Pressed) # Mouse down / touch
|
|
25
|
+
├── Disabled (Inactive) # Cannot interact
|
|
26
|
+
└── Loading (Processing) # Async operation
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Universal State Patterns
|
|
32
|
+
|
|
33
|
+
### Default State (Resting)
|
|
34
|
+
|
|
35
|
+
**Purpose**: Component at rest, no user interaction
|
|
36
|
+
|
|
37
|
+
**Visual characteristics**:
|
|
38
|
+
- **Border**: 30% opacity pink (`rgba(217, 79, 144, 0.3)`)
|
|
39
|
+
- **Background**: Base component background
|
|
40
|
+
- **Shadow**: Medium pink-tinted shadow
|
|
41
|
+
- **Cursor**: Appropriate for element type
|
|
42
|
+
|
|
43
|
+
**Example** (Button):
|
|
44
|
+
```css
|
|
45
|
+
.btn {
|
|
46
|
+
background: var(--color-accent-primary);
|
|
47
|
+
border: 1px solid rgba(217, 79, 144, 0.3);
|
|
48
|
+
box-shadow: 0 2px 8px rgba(217, 79, 144, 0.15);
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
transition: all 0.3s ease;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### Hover State (Mouse Over)
|
|
57
|
+
|
|
58
|
+
**Purpose**: Indicates element is interactive and ready to receive click/tap
|
|
59
|
+
|
|
60
|
+
**Visual changes from default**:
|
|
61
|
+
- **Border**: Brighter (50% opacity)
|
|
62
|
+
- **Background**: Lighter/brighter variant
|
|
63
|
+
- **Shadow**: Add glow effect
|
|
64
|
+
- **Transform**: Subtle lift (`translateY(-2px)`) for cards
|
|
65
|
+
- **Cursor**: `pointer` (if not already)
|
|
66
|
+
|
|
67
|
+
**Timing**: `0.3s ease` transition (standard)
|
|
68
|
+
|
|
69
|
+
**Example** (Button):
|
|
70
|
+
```css
|
|
71
|
+
.btn:hover {
|
|
72
|
+
background: var(--color-accent-light); /* Lighter pink */
|
|
73
|
+
border-color: rgba(217, 79, 144, 0.5); /* Brighter border */
|
|
74
|
+
box-shadow:
|
|
75
|
+
0 2px 8px rgba(217, 79, 144, 0.15), /* Original shadow */
|
|
76
|
+
0 0 20px rgba(217, 79, 144, 0.4); /* Add glow */
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Example** (Glass Card):
|
|
81
|
+
```css
|
|
82
|
+
.glass-card:hover {
|
|
83
|
+
background: rgba(28, 18, 48, 0.5); /* Lighter glass */
|
|
84
|
+
border-color: rgba(217, 79, 144, 0.5);
|
|
85
|
+
transform: translateY(-2px); /* Lift effect */
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### Focus State (Keyboard Navigation)
|
|
92
|
+
|
|
93
|
+
**Purpose**: Indicates element has keyboard focus (Tab key)
|
|
94
|
+
|
|
95
|
+
**Visual characteristics**:
|
|
96
|
+
- **Outline**: 2px solid pink, 2px offset
|
|
97
|
+
- **Border**: Brighter (70% opacity)
|
|
98
|
+
- **Background**: Slightly lighter than default
|
|
99
|
+
- **Shadow**: Enhanced (not glowing)
|
|
100
|
+
|
|
101
|
+
**Accessibility requirement**: Focus indicator MUST be visible (WCAG 2.4.7)
|
|
102
|
+
|
|
103
|
+
**Example** (Button):
|
|
104
|
+
```css
|
|
105
|
+
.btn:focus-visible {
|
|
106
|
+
outline: 2px solid rgba(217, 79, 144, 0.7);
|
|
107
|
+
outline-offset: 2px;
|
|
108
|
+
border-color: rgba(217, 79, 144, 0.7);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Example** (Input):
|
|
113
|
+
```css
|
|
114
|
+
.glass-input:focus {
|
|
115
|
+
background: rgba(20, 12, 40, 0.8); /* More opaque */
|
|
116
|
+
border-color: rgba(217, 79, 144, 0.7);
|
|
117
|
+
outline: 2px solid rgba(217, 79, 144, 0.5);
|
|
118
|
+
outline-offset: 2px;
|
|
119
|
+
box-shadow: 0 0 0 3px rgba(217, 79, 144, 0.1); /* Focus ring */
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Note**: Use `:focus-visible` for buttons (hides outline on click), use `:focus` for inputs (always show outline)
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### Active State (Pressed)
|
|
128
|
+
|
|
129
|
+
**Purpose**: Immediate visual feedback when clicking/pressing
|
|
130
|
+
|
|
131
|
+
**Visual characteristics**:
|
|
132
|
+
- **Border**: Brightest (90% opacity)
|
|
133
|
+
- **Background**: Darker variant (for buttons) or darker glass (for cards)
|
|
134
|
+
- **Shadow**: Reduced (closer to surface)
|
|
135
|
+
- **Transform**: `scale(0.98)` (subtle shrink)
|
|
136
|
+
|
|
137
|
+
**Timing**: `0.15s ease` (faster than hover for immediate feedback)
|
|
138
|
+
|
|
139
|
+
**Example** (Button):
|
|
140
|
+
```css
|
|
141
|
+
.btn:active {
|
|
142
|
+
background: var(--color-accent-dark); /* Darker pink */
|
|
143
|
+
border-color: rgba(217, 79, 144, 0.9);
|
|
144
|
+
box-shadow: 0 1px 4px rgba(217, 79, 144, 0.2); /* Smaller shadow */
|
|
145
|
+
transform: scale(0.98); /* Shrink */
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Example** (Glass Card):
|
|
150
|
+
```css
|
|
151
|
+
.glass-card:active {
|
|
152
|
+
background: rgba(12, 8, 28, 0.8); /* Darker glass */
|
|
153
|
+
border-color: rgba(217, 79, 144, 0.9);
|
|
154
|
+
transform: scale(0.99);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### Disabled State (Inactive)
|
|
161
|
+
|
|
162
|
+
**Purpose**: Indicates element cannot be interacted with
|
|
163
|
+
|
|
164
|
+
**Visual characteristics**:
|
|
165
|
+
- **Opacity**: 50% (entire element)
|
|
166
|
+
- **Cursor**: `not-allowed`
|
|
167
|
+
- **Border**: Muted (10-20% opacity)
|
|
168
|
+
- **No transitions**: Disable hover/focus/active
|
|
169
|
+
- **Color**: Text uses `--color-text-disabled` (30% opacity white)
|
|
170
|
+
|
|
171
|
+
**Accessibility**: Add `aria-disabled="true"` or `disabled` attribute
|
|
172
|
+
|
|
173
|
+
**Example** (Button):
|
|
174
|
+
```css
|
|
175
|
+
.btn:disabled,
|
|
176
|
+
.btn.disabled {
|
|
177
|
+
opacity: 0.5;
|
|
178
|
+
cursor: not-allowed;
|
|
179
|
+
pointer-events: none; /* Disable all interactions */
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Example** (Input):
|
|
184
|
+
```css
|
|
185
|
+
.glass-input:disabled {
|
|
186
|
+
opacity: 0.5;
|
|
187
|
+
cursor: not-allowed;
|
|
188
|
+
background: rgba(20, 12, 40, 0.4); /* Less opaque */
|
|
189
|
+
color: var(--color-text-disabled);
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### Loading State (Processing)
|
|
196
|
+
|
|
197
|
+
**Purpose**: Indicates async operation in progress
|
|
198
|
+
|
|
199
|
+
**Visual characteristics**:
|
|
200
|
+
- **Cursor**: `wait` or `progress`
|
|
201
|
+
- **Content**: Replace with spinner or loading text
|
|
202
|
+
- **Disable interaction**: Add `pointer-events: none`
|
|
203
|
+
- **Optional**: Pulse animation
|
|
204
|
+
|
|
205
|
+
**Example** (Button):
|
|
206
|
+
```html
|
|
207
|
+
<button class="btn" data-loading="true">
|
|
208
|
+
<span class="spinner"></span>
|
|
209
|
+
Loading...
|
|
210
|
+
</button>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```css
|
|
214
|
+
.btn[data-loading="true"] {
|
|
215
|
+
cursor: wait;
|
|
216
|
+
pointer-events: none;
|
|
217
|
+
opacity: 0.8;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.btn[data-loading="true"]::before {
|
|
221
|
+
content: '';
|
|
222
|
+
display: inline-block;
|
|
223
|
+
width: 16px;
|
|
224
|
+
height: 16px;
|
|
225
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
226
|
+
border-top-color: white;
|
|
227
|
+
border-radius: 50%;
|
|
228
|
+
animation: spin 1s linear infinite;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@keyframes spin {
|
|
232
|
+
to { transform: rotate(360deg); }
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
### Error State
|
|
239
|
+
|
|
240
|
+
**Purpose**: Indicates validation error or failed action
|
|
241
|
+
|
|
242
|
+
**Visual characteristics**:
|
|
243
|
+
- **Border**: Red (`#ff4757`) with 70% opacity
|
|
244
|
+
- **Background**: Red tint (optional)
|
|
245
|
+
- **Shake animation**: On error trigger
|
|
246
|
+
- **Error message**: Below element
|
|
247
|
+
|
|
248
|
+
**Example** (Input):
|
|
249
|
+
```css
|
|
250
|
+
.glass-input.error {
|
|
251
|
+
border-color: rgba(255, 71, 87, 0.7);
|
|
252
|
+
box-shadow: 0 0 0 3px rgba(255, 71, 87, 0.1);
|
|
253
|
+
animation: shake 0.3s ease;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
@keyframes shake {
|
|
257
|
+
0%, 100% { transform: translateX(0); }
|
|
258
|
+
25% { transform: translateX(-8px); }
|
|
259
|
+
75% { transform: translateX(8px); }
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Error Message**:
|
|
264
|
+
```html
|
|
265
|
+
<input class="glass-input error" type="email">
|
|
266
|
+
<p class="error-message">Invalid email address</p>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
```css
|
|
270
|
+
.error-message {
|
|
271
|
+
color: var(--color-error);
|
|
272
|
+
font-size: 0.875rem;
|
|
273
|
+
margin-top: 0.25rem;
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
### Success State
|
|
280
|
+
|
|
281
|
+
**Purpose**: Indicates successful action or valid input
|
|
282
|
+
|
|
283
|
+
**Visual characteristics**:
|
|
284
|
+
- **Border**: Green (`#2ed573`) with 70% opacity
|
|
285
|
+
- **Background**: Green tint (optional)
|
|
286
|
+
- **Check icon**: Animated checkmark
|
|
287
|
+
- **Success message**: Below element
|
|
288
|
+
|
|
289
|
+
**Example** (Input):
|
|
290
|
+
```css
|
|
291
|
+
.glass-input.success {
|
|
292
|
+
border-color: rgba(46, 213, 115, 0.7);
|
|
293
|
+
box-shadow: 0 0 0 3px rgba(46, 213, 115, 0.1);
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**Success Message**:
|
|
298
|
+
```html
|
|
299
|
+
<input class="glass-input success" type="email">
|
|
300
|
+
<p class="success-message">✓ Valid email address</p>
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
```css
|
|
304
|
+
.success-message {
|
|
305
|
+
color: var(--color-success);
|
|
306
|
+
font-size: 0.875rem;
|
|
307
|
+
margin-top: 0.25rem;
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Component-Specific State Patterns
|
|
314
|
+
|
|
315
|
+
### Buttons
|
|
316
|
+
|
|
317
|
+
| State | Border Opacity | Background | Shadow | Transform |
|
|
318
|
+
|-------|---------------|------------|--------|-----------|
|
|
319
|
+
| Default | 30% | Accent primary | Small | none |
|
|
320
|
+
| Hover | 50% | Accent light | Medium + glow | none |
|
|
321
|
+
| Focus | 70% | Accent primary | Small | none |
|
|
322
|
+
| Active | 90% | Accent dark | Tiny | scale(0.98) |
|
|
323
|
+
| Disabled | 10% | Accent primary (50% opacity) | none | none |
|
|
324
|
+
|
|
325
|
+
**Transition timing**: `0.3s ease` (except active: `0.15s ease`)
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
### Cards
|
|
330
|
+
|
|
331
|
+
| State | Glass Opacity | Border Opacity | Shadow | Transform |
|
|
332
|
+
|-------|--------------|---------------|--------|-----------|
|
|
333
|
+
| Default | 70% | 30% | Medium | none |
|
|
334
|
+
| Hover | 50% | 50% | Medium + glow | translateY(-2px) |
|
|
335
|
+
| Focus | 70% | 70% | Medium | none |
|
|
336
|
+
| Active | 80% | 90% | Large | scale(0.99) |
|
|
337
|
+
|
|
338
|
+
**Transition timing**: `0.3s ease`
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
### Inputs
|
|
343
|
+
|
|
344
|
+
| State | Glass Opacity | Border Opacity | Outline | Placeholder |
|
|
345
|
+
|-------|--------------|---------------|---------|-------------|
|
|
346
|
+
| Default | 60% | 30% | none | 50% opacity |
|
|
347
|
+
| Hover | 60% | 50% | none | 50% opacity |
|
|
348
|
+
| Focus | 80% | 70% | 2px solid (50% opacity) | hidden |
|
|
349
|
+
| Disabled | 40% | 10% | none | 30% opacity |
|
|
350
|
+
| Error | 60% | 70% (red) | 3px (red tint) | 50% opacity |
|
|
351
|
+
| Success | 60% | 70% (green) | 3px (green tint) | 50% opacity |
|
|
352
|
+
|
|
353
|
+
**Transition timing**: `0.3s ease`
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
### Dropdowns
|
|
358
|
+
|
|
359
|
+
| State | Background | Border | Menu Visibility | Arrow |
|
|
360
|
+
|-------|-----------|--------|----------------|-------|
|
|
361
|
+
| Closed | Default | 30% | hidden | ▼ |
|
|
362
|
+
| Hover | Lighter | 50% | hidden | ▼ |
|
|
363
|
+
| Open | Lighter | 70% | visible | ▲ |
|
|
364
|
+
| Focus | Default | 70% | hidden | ▼ |
|
|
365
|
+
|
|
366
|
+
**Menu animation**: `slide-down` (0.3s ease)
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
### Badges
|
|
371
|
+
|
|
372
|
+
**No interactive states** (static elements)
|
|
373
|
+
- Badges are informational only
|
|
374
|
+
- If clickable, treat as buttons with badge styling
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
### Alerts
|
|
379
|
+
|
|
380
|
+
**Dismissible alerts only**:
|
|
381
|
+
- **Close button**: Standard button states
|
|
382
|
+
- **Alert container**: Static (no hover/focus)
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## CLI Interactive States
|
|
387
|
+
|
|
388
|
+
Terminals have **limited visual feedback** options. Use these patterns:
|
|
389
|
+
|
|
390
|
+
### Hover (CLI Equivalent)
|
|
391
|
+
|
|
392
|
+
**Pattern**: Highlighted menu option
|
|
393
|
+
```
|
|
394
|
+
Option 1
|
|
395
|
+
> Option 2 ← Pink highlight + arrow
|
|
396
|
+
Option 3
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**Implementation**:
|
|
400
|
+
```go
|
|
401
|
+
style := lipgloss.NewStyle().
|
|
402
|
+
Foreground(lipgloss.Color("#d94f90")).
|
|
403
|
+
Bold(true)
|
|
404
|
+
|
|
405
|
+
if isSelected {
|
|
406
|
+
return "> " + style.Render(option)
|
|
407
|
+
}
|
|
408
|
+
return " " + option
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
### Focus (CLI Equivalent)
|
|
414
|
+
|
|
415
|
+
**Pattern**: Selection indicator
|
|
416
|
+
```
|
|
417
|
+
[•] Option 1 ← Selected
|
|
418
|
+
[ ] Option 2
|
|
419
|
+
[ ] Option 3
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**Implementation**:
|
|
423
|
+
```go
|
|
424
|
+
if isSelected {
|
|
425
|
+
return "[•] " + option
|
|
426
|
+
}
|
|
427
|
+
return "[ ] " + option
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
### Active (CLI Equivalent)
|
|
433
|
+
|
|
434
|
+
**Pattern**: Executing state with corruption
|
|
435
|
+
```
|
|
436
|
+
⟨ 処理 processing purosesu... ⟩
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Implementation**:
|
|
440
|
+
```go
|
|
441
|
+
spinner := "⟨ " + corruptedPhrase + " ⟩"
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
### Disabled (CLI Equivalent)
|
|
447
|
+
|
|
448
|
+
**Pattern**: Dimmed text
|
|
449
|
+
```
|
|
450
|
+
Option 1
|
|
451
|
+
Option 2 (unavailable) ← Dimmed
|
|
452
|
+
Option 3
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**Implementation**:
|
|
456
|
+
```go
|
|
457
|
+
style := lipgloss.NewStyle().
|
|
458
|
+
Foreground(lipgloss.Color("240")) // ANSI gray
|
|
459
|
+
|
|
460
|
+
if isDisabled {
|
|
461
|
+
return style.Render(option + " (unavailable)")
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
### Loading (CLI Equivalent)
|
|
468
|
+
|
|
469
|
+
**Pattern**: Animated spinner
|
|
470
|
+
```
|
|
471
|
+
◐ Loading...
|
|
472
|
+
◓ Loading...
|
|
473
|
+
◑ Loading...
|
|
474
|
+
◒ Loading...
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**Implementation**:
|
|
478
|
+
```go
|
|
479
|
+
frames := []string{"◐", "◓", "◑", "◒"}
|
|
480
|
+
spinner := frames[frame % len(frames)]
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
### Error (CLI Equivalent)
|
|
486
|
+
|
|
487
|
+
**Pattern**: Red text with emoji
|
|
488
|
+
```
|
|
489
|
+
🔴 Error: Failed to connect
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
**Implementation**:
|
|
493
|
+
```go
|
|
494
|
+
style := lipgloss.NewStyle().
|
|
495
|
+
Foreground(lipgloss.Color("#ff4757"))
|
|
496
|
+
|
|
497
|
+
return "🔴 " + style.Render("Error: " + message)
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
### Success (CLI Equivalent)
|
|
503
|
+
|
|
504
|
+
**Pattern**: Green text with emoji
|
|
505
|
+
```
|
|
506
|
+
🟢 Success: Connected
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
**Implementation**:
|
|
510
|
+
```go
|
|
511
|
+
style := lipgloss.NewStyle().
|
|
512
|
+
Foreground(lipgloss.Color("#2ed573"))
|
|
513
|
+
|
|
514
|
+
return "🟢 " + style.Render("Success: " + message)
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## Transition Timing
|
|
520
|
+
|
|
521
|
+
### Standard Transitions
|
|
522
|
+
|
|
523
|
+
```css
|
|
524
|
+
/* Default: 0.3s ease */
|
|
525
|
+
transition: all 0.3s ease;
|
|
526
|
+
|
|
527
|
+
/* Fast: 0.15s ease (active states) */
|
|
528
|
+
transition: all 0.15s ease;
|
|
529
|
+
|
|
530
|
+
/* Slow: 0.5s ease (page transitions) */
|
|
531
|
+
transition: all 0.5s ease;
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Property-Specific Timing
|
|
535
|
+
|
|
536
|
+
```css
|
|
537
|
+
.btn {
|
|
538
|
+
/* Different timing for different properties */
|
|
539
|
+
transition:
|
|
540
|
+
background 0.3s ease,
|
|
541
|
+
border-color 0.3s ease,
|
|
542
|
+
box-shadow 0.3s ease,
|
|
543
|
+
transform 0.15s ease; /* Faster transform */
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### Easing Functions
|
|
548
|
+
|
|
549
|
+
```css
|
|
550
|
+
/* Default: ease-in-out (smooth start and end) */
|
|
551
|
+
transition: all 0.3s ease-in-out;
|
|
552
|
+
|
|
553
|
+
/* Bounce: Custom cubic-bezier (overshoots then settles) */
|
|
554
|
+
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
555
|
+
|
|
556
|
+
/* Sharp: ease-out (fast start, slow end) */
|
|
557
|
+
transition: all 0.3s ease-out;
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
---
|
|
561
|
+
|
|
562
|
+
## Accessibility Requirements
|
|
563
|
+
|
|
564
|
+
### WCAG 2.4.7 - Focus Visible
|
|
565
|
+
|
|
566
|
+
**Requirement**: Focus indicator MUST be visible
|
|
567
|
+
|
|
568
|
+
✅ **Good**:
|
|
569
|
+
```css
|
|
570
|
+
.btn:focus-visible {
|
|
571
|
+
outline: 2px solid rgba(217, 79, 144, 0.7);
|
|
572
|
+
outline-offset: 2px;
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
❌ **Bad**:
|
|
577
|
+
```css
|
|
578
|
+
.btn:focus {
|
|
579
|
+
outline: none; /* ❌ Removes focus indicator */
|
|
580
|
+
}
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
### WCAG 2.5.5 - Target Size
|
|
586
|
+
|
|
587
|
+
**Requirement**: Interactive elements minimum 44×44px
|
|
588
|
+
|
|
589
|
+
✅ **Good**:
|
|
590
|
+
```css
|
|
591
|
+
.btn {
|
|
592
|
+
padding: 0.75rem 1.5rem; /* > 44px height */
|
|
593
|
+
min-width: 44px;
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
❌ **Bad**:
|
|
598
|
+
```css
|
|
599
|
+
.btn-sm {
|
|
600
|
+
padding: 0.25rem 0.5rem; /* < 44px height */
|
|
601
|
+
}
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
**Fix for small buttons**: Add larger touch target
|
|
605
|
+
```css
|
|
606
|
+
.btn-sm {
|
|
607
|
+
position: relative;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
.btn-sm::before {
|
|
611
|
+
content: '';
|
|
612
|
+
position: absolute;
|
|
613
|
+
inset: -8px; /* Expand touch area */
|
|
614
|
+
}
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
### WCAG 1.4.3 - Contrast
|
|
620
|
+
|
|
621
|
+
**Requirement**: Text contrast minimum 4.5:1
|
|
622
|
+
|
|
623
|
+
✅ **Good** (all Celeste states meet this):
|
|
624
|
+
- White text on pink: **4.9:1** ✓
|
|
625
|
+
- Pink on dark bg: **7.2:1** ✓
|
|
626
|
+
- Disabled text (30% opacity): **6.3:1** ✓
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
### Keyboard Navigation
|
|
631
|
+
|
|
632
|
+
**Requirement**: All interactive elements accessible via keyboard
|
|
633
|
+
|
|
634
|
+
✅ **Good**:
|
|
635
|
+
```html
|
|
636
|
+
<button class="btn">Click me</button>
|
|
637
|
+
<a href="#" class="btn">Link button</a>
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
❌ **Bad**:
|
|
641
|
+
```html
|
|
642
|
+
<div onclick="handleClick()">Click me</div> <!-- Not keyboard accessible -->
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
**Fix**: Add `tabindex` and keyboard handlers
|
|
646
|
+
```html
|
|
647
|
+
<div
|
|
648
|
+
class="btn"
|
|
649
|
+
role="button"
|
|
650
|
+
tabindex="0"
|
|
651
|
+
onclick="handleClick()"
|
|
652
|
+
onkeydown="if(event.key==='Enter') handleClick()">
|
|
653
|
+
Click me
|
|
654
|
+
</div>
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
## Animation Examples
|
|
660
|
+
|
|
661
|
+
### Hover Lift Effect
|
|
662
|
+
|
|
663
|
+
```css
|
|
664
|
+
.glass-card {
|
|
665
|
+
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.glass-card:hover {
|
|
669
|
+
transform: translateY(-4px);
|
|
670
|
+
box-shadow:
|
|
671
|
+
0 8px 32px rgba(217, 79, 144, 0.35),
|
|
672
|
+
0 0 20px rgba(217, 79, 144, 0.4);
|
|
673
|
+
}
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
### Button Press Feedback
|
|
679
|
+
|
|
680
|
+
```css
|
|
681
|
+
.btn {
|
|
682
|
+
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.btn:active {
|
|
686
|
+
transform: scale(0.96);
|
|
687
|
+
box-shadow: 0 1px 4px rgba(217, 79, 144, 0.2);
|
|
688
|
+
}
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
### Input Focus Glow
|
|
694
|
+
|
|
695
|
+
```css
|
|
696
|
+
.glass-input {
|
|
697
|
+
transition: all 0.3s ease;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
.glass-input:focus {
|
|
701
|
+
box-shadow:
|
|
702
|
+
0 0 0 3px rgba(217, 79, 144, 0.1),
|
|
703
|
+
0 4px 16px rgba(217, 79, 144, 0.25);
|
|
704
|
+
}
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
---
|
|
708
|
+
|
|
709
|
+
### Shake on Error
|
|
710
|
+
|
|
711
|
+
```css
|
|
712
|
+
.glass-input.error {
|
|
713
|
+
animation: shake 0.3s ease;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
@keyframes shake {
|
|
717
|
+
0%, 100% { transform: translateX(0); }
|
|
718
|
+
10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); }
|
|
719
|
+
20%, 40%, 60%, 80% { transform: translateX(4px); }
|
|
720
|
+
}
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
---
|
|
724
|
+
|
|
725
|
+
## Design Token Reference
|
|
726
|
+
|
|
727
|
+
From `DESIGN_TOKENS.md`:
|
|
728
|
+
|
|
729
|
+
```json
|
|
730
|
+
{
|
|
731
|
+
"animation": {
|
|
732
|
+
"timing": {
|
|
733
|
+
"fast": { "$value": "0.15s" },
|
|
734
|
+
"normal": { "$value": "0.3s" },
|
|
735
|
+
"slow": { "$value": "0.5s" }
|
|
736
|
+
},
|
|
737
|
+
"easing": {
|
|
738
|
+
"default": { "$value": "ease-in-out" },
|
|
739
|
+
"bounce": { "$value": "cubic-bezier(0.34, 1.56, 0.64, 1)" }
|
|
740
|
+
}
|
|
741
|
+
},
|
|
742
|
+
"opacity": {
|
|
743
|
+
"disabled": { "$value": "0.5" },
|
|
744
|
+
"placeholder": { "$value": "0.5" },
|
|
745
|
+
"border": {
|
|
746
|
+
"default": { "$value": "0.3" },
|
|
747
|
+
"hover": { "$value": "0.5" },
|
|
748
|
+
"focus": { "$value": "0.7" },
|
|
749
|
+
"active": { "$value": "0.9" }
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
---
|
|
756
|
+
|
|
757
|
+
## Related Documents
|
|
758
|
+
|
|
759
|
+
- **ANIMATION_GUIDELINES.md** - Detailed timing and easing specifications
|
|
760
|
+
- **GLASSMORPHISM.md** - Glass effect state transitions
|
|
761
|
+
- **COLOR_SYSTEM.md** - State color variants
|
|
762
|
+
- **ACCESSIBILITY.md** - Complete WCAG compliance guide
|
|
763
|
+
|
|
764
|
+
---
|
|
765
|
+
|
|
766
|
+
**Status**: ✅ **INTERACTIVE STATES COMPLETE** - Ready for implementation
|