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.
Files changed (44) hide show
  1. package/agents/picasso.md +14 -2
  2. package/checklists/pre-ship.md +83 -0
  3. package/commands/backlog.md +34 -0
  4. package/commands/variants.md +18 -0
  5. package/package.json +3 -1
  6. package/references/accessibility-wcag.md +245 -0
  7. package/references/anti-patterns.md +184 -0
  8. package/references/color-and-contrast.md +477 -0
  9. package/references/component-patterns.md +113 -0
  10. package/references/conversion-design.md +193 -0
  11. package/references/data-visualization.md +226 -0
  12. package/references/depth-and-elevation.md +211 -0
  13. package/references/design-system.md +176 -0
  14. package/references/generative-art.md +648 -0
  15. package/references/interaction-design.md +162 -0
  16. package/references/modern-css-performance.md +361 -0
  17. package/references/motion-and-animation.md +267 -0
  18. package/references/performance-optimization.md +746 -0
  19. package/references/react-patterns.md +318 -0
  20. package/references/responsive-design.md +452 -0
  21. package/references/sensory-design.md +369 -0
  22. package/references/spatial-design.md +176 -0
  23. package/references/style-presets.md +502 -0
  24. package/references/tools-catalog.md +103 -0
  25. package/references/typography.md +415 -0
  26. package/references/ux-psychology.md +235 -0
  27. package/references/ux-writing.md +513 -0
  28. package/skills/picasso/SKILL.md +58 -2
  29. package/skills/picasso/references/animation-performance.md +244 -0
  30. package/skills/picasso/references/brand-and-identity.md +136 -0
  31. package/skills/picasso/references/code-typography.md +222 -0
  32. package/skills/picasso/references/color-and-contrast.md +56 -2
  33. package/skills/picasso/references/dark-mode.md +199 -0
  34. package/skills/picasso/references/depth-and-elevation.md +211 -0
  35. package/skills/picasso/references/i18n-visual-patterns.md +177 -0
  36. package/skills/picasso/references/images-and-media.md +222 -0
  37. package/skills/picasso/references/loading-and-states.md +258 -0
  38. package/skills/picasso/references/micro-interactions.md +291 -0
  39. package/skills/picasso/references/motion-and-animation.md +9 -2
  40. package/skills/picasso/references/navigation-patterns.md +247 -0
  41. package/skills/picasso/references/style-presets.md +1 -1
  42. package/skills/picasso/references/tables-and-forms.md +227 -0
  43. package/skills/picasso/references/tools-catalog.md +103 -0
  44. package/skills/picasso/references/typography.md +45 -2
