picasso-skill 1.5.1 → 2.0.0
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/agents/picasso.md +14 -2
- package/checklists/pre-ship.md +83 -0
- package/commands/backlog.md +34 -0
- package/commands/variants.md +18 -0
- package/package.json +3 -1
- package/references/accessibility-wcag.md +245 -0
- package/references/anti-patterns.md +184 -0
- package/references/color-and-contrast.md +477 -0
- package/references/component-patterns.md +113 -0
- package/references/conversion-design.md +193 -0
- package/references/data-visualization.md +226 -0
- package/references/depth-and-elevation.md +211 -0
- package/references/design-system.md +176 -0
- package/references/generative-art.md +648 -0
- package/references/interaction-design.md +162 -0
- package/references/modern-css-performance.md +361 -0
- package/references/motion-and-animation.md +267 -0
- package/references/performance-optimization.md +746 -0
- package/references/react-patterns.md +318 -0
- package/references/responsive-design.md +452 -0
- package/references/sensory-design.md +369 -0
- package/references/spatial-design.md +176 -0
- package/references/style-presets.md +502 -0
- package/references/tools-catalog.md +103 -0
- package/references/typography.md +415 -0
- package/references/ux-psychology.md +235 -0
- package/references/ux-writing.md +513 -0
- package/skills/picasso/SKILL.md +58 -2
- package/skills/picasso/references/animation-performance.md +244 -0
- package/skills/picasso/references/brand-and-identity.md +136 -0
- package/skills/picasso/references/code-typography.md +222 -0
- package/skills/picasso/references/color-and-contrast.md +56 -2
- package/skills/picasso/references/dark-mode.md +199 -0
- package/skills/picasso/references/depth-and-elevation.md +211 -0
- package/skills/picasso/references/i18n-visual-patterns.md +177 -0
- package/skills/picasso/references/images-and-media.md +222 -0
- package/skills/picasso/references/loading-and-states.md +258 -0
- package/skills/picasso/references/micro-interactions.md +291 -0
- package/skills/picasso/references/motion-and-animation.md +9 -2
- package/skills/picasso/references/navigation-patterns.md +247 -0
- package/skills/picasso/references/style-presets.md +1 -1
- package/skills/picasso/references/tables-and-forms.md +227 -0
- package/skills/picasso/references/tools-catalog.md +103 -0
- package/skills/picasso/references/typography.md +45 -2
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# Tables and Forms Reference
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
1. Sortable Tables
|
|
5
|
+
2. Responsive Tables
|
|
6
|
+
3. Inline Editing
|
|
7
|
+
4. Multi-Select Patterns
|
|
8
|
+
5. Form Validation
|
|
9
|
+
6. Multi-Step Forms
|
|
10
|
+
7. Complex Inputs
|
|
11
|
+
8. Common Mistakes
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 1. Sortable Tables
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<table>
|
|
19
|
+
<thead>
|
|
20
|
+
<tr>
|
|
21
|
+
<th aria-sort="ascending">
|
|
22
|
+
<button>Name <span aria-hidden="true">↑</span></button>
|
|
23
|
+
</th>
|
|
24
|
+
<th aria-sort="none">
|
|
25
|
+
<button>Date <span aria-hidden="true">↕</span></button>
|
|
26
|
+
</th>
|
|
27
|
+
</tr>
|
|
28
|
+
</thead>
|
|
29
|
+
</table>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- Use `aria-sort` on `<th>`: `ascending`, `descending`, or `none`.
|
|
33
|
+
- Sort icon: `↑` ascending, `↓` descending, `↕` unsorted. Use `aria-hidden="true"` on the icon.
|
|
34
|
+
- Sortable headers must be `<button>` inside `<th>`, not clickable `<th>`.
|
|
35
|
+
- Default sort: most recent first for dates, alphabetical for names.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 2. Responsive Tables
|
|
40
|
+
|
|
41
|
+
**Option A: Horizontal scroll** (preferred for data tables)
|
|
42
|
+
|
|
43
|
+
```css
|
|
44
|
+
.table-container {
|
|
45
|
+
overflow-x: auto;
|
|
46
|
+
-webkit-overflow-scrolling: touch;
|
|
47
|
+
border: 1px solid var(--border);
|
|
48
|
+
border-radius: 8px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* Fade edge to hint scrollability */
|
|
52
|
+
.table-container::after {
|
|
53
|
+
content: '';
|
|
54
|
+
position: absolute;
|
|
55
|
+
right: 0;
|
|
56
|
+
top: 0;
|
|
57
|
+
bottom: 0;
|
|
58
|
+
width: 40px;
|
|
59
|
+
background: linear-gradient(to left, var(--surface-1), transparent);
|
|
60
|
+
pointer-events: none;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Option B: Stacked cards** (for simple tables on mobile)
|
|
65
|
+
|
|
66
|
+
```css
|
|
67
|
+
@media (max-width: 640px) {
|
|
68
|
+
table, thead, tbody, th, td, tr { display: block; }
|
|
69
|
+
thead { display: none; }
|
|
70
|
+
td { padding: 8px 16px; text-align: right; }
|
|
71
|
+
td::before {
|
|
72
|
+
content: attr(data-label);
|
|
73
|
+
float: left;
|
|
74
|
+
font-weight: 600;
|
|
75
|
+
color: var(--text-secondary);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 3. Inline Editing
|
|
83
|
+
|
|
84
|
+
Click to edit pattern: display text, click reveals input, blur/Enter saves.
|
|
85
|
+
|
|
86
|
+
```jsx
|
|
87
|
+
function EditableCell({ value, onSave }) {
|
|
88
|
+
const [editing, setEditing] = useState(false);
|
|
89
|
+
const [draft, setDraft] = useState(value);
|
|
90
|
+
|
|
91
|
+
if (!editing) return (
|
|
92
|
+
<span onClick={() => setEditing(true)} className="cursor-text hover:bg-surface-2 px-2 py-1 rounded">
|
|
93
|
+
{value}
|
|
94
|
+
</span>
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<input
|
|
99
|
+
value={draft}
|
|
100
|
+
onChange={e => setDraft(e.target.value)}
|
|
101
|
+
onBlur={() => { onSave(draft); setEditing(false); }}
|
|
102
|
+
onKeyDown={e => { if (e.key === 'Enter') { onSave(draft); setEditing(false); } if (e.key === 'Escape') setEditing(false); }}
|
|
103
|
+
autoFocus
|
|
104
|
+
className="input-base w-full"
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Show a subtle pencil icon on row hover. Use `opacity-0 group-hover:opacity-100` pattern.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 4. Multi-Select Patterns
|
|
115
|
+
|
|
116
|
+
- **Checkbox column**: leftmost column, always visible.
|
|
117
|
+
- **Shift-click range select**: select from last checked to current.
|
|
118
|
+
- **Select all**: checkbox in header, toggles all visible (filtered) rows.
|
|
119
|
+
- **Bulk action bar**: appears when 1+ rows selected. Shows count + actions.
|
|
120
|
+
|
|
121
|
+
```jsx
|
|
122
|
+
<div className={`fixed bottom-4 left-1/2 -translate-x-1/2 bg-surface-2 rounded-xl px-4 py-2
|
|
123
|
+
flex items-center gap-4 shadow-lg border border-border transition-transform
|
|
124
|
+
${selectedCount > 0 ? 'translate-y-0' : 'translate-y-[200%]'}`}>
|
|
125
|
+
<span className="text-sm font-medium">{selectedCount} selected</span>
|
|
126
|
+
<button className="btn-ghost text-sm">Export</button>
|
|
127
|
+
<button className="btn-ghost text-sm text-red">Delete</button>
|
|
128
|
+
</div>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 5. Form Validation
|
|
134
|
+
|
|
135
|
+
**When to validate:**
|
|
136
|
+
|
|
137
|
+
| Trigger | Use For |
|
|
138
|
+
|---|---|
|
|
139
|
+
| On blur | Email format, required fields, min/max length |
|
|
140
|
+
| On submit | All fields, server-side checks |
|
|
141
|
+
| Real-time (on change) | Password strength, username availability |
|
|
142
|
+
| Never on keystroke | Don't interrupt typing. Wait for blur or 500ms debounce. |
|
|
143
|
+
|
|
144
|
+
```jsx
|
|
145
|
+
<div className="space-y-1.5">
|
|
146
|
+
<label htmlFor="email" className="text-sm font-medium">Email</label>
|
|
147
|
+
<input
|
|
148
|
+
id="email"
|
|
149
|
+
type="email"
|
|
150
|
+
aria-invalid={error ? "true" : undefined}
|
|
151
|
+
aria-describedby={error ? "email-error" : undefined}
|
|
152
|
+
className={`input-base ${error ? 'border-red' : ''}`}
|
|
153
|
+
/>
|
|
154
|
+
{error && (
|
|
155
|
+
<p id="email-error" role="alert" className="text-xs text-red flex items-center gap-1">
|
|
156
|
+
<svg className="w-3.5 h-3.5" aria-hidden="true">...</svg>
|
|
157
|
+
{error}
|
|
158
|
+
</p>
|
|
159
|
+
)}
|
|
160
|
+
</div>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Error messages: specific and helpful. "Enter a valid email" not "Invalid input."
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 6. Multi-Step Forms
|
|
168
|
+
|
|
169
|
+
Show a progress indicator. Allow back navigation. Validate per step, not all at once.
|
|
170
|
+
|
|
171
|
+
```jsx
|
|
172
|
+
<div className="flex items-center gap-2 mb-8">
|
|
173
|
+
{steps.map((step, i) => (
|
|
174
|
+
<Fragment key={i}>
|
|
175
|
+
<div className={`flex items-center justify-center h-8 w-8 rounded-full text-sm font-bold
|
|
176
|
+
${i < currentStep ? 'bg-accent text-white' :
|
|
177
|
+
i === currentStep ? 'border-2 border-accent text-accent' :
|
|
178
|
+
'border border-border text-muted'}`}>
|
|
179
|
+
{i < currentStep ? '✓' : i + 1}
|
|
180
|
+
</div>
|
|
181
|
+
{i < steps.length - 1 && (
|
|
182
|
+
<div className={`flex-1 h-0.5 ${i < currentStep ? 'bg-accent' : 'bg-border'}`} />
|
|
183
|
+
)}
|
|
184
|
+
</Fragment>
|
|
185
|
+
))}
|
|
186
|
+
</div>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Rules:
|
|
190
|
+
- Save progress per step (don't lose data on back).
|
|
191
|
+
- Validate step before advancing (disable Next if invalid).
|
|
192
|
+
- Show step count: "Step 2 of 4".
|
|
193
|
+
- Allow clicking completed steps to go back.
|
|
194
|
+
- Final step: show summary before submit.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## 7. Complex Inputs
|
|
199
|
+
|
|
200
|
+
**Date pickers:** Use native `<input type="date">` first. Custom picker only if design requires it. Always allow manual text entry as fallback.
|
|
201
|
+
|
|
202
|
+
**File upload:** Show progress, preview (for images), allow removal.
|
|
203
|
+
|
|
204
|
+
```jsx
|
|
205
|
+
<label className="flex flex-col items-center gap-2 p-8 border-2 border-dashed border-border
|
|
206
|
+
rounded-xl cursor-pointer hover:border-accent hover:bg-accent/5 transition-colors">
|
|
207
|
+
<svg>...</svg>
|
|
208
|
+
<span className="text-sm text-secondary">Drop files or click to upload</span>
|
|
209
|
+
<input type="file" className="hidden" onChange={handleUpload} />
|
|
210
|
+
</label>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Address autocomplete:** Use Google Places API or similar. Show suggestions in a dropdown. Parse into structured fields (street, city, state, zip).
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 8. Common Mistakes
|
|
218
|
+
|
|
219
|
+
- **Sortable `<th>` without `<button>`.** Clicking a `<th>` isn't keyboard accessible.
|
|
220
|
+
- **No `aria-sort` on sortable columns.** Screen readers can't announce sort state.
|
|
221
|
+
- **Validating on every keystroke.** Annoying. Use blur or 500ms debounce.
|
|
222
|
+
- **Error messages without `role="alert"`.** Screen readers won't announce them.
|
|
223
|
+
- **Multi-step form losing data on back.** Save each step's state.
|
|
224
|
+
- **No horizontal scroll hint on tables.** Users don't know content is hidden. Add fade gradient.
|
|
225
|
+
- **Custom date picker without text input fallback.** Some users prefer typing dates.
|
|
226
|
+
- **Select all selecting ALL rows, not just filtered.** Only select what's visible.
|
|
227
|
+
- **Labels as placeholder text.** Labels must be visible above the input, always.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Tools & Libraries Catalog
|
|
2
|
+
|
|
3
|
+
Consolidated reference for animation libraries, design tools, and utilities. Quick lookup when generating or recommending tools.
|
|
4
|
+
|
|
5
|
+
## Animation Libraries
|
|
6
|
+
|
|
7
|
+
### React Bits (reactbits.dev)
|
|
8
|
+
126 animated React components. 37.5K GitHub stars.
|
|
9
|
+
- **Text (23):** Split Text, Blur Text, Shiny Text, Gradient Text, Glitch Text, Scrambled Text, Count Up, etc.
|
|
10
|
+
- **Animations (28):** Electric Border, Glare Hover, Magnet Lines, Click Spark, Pixel Trail, Meta Balls, etc.
|
|
11
|
+
- **Components (36):** Magic Bento, Fluid Glass, Tilted Card, Dock, Gooey Nav, Elastic Slider, etc.
|
|
12
|
+
- **Backgrounds (39):** Liquid Ether, Silk, Aurora, Plasma, Hyperspeed, Iridescence, Balatro, etc.
|
|
13
|
+
- **Tools:** Background Studio, Shape Magic, Texture Lab
|
|
14
|
+
|
|
15
|
+
### Animate UI (animate-ui.com)
|
|
16
|
+
shadcn-registry-based animation components built on Motion (Framer Motion).
|
|
17
|
+
- Animated primitives (ported from Radix UI, Base UI, Headless UI)
|
|
18
|
+
- Components with baseline styles inspired by shadcn/ui
|
|
19
|
+
- Animated Lucide icons
|
|
20
|
+
- Install: follows shadcn pattern (copy source, customize)
|
|
21
|
+
|
|
22
|
+
### Cursify (cursify.ui-layouts.com)
|
|
23
|
+
11 React cursor animation effects:
|
|
24
|
+
Fairydust, Smooth Following, Canvas, Bubble, Character, Snowflake, Rainbow, Follow, Spotlight, Springy, Neural Glow.
|
|
25
|
+
Best for: portfolio sites, creative agencies, landing pages (not productivity tools).
|
|
26
|
+
|
|
27
|
+
### Motion (formerly Framer Motion)
|
|
28
|
+
React animation library with gesture support, spring physics, layout animations.
|
|
29
|
+
Use for: complex choreography, gesture-driven interactions, shared layout transitions.
|
|
30
|
+
|
|
31
|
+
### Torph (npm torph)
|
|
32
|
+
Character-level text morph animations. Dependency-free. React, Vue, Svelte, vanilla TS.
|
|
33
|
+
|
|
34
|
+
## Visual Effects
|
|
35
|
+
|
|
36
|
+
### Radiant Shaders (radiant-shaders.com)
|
|
37
|
+
80+ production-ready WebGL/Canvas shaders. 0 dependencies, MIT license. Copy source, integrate, ship. Similar to shadcn's approach but for visual effects.
|
|
38
|
+
|
|
39
|
+
## Layout & Interaction
|
|
40
|
+
|
|
41
|
+
### Hit Area Utilities (bazza.dev)
|
|
42
|
+
Tailwind classes expanding clickable areas without affecting visual layout.
|
|
43
|
+
Install: `npx shadcn@latest add https://bazza.dev/r/hit-area`
|
|
44
|
+
Classes: `hit-area-6`, `hit-area-x-4`, `hit-area-l-8`, `hit-area-debug`
|
|
45
|
+
|
|
46
|
+
### WebHaptics (npm web-haptics)
|
|
47
|
+
Haptic feedback for mobile web. React, Vue, Svelte, TypeScript.
|
|
48
|
+
Patterns: success, warning, error, light, medium, heavy, soft, rigid, selection.
|
|
49
|
+
```jsx
|
|
50
|
+
import { useWebHaptics } from "web-haptics/react";
|
|
51
|
+
const { trigger } = useWebHaptics();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Pretext (@chenglou/pretext)
|
|
55
|
+
500x faster text measurement than DOM. Pure TypeScript, ~15KB.
|
|
56
|
+
Two-function API: `prepare()` (one-time) + `layout()` (hot path, pure arithmetic).
|
|
57
|
+
Universal: DOM, Canvas, SVG, WebGL, server-side. CJK, Arabic, Hebrew, Thai support.
|
|
58
|
+
|
|
59
|
+
## Design References
|
|
60
|
+
|
|
61
|
+
### Component Gallery (component.gallery)
|
|
62
|
+
60 interface components, 95 design systems, 2,676 examples.
|
|
63
|
+
Cross-reference the same component across 95+ design systems for naming conventions and patterns.
|
|
64
|
+
|
|
65
|
+
### Checklist Design (checklist.design)
|
|
66
|
+
56 design checklists:
|
|
67
|
+
- 13 page checklists (404, Login, Pricing, Sign Up, etc.)
|
|
68
|
+
- 24 component checklists (Button, Card, Modal, Table, Toast, etc.)
|
|
69
|
+
- 13 flow checklists (Adding to cart, Resetting password, etc.)
|
|
70
|
+
- 3 topic checklists (Responsiveness, Dark Mode, UX Copy)
|
|
71
|
+
- 3 brand checklists (Logo, Typography, Tone of Voice)
|
|
72
|
+
Also: Figma plugin for in-context checking.
|
|
73
|
+
|
|
74
|
+
## Design Tools
|
|
75
|
+
|
|
76
|
+
### Google Stitch (stitch.withgoogle.com)
|
|
77
|
+
AI design tool: text prompts -> high-fidelity UI designs with production code.
|
|
78
|
+
Features: AI canvas, voice interaction, DESIGN.md export, instant prototyping.
|
|
79
|
+
MCP server + SDK for coding agent integration. 350 free generations/month.
|
|
80
|
+
|
|
81
|
+
### Subframe (subframe.com)
|
|
82
|
+
Drag-and-drop visual editor connected to coding agents via MCP.
|
|
83
|
+
AI generates -> you visually refine -> clean code flows back.
|
|
84
|
+
|
|
85
|
+
### Variant (variant.com)
|
|
86
|
+
AI design generator with infinite scroll exploration. Enter idea, scroll for endless options.
|
|
87
|
+
|
|
88
|
+
## CSS & Font Tools
|
|
89
|
+
- **pyftsubset** / **glyphhanger** -- font subsetting
|
|
90
|
+
- **svgo** -- SVG optimization (`svgo --precision=1 --multipass`)
|
|
91
|
+
- **critical** (npm) / **critters** (webpack/vite) -- critical CSS extraction
|
|
92
|
+
|
|
93
|
+
## Sound & Haptics
|
|
94
|
+
- **soundcn** -- 700+ CC0 UI sounds
|
|
95
|
+
- **Kenney.nl** -- free CC0 UI sound packs
|
|
96
|
+
- **Freesound.org** -- CC0 filtered sounds
|
|
97
|
+
- **Tone.js** -- procedural runtime synthesis
|
|
98
|
+
|
|
99
|
+
## Utilities
|
|
100
|
+
- **facehash** -- deterministic avatar faces from any string (~3KB)
|
|
101
|
+
- **better-icons** -- 200K+ icons from 150+ icon sets
|
|
102
|
+
- **Lucide React** -- default icon library (tree-shakeable)
|
|
103
|
+
- **better-all** -- dependency-based parallel data fetching
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
7. Web Font Loading
|
|
11
11
|
8. Curated Font Pairings
|
|
12
12
|
9. Variable Fonts
|
|
13
|
-
10.
|
|
13
|
+
10. Dark Mode Font Weight
|
|
14
|
+
11. Metric-Matched Font Fallbacks
|
|
15
|
+
12. Common Mistakes
|
|
14
16
|
|
|
15
17
|
---
|
|
16
18
|
|
|
@@ -361,7 +363,46 @@ A single variable font file (typically 50-120KB for Latin subset) replaces 4-8 s
|
|
|
361
363
|
|
|
362
364
|
---
|
|
363
365
|
|
|
364
|
-
## 10.
|
|
366
|
+
## 10. Dark Mode Font Weight
|
|
367
|
+
|
|
368
|
+
Light text on a dark background appears optically heavier than the same weight on white. Compensate by reducing body font weight in dark mode:
|
|
369
|
+
|
|
370
|
+
```css
|
|
371
|
+
:root[data-theme="dark"] {
|
|
372
|
+
--body-weight: 350;
|
|
373
|
+
}
|
|
374
|
+
.body {
|
|
375
|
+
font-weight: var(--body-weight, 400);
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Also increase line-height by 0.05-0.1 for light-on-dark text to improve readability. This is a subtle refinement that separates polished dark themes from rushed ones.
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## 11. Metric-Matched Font Fallbacks (Eliminate CLS)
|
|
384
|
+
|
|
385
|
+
Custom fonts cause Cumulative Layout Shift when the fallback and custom font have different metrics. Fix this with `@font-face` override descriptors that match the fallback to the custom font:
|
|
386
|
+
|
|
387
|
+
```css
|
|
388
|
+
@font-face {
|
|
389
|
+
font-family: 'CustomFont-Fallback';
|
|
390
|
+
src: local('Arial');
|
|
391
|
+
size-adjust: 105%;
|
|
392
|
+
ascent-override: 90%;
|
|
393
|
+
descent-override: 20%;
|
|
394
|
+
line-gap-override: 10%;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/* Use in the font stack */
|
|
398
|
+
--font-body: 'Satoshi', 'CustomFont-Fallback', sans-serif;
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Measure your custom font's metrics against the fallback (tools like `fontpie` or the Chrome DevTools font panel help) and tune these four values. The result: zero layout shift on font load, even with `font-display: swap`.
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## 12. Common Mistakes
|
|
365
406
|
|
|
366
407
|
- Using more than 3 font families on a page
|
|
367
408
|
- Setting body text below 16px on desktop or 14px on mobile
|
|
@@ -370,3 +411,5 @@ A single variable font file (typically 50-120KB for Latin subset) replaces 4-8 s
|
|
|
370
411
|
- Centering long paragraphs (center alignment works for 1-2 lines maximum)
|
|
371
412
|
- Forgetting to set `max-width` on text blocks (ideal: 60-75 characters per line, roughly 600-750px)
|
|
372
413
|
- Using all caps for more than a few words without increasing letter-spacing
|
|
414
|
+
- Not adjusting font weight for dark mode (light-on-dark text appears heavier)
|
|
415
|
+
- Missing metric-matched fallbacks (causes CLS on font load)
|