picasso-skill 2.5.0 → 2.6.1

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.
@@ -1,78 +1,33 @@
1
1
  # Responsive Design Reference
2
2
 
3
- ## Table of Contents
4
- 1. Breakpoints
5
- 2. Mobile-First Approach
6
- 3. Fluid Design
7
- 4. Dynamic Viewport Units
8
- 5. Container Queries
9
- 6. Touch Targets
10
- 7. Responsive Typography
11
- 8. Navigation Patterns
12
- 9. Images
13
- 10. Responsive Tables
14
- 11. Print Styles
15
- 12. Progressive Enhancement
16
- 13. Landscape and Orientation
17
- 14. Common Mistakes
18
-
19
3
  ---
20
4
 
21
5
  ## 1. Breakpoints
22
6
 
23
- Use content-driven breakpoints, not device-driven. These are sensible defaults:
7
+ Use content-driven breakpoints, not device-driven. Sensible defaults:
24
8
 
25
- ```css
26
- /* Mobile first: no media query = mobile */
27
- /* Small tablets / large phones */
28
- @media (min-width: 640px) { }
29
- /* Tablets / small laptops */
30
- @media (min-width: 768px) { }
31
- /* Laptops / desktops */
32
- @media (min-width: 1024px) { }
33
- /* Large desktops */
34
- @media (min-width: 1280px) { }
35
- /* Ultrawide */
36
- @media (min-width: 1536px) { }
37
- ```
9
+ | Breakpoint | Width | Target |
10
+ |---|---|---|
11
+ | (none) | Base | Mobile first, no media query |
12
+ | sm | 640px | Large phones / small tablets |
13
+ | md | 768px | Tablets |
14
+ | lg | 1024px | Laptops / desktops |
15
+ | xl | 1280px | Large desktops |
16
+ | 2xl | 1536px | Ultrawide |
38
17
 
39
- When a layout breaks before reaching a named breakpoint, add a custom one. The content dictates the breakpoint, not the other way around. Avoid more than five or six breakpoints total.
18
+ When a layout breaks before reaching a named breakpoint, add a custom one. The content dictates the breakpoint. Avoid more than 5-6 total.
40
19
 
41
- ## 2. Mobile-First Approach
42
-
43
- Start with the mobile layout (single column, stacked). Add complexity at wider breakpoints. This ensures the core experience works everywhere before enhancements.
20
+ ---
44
21
 
45
- ```css
46
- /* Base: single column */
47
- .grid { display: grid; gap: 1rem; }
22
+ ## 2. Mobile-First Approach
48
23
 
49
- /* Tablet: two columns */
50
- @media (min-width: 768px) {
51
- .grid { grid-template-columns: repeat(2, 1fr); }
52
- }
24
+ Start with single-column, stacked layout. Add complexity at wider breakpoints. Base styles = mobile. `@media (min-width)` = enhancements.
53
25
 
54
- /* Desktop: three columns */
55
- @media (min-width: 1024px) {
56
- .grid { grid-template-columns: repeat(3, 1fr); }
57
- }
58
- ```
26
+ ---
59
27
 
60
28
  ## 3. Fluid Design
61
29
 
62
- Use `clamp()` for font sizes, padding, and gaps that scale smoothly:
63
-
64
- ```css
65
- .container {
66
- padding: clamp(1rem, 4vw, 3rem);
67
- max-width: 1200px;
68
- margin: 0 auto;
69
- }
70
- h1 {
71
- font-size: clamp(1.75rem, 4vw + 0.5rem, 3.5rem);
72
- }
73
- ```
74
-
75
- For spacing systems, combine `clamp()` with CSS custom properties so every spacing token scales together:
30
+ Use `clamp()` for font sizes, padding, and gaps that scale smoothly. Combine with CSS custom properties so all spacing tokens scale together:
76
31
 
77
32
  ```css
78
33
  :root {
@@ -80,373 +35,116 @@ For spacing systems, combine `clamp()` with CSS custom properties so every spaci
80
35
  --space-m: clamp(1rem, 3vw, 1.5rem);
81
36
  --space-l: clamp(1.5rem, 5vw, 3rem);
82
37
  }
38
+ h1 { font-size: clamp(1.75rem, 4vw + 0.5rem, 3.5rem); }
83
39
  ```
84
40
 
85
- ## 4. Dynamic Viewport Units
41
+ ---
86
42
 
87
- The classic `vh` unit does not account for browser chrome (address bar, toolbar) on mobile devices. This causes content to be hidden behind the UI. Use the newer viewport units instead:
43
+ ## 4. Dynamic Viewport Units
88
44
 