@@ -0,0 +1,244 @@
1
+ # Animation Performance Reference
2
+
3
+ ## Table of Contents
4
+ 1. Compositor-Only Properties
5
+ 2. Will-Change Best Practices
6
+ 3. Layout Thrashing
7
+ 4. IntersectionObserver vs Scroll Events
8
+ 5. Web Animations API
9
+ 6. Performance Measurement
10
+ 7. Testing on Low-End Devices
11
+ 8. Contain Property
12
+ 9. Common Mistakes
13
+
14
+ ---
15
+
16
+ ## 1. Compositor-Only Properties
17
+
18
+ Only two CSS properties can be animated without triggering layout or paint: **transform** and **opacity**. Everything else causes reflow.
19
+
20
+ | Property | Layout | Paint | Composite | Animate? |
21
+ |---|---|---|---|---|
22
+ | `transform` | No | No | Yes | **Yes** |
23
+ | `opacity` | No | No | Yes | **Yes** |
24
+ | `filter` | No | Yes | Yes | Carefully |
25
+ | `background-color` | No | Yes | No | Avoid |
26
+ | `width`, `height` | Yes | Yes | No | **Never** |
27
+ | `top`, `left` | Yes | Yes | No | **Never** |
28
+ | `margin`, `padding` | Yes | Yes | No | **Never** |
29
+ | `border-radius` | No | Yes | No | Avoid |
30
+
31
+ ```css
32
+ /* Good: compositor-only */
33
+ .slide-in {
34
+ transform: translateX(-100%);
35
+ opacity: 0;
36
+ transition: transform 300ms var(--ease-out), opacity 300ms var(--ease-out);
37
+ }
38
+ .slide-in.active {
39
+ transform: translateX(0);
40
+ opacity: 1;
41
+ }
42
+
43
+ /* Bad: triggers layout on every frame */
44
+ .slide-in-bad {
45
+ left: -100%;
46
+ transition: left 300ms ease;
47
+ }
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 2. Will-Change Best Practices
53
+
54
+ `will-change` promotes an element to its own compositor layer. This speeds up animation but consumes GPU memory.
55
+
56
+ Rules:
57
+ - Add `will-change` BEFORE the animation starts (e.g., on hover, not in the animation itself).
58
+ - Remove it AFTER the animation completes.
59
+ - Never use `will-change: all` — it promotes everything.
60
+ - Never apply it to more than 10 elements simultaneously.
61
+ - Don't put it in your stylesheet permanently.
62
+
63
+ ```js
64
+ // Good: apply before, remove after
65
+ element.addEventListener('mouseenter', () => {
66
+ element.style.willChange = 'transform';
67
+ });
68
+ element.addEventListener('transitionend', () => {
69
+ element.style.willChange = 'auto';
70
+ });
71
+ ```
72
+
73
+ ```css
74
+ /* Acceptable: for elements that are ALWAYS animated (e.g., loading spinners) */
75
+ .spinner { will-change: transform; }
76
+
77
+ /* Bad: permanent will-change on static elements */
78
+ .card { will-change: transform, opacity; } /* don't do this */
79
+ ```
80
+
81
+ ---
82
+
83
+ ## 3. Layout Thrashing
84
+
85
+ Reading layout properties then writing them in a loop forces the browser to recalculate layout on every iteration.
86
+
87
+ ```js
88
+ // BAD: layout thrashing (read-write-read-write)
89
+ elements.forEach(el => {
90
+ const height = el.offsetHeight; // READ — forces layout
91
+ el.style.height = height + 10 + 'px'; // WRITE — invalidates layout
92
+ });
93
+
94
+ // GOOD: batch reads, then batch writes
95
+ const heights = elements.map(el => el.offsetHeight); // all reads first
96
+ elements.forEach((el, i) => {
97
+ el.style.height = heights[i] + 10 + 'px'; // all writes after
98
+ });
99
+ ```
100
+
101
+ Properties that trigger forced layout when read: `offsetHeight`, `offsetWidth`, `getBoundingClientRect()`, `scrollTop`, `clientHeight`, `getComputedStyle()`.
102
+
103
+ ---
104
+
105
+ ## 4. IntersectionObserver vs Scroll Events
106
+
107
+ | | `scroll` event | IntersectionObserver |
108
+ |---|---|---|
109
+ | Performance | Fires every pixel, blocks main thread | Async, fires on threshold crossing |
110
+ | Throttling | Manual (requestAnimationFrame) | Built-in |
111
+ | Use case | Scroll-linked animation (position) | Visibility detection (enter/exit) |
112
+ | Recommendation | Almost never | Almost always |
113
+
114
+ ```js
115
+ // Good: IntersectionObserver for reveal animations
116
+ const observer = new IntersectionObserver(
117
+ (entries) => {
118
+ entries.forEach(entry => {
119
+ entry.target.classList.toggle('visible', entry.isIntersecting);
120
+ });
121
+ },
122
+ { threshold: 0.1 }
123
+ );
124
+ ```
125
+
126
+ For scroll-linked animations where you need exact scroll position, use the Scroll-Driven Animations API:
127
+
128
+ ```css
129
+ @keyframes fade-in {
130
+ from { opacity: 0; transform: translateY(20px); }
131
+ to { opacity: 1; transform: translateY(0); }
132
+ }
133
+
134
+ .scroll-reveal {
135
+ animation: fade-in linear;
136
+ animation-timeline: view();
137
+ animation-range: entry 0% entry 100%;
138
+ }
139
+ ```
140
+
141
+ ---
142
+
143
+ ## 5. Web Animations API
144
+
145
+ For complex JS-driven animations, use WAAPI instead of manual `requestAnimationFrame`:
146
+
147
+ ```js
148
+ element.animate(
149
+ [
150
+ { transform: 'translateY(20px)', opacity: 0 },
151
+ { transform: 'translateY(0)', opacity: 1 }
152
+ ],
153
+ {
154
+ duration: 300,
155
+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
156
+ fill: 'forwards'
157
+ }
158
+ );
159
+ ```
160
+
161
+ Benefits over CSS: programmable, cancellable, can read progress, can reverse.
162
+
163
+ ---
164
+
165
+ ## 6. Performance Measurement
166
+
167
+ ```js
168
+ // Measure animation frame rate
169
+ let frames = 0;
170
+ let lastTime = performance.now();
171
+
172
+ function countFrames() {
173
+ frames++;
174
+ const now = performance.now();
175
+ if (now - lastTime >= 1000) {
176
+ console.log(`FPS: ${frames}`);
177
+ frames = 0;
178
+ lastTime = now;
179
+ }
180
+ requestAnimationFrame(countFrames);
181
+ }
182
+ requestAnimationFrame(countFrames);
183
+ ```
184
+
185
+ Chrome DevTools:
186
+ 1. Performance tab → Record → interact with animations → Stop
187
+ 2. Look for long frames (> 16ms) in the flame chart
188
+ 3. Rendering tab → Paint flashing (green = repaint, should be minimal)
189
+ 4. Rendering tab → Layer borders (orange = composited layers)
190
+
191
+ Target: 60fps = 16.67ms per frame. If ANY frame takes > 33ms, users perceive jank.
192
+
193
+ ---
194
+
195
+ ## 7. Testing on Low-End Devices
196
+
197
+ Your M-series Mac is not representative. Test with:
198
+ - **Chrome DevTools CPU throttling:** Performance tab → CPU → 6x slowdown
199
+ - **Network throttling:** Slow 3G preset to test loading animations
200
+ - **Real device:** Test on a 3-year-old Android phone if possible
201
+
202
+ If an animation stutters at 6x CPU throttle, reduce:
203
+ 1. Number of concurrent animations
204
+ 2. Element count being animated
205
+ 3. Complexity of each animation
206
+
207
+ ---
208
+
209
+ ## 8. Contain Property
210
+
211
+ `contain` tells the browser what NOT to recalculate when an element changes.
212
+
213
+ ```css
214
+ /* Isolate layout/paint to this element */
215
+ .card {
216
+ contain: layout paint;
217
+ }
218
+
219
+ /* Full isolation — best for off-screen or independent components */
220
+ .widget {
221
+ contain: strict; /* = size + layout + paint + style */
222
+ }
223
+
224
+ /* Content containment — layout + paint + style (most common) */
225
+ .list-item {
226
+ contain: content;
227
+ }
228
+ ```
229
+
230
+ Use `contain: content` on repeated elements (list items, cards) to prevent layout changes from propagating to siblings.
231
+
232
+ ---
233
+
234
+ ## 9. Common Mistakes
235
+
236
+ - **Animating `width`/`height`/`top`/`left`.** Use `transform: translate/scale` instead.
237
+ - **`will-change` on everything.** Max 10 elements. Remove after animation completes.
238
+ - **`addEventListener('scroll')` for visibility.** Use IntersectionObserver.
239
+ - **Reading layout properties in animation loops.** Batch reads before writes.
240
+ - **Testing only on fast hardware.** Use Chrome CPU throttling at 6x.
241
+ - **No frame budget awareness.** 16ms per frame. If your JS takes 20ms, you drop frames.
242
+ - **CSS `transition: all`.** Transitions every property including layout triggers.
243
+ - **Forgetting `contain` on repeated elements.** One card's layout change recalculates the entire list.
244
+ - **`requestAnimationFrame` without cancellation.** Always store the ID and `cancelAnimationFrame` on cleanup.
@@ -0,0 +1,136 @@
1
+ # Brand and Identity Reference
2
+
3
+ ## Table of Contents
4
+ 1. Logo Sizing Rules
5
+ 2. Logo Placement
6
+ 3. Logo Lockup Variants
7
+ 4. Brand Color Usage
8
+ 5. Brand Typography
9
+ 6. Consistency Across Pages
10
+ 7. When to Bend Brand Rules
11
+ 8. Common Mistakes
12
+
13
+ ---
14
+
15
+ ## 1. Logo Sizing Rules
16
+
17
+ - **Minimum size:** 24px height for icon-only, 32px height for full logo. Below this it's illegible.
18
+ - **Clear space:** Minimum clear space around logo = the height of the logo's icon element. No text or elements may intrude.
19
+ - **Typical sizes by context:**
20
+
21
+ | Context | Height |
22
+ |---|---|
23
+ | Favicon | 32px |
24
+ | Mobile header | 28-32px |
25
+ | Desktop header | 32-40px |
26
+ | Footer | 24-28px |
27
+ | Hero/marketing | 48-64px |
28
+ | App splash | 80-120px |
29
+
30
+ ```css
31
+ .logo { height: 32px; width: auto; } /* maintain aspect ratio */
32
+ .logo-icon { height: 28px; width: 28px; }
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 2. Logo Placement
38
+
39
+ - **Header:** top-left for LTR, top-right for RTL. Always links to homepage.
40
+ - **Footer:** bottom-left or bottom-center. Smaller than header.
41
+ - **Marketing pages:** centered for hero sections, left-aligned for navigation.
42
+ - **Loading/splash:** centered vertically and horizontally.
43
+
44
+ The header logo is the most important. It should be the first visual element the user sees, but not dominate the page. Keep it slim.
45
+
46
+ ---
47
+
48
+ ## 3. Logo Lockup Variants
49
+
50
+ Every brand needs at least 3 logo variants:
51
+
52
+ 1. **Full lockup:** icon + wordmark (for headers, marketing)
53
+ 2. **Icon only:** for favicons, app icons, small spaces, mobile headers
54
+ 3. **Wordmark only:** for editorial/text-heavy contexts
55
+
56
+ ```jsx
57
+ // Responsive logo: icon on mobile, full on desktop
58
+ <Link href="/" className="flex items-center gap-2">
59
+ <img src="/logo-icon.svg" alt="" className="h-7 w-7" />
60
+ <span className="hidden sm:inline text-sm font-bold tracking-tight">Brand Name</span>
61
+ </Link>
62
+ ```
63
+
64
+ ---
65
+
66
+ ## 4. Brand Color Usage
67
+
68
+ Follow the 60-30-10 rule with brand colors:
69
+ - **60%** — neutral surfaces (backgrounds, cards). Brand color should NOT be the 60%.
70
+ - **30%** — supporting colors (borders, secondary text, section backgrounds).
71
+ - **10%** — brand/accent color (CTAs, active states, highlights). This is where brand color goes.
72
+
73
+ ```css
74
+ :root {
75
+ --brand: oklch(0.55 0.25 250); /* Primary brand color — use at 10% */
76
+ --brand-subtle: oklch(0.95 0.03 250); /* Tinted background — use sparingly */
77
+ --brand-on-dark: oklch(0.70 0.18 250); /* Lighter variant for dark backgrounds */
78
+ }
79
+ ```
80
+
81
+ Never use brand color as background for large areas (hero sections, full-width bars) unless the brand is specifically known for it (like Spotify's green). Large saturated surfaces are fatiguing.
82
+
83
+ ---
84
+
85
+ ## 5. Brand Typography
86
+
87
+ If the brand has a custom/licensed font, use it for headings only. Body text should be a readable, web-optimized font.
88
+
89
+ ```css
90
+ /* Brand font for headings */
91
+ h1, h2, h3 { font-family: 'Brand Display', var(--font-body); }
92
+
93
+ /* Readable font for body */
94
+ body { font-family: 'DM Sans', system-ui, sans-serif; }
95
+ ```
96
+
97
+ If the brand font isn't available for web, find the closest web-safe alternative:
98
+ - Futura → use Outfit or Jost
99
+ - Helvetica Neue → use Inter (only acceptable here) or Geist
100
+ - Garamond → use EB Garamond or Cormorant
101
+
102
+ ---
103
+
104
+ ## 6. Consistency Across Pages
105
+
106
+ Every page should share:
107
+ - Same header and footer (identical, not "similar")
108
+ - Same color palette (no page-specific colors)
109
+ - Same typography scale
110
+ - Same border-radius philosophy
111
+ - Same spacing scale
112
+
113
+ Variation should come from layout and content, not from inconsistent styling. A dashboard page and a marketing page can look different through layout while sharing the same design tokens.
114
+
115
+ ---
116
+
117
+ ## 7. When to Bend Brand Rules
118
+
119
+ Strict brand adherence isn't always right:
120
+ - **Data-dense dashboards:** Brand color as accent only. Don't fight with data colors.
121
+ - **Error states:** Use standard red for errors, not brand color. Users need instant recognition.
122
+ - **Third-party embeds:** Payment forms, maps, chat widgets have their own styling. Don't fight it.
123
+ - **Dark mode:** Brand color may need lightness/chroma adjustment to maintain contrast.
124
+ - **Accessibility:** If brand colors don't meet WCAG contrast, accessibility wins.
125
+
126
+ ---
127
+
128
+ ## 8. Common Mistakes
129
+
130
+ - **Logo too small in the header.** Minimum 28px height. Users need to identify the brand instantly.
131
+ - **Brand color as full-width background.** Fatiguing. Use at 10% ratio maximum.
132
+ - **Different fonts on every page.** Pick 2 fonts and use them everywhere.
133
+ - **Logo without clear space.** Crowded logos look unprofessional. Enforce minimum padding.
134
+ - **No icon-only variant.** Mobile needs a compact logo. Don't just shrink the full lockup.
135
+ - **Brand color unchanged in dark mode.** Adjust lightness and chroma for dark backgrounds.
136
+ - **Inconsistent border radius between pages.** One sharp page and one rounded page = two brands.
@@ -0,0 +1,222 @@
1
+ # Code Typography Reference
2
+
3
+ ## Table of Contents
4
+ 1. Monospace Font Selection
5
+ 2. Code Block Design
6
+ 3. Syntax Highlighting Accessibility
7
+ 4. Copy-to-Clipboard
8
+ 5. Responsive Code Blocks
9
+ 6. Inline Code Styling
10
+ 7. Diff Views
11
+ 8. Terminal Output
12
+ 9. Common Mistakes
13
+
14
+ ---
15
+
16
+ ## 1. Monospace Font Selection
17
+
18
+ | Font | Ligatures | Style | Best For |
19
+ |---|---|---|---|
20
+ | JetBrains Mono | Yes | Clean, geometric | General purpose, IDEs |
21
+ | Fira Code | Yes | Slightly rounded | Tutorials, docs |
22
+ | Source Code Pro | No | Adobe, professional | Enterprise, clean look |
23
+ | IBM Plex Mono | No | Corporate, legible | Documentation |
24
+ | Geist Mono | No | Vercel, modern | Next.js projects |
25
+ | Cascadia Code | Yes | Microsoft, playful | Terminals |
26
+
27
+ ```css
28
+ code, pre, .mono {
29
+ font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
30
+ font-feature-settings: 'liga' 1, 'calt' 1; /* enable ligatures */
31
+ font-variant-ligatures: common-ligatures;
32
+ }
33
+ ```
34
+
35
+ Ligatures: `=>` becomes ⇒, `!==` becomes ≢, `>=` becomes ≥. Enable for display, disable for editing if users copy code.
36
+
37
+ ---
38
+
39
+ ## 2. Code Block Design
40
+
41
+ ```css
42
+ pre {
43
+ background: var(--surface-1);
44
+ border: 1px solid var(--border);
45
+ border-radius: 8px;
46
+ padding: 1rem 1.25rem;
47
+ font-size: 0.875rem; /* 14px — slightly smaller than body */
48
+ line-height: 1.65; /* Looser than body text for readability */
49
+ overflow-x: auto;
50
+ tab-size: 2;
51
+ -moz-tab-size: 2;
52
+ }
53
+
54
+ /* Dark mode code blocks on light sites */
55
+ [data-theme="light"] pre {
56
+ background: oklch(0.14 0.02 230);
57
+ color: oklch(0.90 0.01 230);
58
+ }
59
+ ```
60
+
61
+ Line numbers (optional):
62
+ ```css
63
+ pre.line-numbers {
64
+ counter-reset: line;
65
+ padding-left: 3.5rem;
66
+ position: relative;
67
+ }
68
+ pre.line-numbers .line::before {
69
+ counter-increment: line;
70
+ content: counter(line);
71
+ position: absolute;
72
+ left: 1rem;
73
+ color: var(--text-muted);
74
+ font-size: 0.75rem;
75
+ user-select: none; /* don't copy line numbers */
76
+ }
77
+ ```
78
+
79
+ ---
80
+
81
+ ## 3. Syntax Highlighting Accessibility
82
+
83
+ Every token color must have **minimum 3:1 contrast** against the code block background. Don't rely on color alone — use font-weight or font-style for emphasis.
84
+
85
+ | Token Type | Suggested OKLCH (dark bg) | Purpose |
86
+ |---|---|---|
87
+ | Keywords | `oklch(0.75 0.15 300)` | purple-ish, bold |
88
+ | Strings | `oklch(0.72 0.14 150)` | green |
89
+ | Numbers | `oklch(0.75 0.12 60)` | amber |
90
+ | Comments | `oklch(0.50 0.01 230)` | muted, italic |
91
+ | Functions | `oklch(0.78 0.10 230)` | blue |
92
+ | Variables | `oklch(0.85 0.01 230)` | near-white |
93
+
94
+ ```css
95
+ .token-keyword { color: oklch(0.75 0.15 300); font-weight: 600; }
96
+ .token-string { color: oklch(0.72 0.14 150); }
97
+ .token-comment { color: oklch(0.50 0.01 230); font-style: italic; }
98
+ ```
99
+
100
+ ---
101
+
102
+ ## 4. Copy-to-Clipboard
103
+
104
+ Position: top-right corner of the code block. Show on hover. Provide visual feedback.
105
+
106
+ ```jsx
107
+ function CopyButton({ code }) {
108
+ const [copied, setCopied] = useState(false);
109
+
110
+ return (
111
+ <button
112
+ onClick={() => {
113
+ navigator.clipboard.writeText(code);
114
+ setCopied(true);
115
+ setTimeout(() => setCopied(false), 2000);
116
+ }}
117
+ className="absolute top-2 right-2 p-1.5 rounded-md bg-white/5 hover:bg-white/10 text-xs text-muted"
118
+ aria-label="Copy code"
119
+ >
120
+ {copied ? 'Copied' : 'Copy'}
121
+ </button>
122
+ );
123
+ }
124
+ ```
125
+
126
+ ---
127
+
128
+ ## 5. Responsive Code Blocks
129
+
130
+ Code blocks should **scroll horizontally** on mobile, never wrap. Terminal output CAN wrap.
131
+
132
+ ```css
133
+ pre {
134
+ overflow-x: auto;
135
+ white-space: pre; /* code: no wrap */
136
+ -webkit-overflow-scrolling: touch; /* smooth scroll on iOS */
137
+ }
138
+
139
+ pre.terminal {
140
+ white-space: pre-wrap; /* terminal: wrap is OK */
141
+ word-break: break-all;
142
+ }
143
+
144
+ /* Hide scrollbar but keep functionality */
145
+ pre::-webkit-scrollbar { height: 4px; }
146
+ pre::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
147
+ ```
148
+
149
+ On very small screens (< 375px), consider reducing code font-size to 12px.
150
+
151
+ ---
152
+
153
+ ## 6. Inline Code Styling
154
+
155
+ Inline code needs subtle visual distinction from body text:
156
+
157
+ ```css
158
+ code:not(pre code) {
159
+ background: var(--surface-2);
160
+ padding: 0.15em 0.4em;
161
+ border-radius: 4px;
162
+ font-size: 0.9em; /* slightly smaller than surrounding text */
163
+ font-weight: 500;
164
+ border: 1px solid var(--border);
165
+ }
166
+ ```
167
+
168
+ Never use inline code for emphasis. It's for code references (`useState`, `border-radius`, `GET /api/users`), not for highlighting words.
169
+
170
+ ---
171
+
172
+ ## 7. Diff Views
173
+
174
+ Use color + icon, not color alone (colorblind users):
175
+
176
+ ```css
177
+ .diff-add {
178
+ background: oklch(0.62 0.19 150 / 0.1);
179
+ border-left: 3px solid oklch(0.62 0.19 150);
180
+ }
181
+ .diff-add::before { content: '+'; color: oklch(0.62 0.19 150); }
182
+
183
+ .diff-remove {
184
+ background: oklch(0.55 0.22 25 / 0.1);
185
+ border-left: 3px solid oklch(0.55 0.22 25);
186
+ text-decoration: line-through;
187
+ opacity: 0.7;
188
+ }
189
+ .diff-remove::before { content: '-'; color: oklch(0.55 0.22 25); }
190
+ ```
191
+
192
+ ---
193
+
194
+ ## 8. Terminal Output
195
+
196
+ Terminal/console styling should feel distinct from code:
197
+
198
+ ```css
199
+ .terminal {
200
+ background: oklch(0.08 0.01 230);
201
+ color: oklch(0.80 0.01 150); /* slight green tint for terminal feel */
202
+ font-family: 'JetBrains Mono', monospace;
203
+ padding: 1rem;
204
+ border-radius: 8px;
205
+ }
206
+ .terminal .prompt { color: oklch(0.65 0.10 230); } /* blue prompt */
207
+ .terminal .output { color: oklch(0.75 0.01 230); } /* neutral output */
208
+ .terminal .error { color: oklch(0.65 0.22 25); } /* red errors */
209
+ ```
210
+
211
+ ---
212
+
213
+ ## 9. Common Mistakes
214
+
215
+ - **Code font too large.** 14px for blocks, 0.9em for inline. Larger fights with body text.
216
+ - **No horizontal scroll on code blocks.** Wrapping code breaks readability. Always `overflow-x: auto`.
217
+ - **Syntax colors with < 3:1 contrast.** Comments especially — they tend to be too faint.
218
+ - **Color-only diff indication.** Always add + / - markers or icons alongside color.
219
+ - **Copying includes line numbers.** Use `user-select: none` on line number elements.
220
+ - **Same styling for code blocks and terminal.** They serve different purposes. Terminal gets darker bg, green tint.
221
+ - **`font-family: monospace` without named fonts.** Browsers default to Courier New which looks dated. Always specify a modern monospace font first.
222
+ - **No copy button.** Users shouldn't have to triple-click and drag to copy code.
@@ -9,7 +9,9 @@
9
9
  6. CSS Variables Pattern
10
10
  7. Curated Color Palettes
11
11
  8. Wide Gamut Colors (P3)
12
- 9. Common Mistakes
12
+ 9. `light-dark()` CSS Function
13
+ 10. `color-mix()` for Runtime Blending
14
+ 11. Common Mistakes
13
15
 
14
16
  ---
15
17
 
@@ -412,7 +414,58 @@ Note: OKLCH values automatically map to the widest gamut the browser and display
412
414
 
413
415
  ---
414
416
 
415
- ## 9. Common Mistakes
417
+ ## 9. `light-dark()` CSS Function
418
+
419
+ The `light-dark()` function returns one of two values depending on the current `color-scheme`. This eliminates the need for duplicate variable declarations in many cases:
420
+
421
+ ```css
422
+ :root {
423
+ color-scheme: light dark;
424
+ }
425
+
426
+ .surface {
427
+ background: light-dark(oklch(0.97 0.005 260), oklch(0.17 0.012 260));
428
+ }
429
+ .text {
430
+ color: light-dark(oklch(0.20 0.015 260), oklch(0.93 0.01 260));
431
+ }
432
+ .border {
433
+ border-color: light-dark(oklch(0.88 0.01 260), oklch(0.25 0.01 260));
434
+ }
435
+ ```
436
+
437
+ Use `light-dark()` for simple color flips (surfaces, text, borders). For complex theme differences (shadow systems, accent adjustments, chroma changes), continue using `[data-theme="dark"]` selectors or CSS custom properties for full control.
438
+
439
+ Browser support: baseline since March 2024 (Chrome 123, Firefox 120, Safari 17.5).
440
+
441
+ ---
442
+
443
+ ## 10. `color-mix()` for Runtime Blending
444
+
445
+ `color-mix()` blends two colors at runtime without defining intermediate tokens. Useful for hover states, tinted surfaces, and dynamic theming:
446
+
447
+ ```css
448
+ /* Hover: darken accent by mixing with black */
449
+ .btn:hover {
450
+ background: color-mix(in oklch, var(--accent), black 15%);
451
+ }
452
+
453
+ /* Subtle tint: mix accent into white */
454
+ .surface-tinted {
455
+ background: color-mix(in oklch, var(--accent), white 92%);
456
+ }
457
+
458
+ /* Disabled: reduce opacity feel by mixing with the surface */
459
+ .btn:disabled {
460
+ background: color-mix(in oklch, var(--accent), var(--surface-0) 60%);
461
+ }
462
+ ```
463
+
464
+ Always specify `in oklch` for perceptually uniform blending. Mixing `in srgb` produces muddier results, especially across hues.
465
+
466
+ ---
467
+
468
+ ## 11. Common Mistakes
416
469
 
417
470
  - Using pure black (#000) for text (use tinted near-black instead)
418
471
  - Using gray text on colored backgrounds (low contrast, hard to read)
@@ -421,3 +474,4 @@ Note: OKLCH values automatically map to the widest gamut the browser and display
421
474
  - Forgetting to test dark mode after building light mode
422
475
  - Using brand colors at full saturation for large surfaces (they vibrate and cause eye strain; reserve full chroma for small accents)
423
476
  - Not providing hover/focus states with visible color change
477
+ - Using `color-mix(in srgb, ...)` instead of `color-mix(in oklch, ...)` (sRGB blending produces muddier, less predictable results)