89
45
  | Unit | Meaning | Use when |
90
46
  |------|---------|----------|
91
- | `svh` | Small viewport height (browser chrome fully visible) | You want the smallest guaranteed visible area |
92
- | `lvh` | Large viewport height (browser chrome hidden) | You want the largest possible area |
93
- | `dvh` | Dynamic viewport height (updates live as chrome shows/hides) | You want the hero or section to always fill exactly the visible area |
94
- | `dvw` | Dynamic viewport width | Rare, but useful for side-panel layouts on mobile browsers with edge UI |
95
-
96
- ```css
97
- /* Full-screen hero that actually fills the screen on mobile */
98
- .hero {
99
- min-height: 100dvh;
100
- display: grid;
101
- place-items: center;
102
- }
103
-
104
- /* Sticky footer layout that respects mobile browser chrome */
105
- .app-shell {
106
- display: grid;
107
- grid-template-rows: auto 1fr auto;
108
- min-height: 100dvh;
109
- }
47
+ | `svh` | Small viewport height (browser chrome visible) | Smallest guaranteed visible area |
48
+ | `lvh` | Large viewport height (chrome hidden) | Largest possible area |
49
+ | `dvh` | Dynamic viewport height (updates live) | Hero/section should always fill visible area |
110
50
 
111
- /* Fallback for older browsers */
112
- .hero {
113
- min-height: 100vh;
114
- min-height: 100dvh;
115
- }
116
- ```
51
+ Always declare a `vh` fallback before the `dvh` value. Use `100dvh` for full-screen heroes and sticky footer layouts.
117
52
 
118
- Always declare a `vh` fallback before the `dvh` value. Browser support is strong (2023+), but the fallback costs nothing.
53
+ ---
119
54
 
120
55
  ## 5. Container Queries
121
56
 
122
- For component-level responsiveness (when the component's width, not the viewport, should determine layout). This is essential for reusable components that live in different layout contexts (main content area, sidebar, modal, dashboard grid).
123
-
124
- ### Card that adapts to its container
57
+ For component-level responsiveness (when the component's width, not the viewport, determines layout). Essential for reusable components in different layout contexts.
125
58
 
126
59
  ```css
127
- .card-container {
128
- container-type: inline-size;
129
- container-name: card;
130
- }
131
-
132
- /* Compact: image on top, content below */
133
- .card {
134
- display: grid;
135
- gap: 0.75rem;
136
- }
137
- .card img {
138
- width: 100%;
139
- aspect-ratio: 16 / 9;
140
- object-fit: cover;
141
- }
142
-
143
- /* Wide enough: image beside content */
144
- @container card (min-width: 400px) {
145
- .card {
146
- grid-template-columns: 200px 1fr;
147
- }
148
- .card img {
149
- aspect-ratio: 1;
150
- height: 100%;
151
- }
152
- }
153
-
154
- /* Very wide: add metadata column */
155
- @container card (min-width: 700px) {
156
- .card {
157
- grid-template-columns: 240px 1fr 180px;
158
- }
159
- }
60
+ .card-container { container-type: inline-size; container-name: card; }
61
+ @container card (min-width: 400px) { .card { grid-template-columns: 200px 1fr; } }
62
+ @container card (min-width: 700px) { .card { grid-template-columns: 240px 1fr 180px; } }
160
63
  ```
161
64
 
162
- ### Sidebar-aware layout
163
-
164
- ```css
165
- .main-content { container-type: inline-size; }
65
+ When the sidebar is open and the main area shrinks, container query grids automatically drop columns without viewport media queries.
166
66
 
167
- @container (min-width: 600px) {
168
- .dashboard-grid {
169
- grid-template-columns: repeat(2, 1fr);
170
- }
171
- }
172
- @container (min-width: 900px) {
173
- .dashboard-grid {
174
- grid-template-columns: repeat(3, 1fr);
175
- }
176
- }
177
- ```
178
-
179
- This means when the sidebar is open and the main area shrinks, the grid automatically drops columns without any viewport media query.
67
+ ---
180
68
 
181
69
  ## 6. Touch Targets
182
70
 
183
- Minimum touch target: 44x44px (WCAG) or 48x48px (Material). Apply to all interactive elements on mobile. If the visual element is smaller, use padding or `::before` pseudo-element to extend the hit area.
71
+ - Minimum: 44x44px (WCAG) or 48x48px (Material)
72
+ - If visual element is smaller, extend hit area with padding or `::before { inset: -12px; }`
73
+ - Ensure at least 8px space between adjacent touch targets
184
74
 
185
- ```css
186
- .icon-button {
187
- position: relative;
188
- width: 24px;
189
- height: 24px;
190
- }
191
- .icon-button::before {
192
- content: '';
193
- position: absolute;
194
- inset: -12px; /* extends tap area to 48x48 */
195
- }
196
- ```
197
-
198
- Also ensure at least 8px of space between adjacent touch targets to prevent mis-taps.
75
+ ---
199
76
 
200
77
  ## 7. Responsive Typography
201
78
 
202
- Do not just shrink everything on mobile. Adjust the type scale:
203
- - Mobile: use a smaller ratio (1.2) with a 15-16px base
204
- - Desktop: use a larger ratio (1.25-1.333) with a 16-18px base
79
+ - Mobile: smaller ratio (1.2) with 15-16px base
80
+ - Desktop: larger ratio (1.25-1.333) with 16-18px base
205
81
  - Headings should scale more aggressively than body text
206
82
 
83
+ ---
84
+
207
85
  ## 8. Navigation Patterns
208
86
 
209
- - **Mobile (< 768px)**: Hamburger menu, bottom tab bar, or slide-out drawer
210
- - **Tablet (768-1024px)**: Collapsed sidebar or icon-only navigation
211
- - **Desktop (> 1024px)**: Full sidebar, top navigation bar, or mega-menu
87
+ | Viewport | Pattern |
88
+ |---|---|
89
+ | Mobile (< 768px) | Hamburger, bottom tab bar, or slide-out drawer |
90
+ | Tablet (768-1024px) | Collapsed sidebar or icon-only nav |
91
+ | Desktop (> 1024px) | Full sidebar, top nav bar, or mega-menu |
92
+
93
+ ---
212
94
 
213
95
  ## 9. Images
214
96
 
215
- Use `srcset` and `sizes` for responsive images. Use `loading="lazy"` for below-the-fold images. Set `aspect-ratio` to prevent layout shift:
97
+ Use `srcset` and `sizes` for responsive images. Use `loading="lazy"` for below-the-fold. Set `aspect-ratio` to prevent layout shift. Use `<picture>` with AVIF/WebP sources.
216
98
 
217
- ```css
218
- img {
219
- width: 100%;
220
- height: auto;
221
- aspect-ratio: 16 / 9;
222
- object-fit: cover;
223
- }
224
- ```
99
+ ---
225
100
 
226
101
  ## 10. Responsive Tables
227
102
 
228
- Tables are one of the hardest elements to make responsive. Two proven patterns:
229
-
230
- ### Pattern A: Horizontal scroll wrapper
231
-
232
- Keeps the table structure intact. Best for data-dense tables where column relationships matter (financial data, comparison grids).
233
-
234
- ```css
235
- .table-wrapper {
236
- overflow-x: auto;
237
- -webkit-overflow-scrolling: touch;
238
- border: 1px solid var(--border);
239
- border-radius: 0.5rem;
240
- }
241
- .table-wrapper table {
242
- min-width: 600px; /* prevents columns from crushing */
243
- width: 100%;
244
- border-collapse: collapse;
245
- }
246
-
247
- /* Visual hint that the table scrolls */
248
- .table-wrapper {
249
- background:
250
- linear-gradient(to right, white 30%, transparent),
251
- linear-gradient(to left, white 30%, transparent),
252
- linear-gradient(to right, rgba(0,0,0,0.1), transparent 15px),
253
- linear-gradient(to left, rgba(0,0,0,0.1), transparent 15px);
254
- background-position: left, right, left, right;
255
- background-size: 40px 100%, 40px 100%, 15px 100%, 15px 100%;
256
- background-repeat: no-repeat;
257
- background-attachment: local, local, scroll, scroll;
258
- }
259
- ```
260
-
261
- ### Pattern B: Stacked cards on mobile
103
+ | Pattern | When to Use |
104
+ |---|---|
105
+ | Horizontal scroll wrapper | Data-dense tables where column relationships matter (financial, comparison) |
106
+ | Stacked cards on mobile | User-facing lists where each row is an independent record (orders, contacts) |
262
107
 
263
- Reformats each row into a standalone card. Best for user-facing lists (orders, contacts, transactions) where each row is an independent record.
108
+ For scroll wrapper: add `overflow-x: auto` with scroll shadow hints. For stacked cards: use `data-label` attributes on `<td>` elements and `td::before { content: attr(data-label); }` on mobile.
264
109
 
265
- ```css
266
- @media (max-width: 767px) {
267
- table, thead, tbody, th, td, tr {
268
- display: block;
269
- }
270
- thead {
271
- position: absolute;
272
- width: 1px;
273
- height: 1px;
274
- overflow: hidden;
275
- clip: rect(0, 0, 0, 0);
276
- }
277
- tr {
278
- margin-bottom: 1rem;
279
- border: 1px solid var(--border);
280
- border-radius: 0.5rem;
281
- padding: 0.75rem;
282
- }
283
- td {
284
- display: flex;
285
- justify-content: space-between;
286
- padding: 0.4rem 0;
287
- border-bottom: 1px solid var(--border-light);
288
- }
289
- td:last-child {
290
- border-bottom: none;
291
- }
292
- /* Use data attributes for labels */
293
- td::before {
294
- content: attr(data-label);
295
- font-weight: 600;
296
- margin-right: 1rem;
297
- flex-shrink: 0;
298
- }
299
- }
300
- ```
301
-
302
- The HTML needs `data-label` attributes on each `<td>`:
303
-
304
- ```html
305
- <td data-label="Name">Alice Johnson</td>
306
- <td data-label="Status">Active</td>
307
- <td data-label="Amount">$1,240.00</td>
308
- ```
110
+ ---
309
111
 
310
112
  ## 11. Print Styles
311
113
 
312
- Always include basic print styles for pages with substantive content (articles, invoices, dashboards, reports):
114
+ For pages with substantive content (articles, invoices, dashboards):
115
+ - Hide nav, sidebar, toolbar, footer with `display: none !important`
116
+ - Reset to white background, black text, 12pt
117
+ - Use `break-after: avoid` on headings, `break-inside: avoid` on tables/cards
118
+ - Show link URLs: `a[href^="http"]::after { content: " (" attr(href) ")"; }`
313
119
 
314
- ```css
315
- @media print {
316
- /* Remove non-essential UI */
317
- nav, .sidebar, .toolbar, footer, .no-print {
318
- display: none !important;
319
- }
320
-
321
- /* Reset backgrounds and colors for ink saving */
322
- body {
323
- background: white !important;
324
- color: black !important;
325
- font-size: 12pt;
326
- line-height: 1.5;
327
- }
328
-
329
- /* Prevent elements from breaking across pages */
330
- h1, h2, h3 {
331
- break-after: avoid;
332
- }
333
- table, figure, .card {
334
- break-inside: avoid;
335
- }
336
-
337
- /* Show link URLs inline */
338
- a[href^="http"]::after {
339
- content: " (" attr(href) ")";
340
- font-size: 0.85em;
341
- color: #555;
342
- }
343
-
344
- /* Constrain width for readability */
345
- .container {
346
- max-width: 100% !important;
347
- padding: 0 !important;
348
- }
349
- }
350
- ```
120
+ ---
351
121
 
352
122
  ## 12. Progressive Enhancement
353
123
 
354
- Use `@supports` to deliver modern layouts to capable browsers while keeping a usable fallback:
355
-
356
- ```css
357
- /* Fallback: flexbox grid */
358
- .grid {
359
- display: flex;
360
- flex-wrap: wrap;
361
- gap: 1rem;
362
- }
363
- .grid > * {
364
- flex: 1 1 300px;
365
- }
366
-
367
- /* Enhancement: subgrid for aligned cards */
368
- @supports (grid-template-rows: subgrid) {
369
- .grid {
370
- display: grid;
371
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
372
- }
373
- .grid > .card {
374
- display: grid;
375
- grid-template-rows: subgrid;
376
- grid-row: span 3;
377
- }
378
- }
379
- ```
380
-
381
- Other useful `@supports` checks:
382
-
383
- ```css
384
- /* Container queries */
385
- @supports (container-type: inline-size) {
386
- .widget-wrapper { container-type: inline-size; }
387
- }
124
+ Use `@supports` for modern layouts with graceful fallbacks:
125
+ - Flexbox fallback, then `@supports (grid-template-rows: subgrid)` for aligned cards
126
+ - `@supports (container-type: inline-size)` for container queries
127
+ - `@supports (backdrop-filter: blur(10px))` for frosted glass
388
128
 
389
- /* Has selector for advanced targeting */
390
- @supports selector(:has(*)) {
391
- .form-group:has(:invalid) { border-color: red; }
392
- }
393
-
394
- /* Backdrop filter for frosted glass */
395
- @supports (backdrop-filter: blur(10px)) {
396
- .overlay {
397
- backdrop-filter: blur(10px);
398
- background: rgba(255, 255, 255, 0.6);
399
- }
400
- }
401
- ```
129
+ ---
402
130
 
403
131
  ## 13. Landscape and Orientation
404
132
 
405
- Handle orientation changes explicitly, especially for mobile devices where landscape mode drastically changes available height:
406
-
407
- ```css
408
- /* Landscape phones: reduce vertical spacing, switch to row layout */
409
- @media (orientation: landscape) and (max-height: 500px) {
410
- .hero {
411
- min-height: auto;
412
- padding: 2rem 1rem;
413
- }
414
- .onboarding-steps {
415
- flex-direction: row;
416
- overflow-x: auto;
417
- }
418
- }
419
-
420
- /* Tablet landscape: often wide enough for desktop layout */
421
- @media (orientation: landscape) and (min-width: 768px) {
422
- .sidebar { display: block; }
423
- }
424
- ```
133
+ - Landscape phones have very little vertical space (under 400px). No full-height heroes or tall modals.
134
+ - Use `@media (orientation: landscape) and (max-height: 500px)` for landscape phone overrides
135
+ - Virtual keyboards consume even more vertical space in landscape
425
136
 
426
- Key considerations:
427
- - Landscape phones have very little vertical space (typically under 400px). Do not use full-height heroes or tall modals.
428
- - Virtual keyboards consume even more vertical space in landscape. Keep form inputs above the fold or use a scroll strategy.
429
- - Test with `(max-height: Xpx)` in addition to orientation queries for finer control.
137
+ ---
430
138
 
431
139
  ## 14. Common Mistakes
432
140
 
433
- - **Hiding content on mobile**: Users expect the same information, just reorganized. Use progressive disclosure (expand/collapse) instead of `display: none`.
434
- - **Unguarded `vw` text**: Using `vw` units for text without a `clamp()` minimum makes text unreadable on small screens and comically large on ultrawide.
435
- - **Horizontal overflow**: Almost never acceptable on mobile. Test at 320px wide to catch it. Common culprits: tables, pre/code blocks, fixed-width images, long URLs.
436
- - **Fixed elements hogging the viewport**: A fixed header + fixed bottom bar + cookie banner can consume over half the screen on a short phone.
437
- - **Not testing real device widths**: 375px (iPhone SE), 390px (modern iPhone), 360px (common Android), 320px (stress test).
438
- - **Ignoring the notch and safe areas**: On devices with notches or rounded corners, use `env(safe-area-inset-*)` for edge-to-edge layouts:
439
- ```css
440
- .bottom-bar {
441
- padding-bottom: env(safe-area-inset-bottom, 0px);
442
- }
443
- ```
444
- - **Breakpoint-only thinking**: If you find yourself writing more than three media queries for a single component, switch to container queries or fluid sizing.
445
- - **Forgetting hover states are absent on touch**: Use `@media (hover: hover)` to scope hover effects so they do not get stuck on touch devices.
446
- ```css
447
- @media (hover: hover) {
448
- .card:hover { transform: translateY(-2px); }
449
- }
450
- ```
451
- - **Z-index wars on mobile**: Stacking contexts behave differently when fixed/sticky elements overlap modals and drawers. Establish a z-index scale in custom properties.
452
- - **Viewport-height layouts with virtual keyboards**: On mobile, the virtual keyboard does not shrink the viewport in all browsers. Elements pinned to `100vh` can end up hidden. Use `100dvh` or listen for `visualViewport` resize events.
141
+ - **Hiding content on mobile**: Use progressive disclosure (expand/collapse) instead of `display: none`
142
+ - **Unguarded `vw` text**: Always use `clamp()` with a minimum
143
+ - **Horizontal overflow**: Test at 320px. Common culprits: tables, pre/code, fixed-width images, long URLs
144
+ - **Fixed elements hogging viewport**: Header + bottom bar + cookie banner can take half the screen
145
+ - **Not testing real widths**: 375px (iPhone SE), 390px (modern iPhone), 360px (Android), 320px (stress test)
146
+ - **Ignoring safe areas**: Use `env(safe-area-inset-*)` for edge-to-edge layouts
147
+ - **Breakpoint-only thinking**: If 3+ media queries for one component, switch to container queries or fluid sizing
148
+ - **Hover states on touch**: Use `@media (hover: hover)` to scope hover effects
149
+ - **Z-index wars**: Establish a z-index scale in custom properties
150
+ - **Viewport-height with virtual keyboards**: Use `100dvh` or `visualViewport` resize events