devtronic 1.2.2 → 1.2.4

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 (21) hide show
  1. package/dist/index.js +154 -149
  2. package/package.json +1 -1
  3. package/templates/addons/auto-devtronic/agents/failure-analyst.md +156 -0
  4. package/templates/addons/auto-devtronic/agents/issue-parser.md +145 -0
  5. package/templates/addons/auto-devtronic/agents/quality-runner.md +85 -0
  6. package/templates/addons/auto-devtronic/manifest.json +16 -0
  7. package/templates/addons/auto-devtronic/skills/auto-devtronic/SKILL.md +611 -0
  8. package/templates/addons/design-best-practices/manifest.json +28 -0
  9. package/templates/addons/design-best-practices/reference/color-and-contrast.md +146 -0
  10. package/templates/addons/design-best-practices/reference/interaction-design.md +208 -0
  11. package/templates/addons/design-best-practices/reference/motion-design.md +167 -0
  12. package/templates/addons/design-best-practices/reference/responsive-design.md +180 -0
  13. package/templates/addons/design-best-practices/reference/spatial-design.md +161 -0
  14. package/templates/addons/design-best-practices/reference/typography.md +136 -0
  15. package/templates/addons/design-best-practices/reference/ux-writing.md +190 -0
  16. package/templates/addons/design-best-practices/rules/design-quality.md +53 -0
  17. package/templates/addons/design-best-practices/skills/design-harden/SKILL.md +142 -0
  18. package/templates/addons/design-best-practices/skills/design-init/SKILL.md +95 -0
  19. package/templates/addons/design-best-practices/skills/design-refine/SKILL.md +124 -0
  20. package/templates/addons/design-best-practices/skills/design-review/SKILL.md +107 -0
  21. package/templates/addons/design-best-practices/skills/design-system/SKILL.md +125 -0
@@ -0,0 +1,146 @@
1
+ # Color & Contrast Reference
2
+
3
+ Guide to building functional, accessible color palettes for frontend interfaces.
4
+
5
+ ---
6
+
7
+ ## OKLCH Color Space
8
+
9
+ OKLCH (Oklab Lightness, Chroma, Hue) provides perceptually uniform color manipulation:
10
+
11
+ ```css
12
+ /* oklch(lightness chroma hue) */
13
+ --accent: oklch(0.65 0.2 250); /* Vivid blue */
14
+ --accent-light: oklch(0.85 0.1 250); /* Same hue, lighter */
15
+ --accent-dark: oklch(0.45 0.2 250); /* Same hue, darker */
16
+ ```
17
+
18
+ **Why OKLCH over HSL:**
19
+ - Perceptually uniform lightness (50% L in HSL varies wildly across hues)
20
+ - Easier to create harmonious palettes
21
+ - Better for dark mode transformations (adjust L only)
22
+ - Chroma channel controls saturation more predictably
23
+
24
+ ---
25
+
26
+ ## Palette Construction
27
+
28
+ ### Step 1: Neutrals First
29
+
30
+ Build the neutral palette before any color:
31
+
32
+ ```
33
+ Near-white: oklch(0.98 0.005 [warm/cool hue])
34
+ Light gray: oklch(0.92 0.005 [same hue])
35
+ Mid gray: oklch(0.70 0.005 [same hue])
36
+ Dark gray: oklch(0.40 0.01 [same hue])
37
+ Near-black: oklch(0.15 0.01 [same hue])
38
+ ```
39
+
40
+ Slightly warm (hue ~80) or cool (hue ~250) — never pure neutral gray.
41
+
42
+ ### Step 2: Functional Colors
43
+
44
+ ```
45
+ Error: oklch(0.55 0.2 25) /* Red family */
46
+ Warning: oklch(0.70 0.15 80) /* Amber family */
47
+ Success: oklch(0.60 0.15 150) /* Green family */
48
+ Info: oklch(0.60 0.15 240) /* Blue family */
49
+ ```
50
+
51
+ ### Step 3: Accent (One Strong Color)
52
+
53
+ - Pick one accent color for primary actions and emphasis
54
+ - Generate 3-5 shades (lighter for backgrounds, darker for text)
55
+ - One intense color moment is stronger than five
56
+
57
+ ### The 60-30-10 Rule
58
+
59
+ - **60%** — Dominant (background, surfaces)
60
+ - **30%** — Secondary (cards, text, supporting elements)
61
+ - **10%** — Accent (CTAs, active states, highlights)
62
+
63
+ ---
64
+
65
+ ## WCAG Contrast Requirements
66
+
67
+ ### Minimum Ratios
68
+
69
+ | Text Size | Level AA | Level AAA |
70
+ |-----------|----------|-----------|
71
+ | Body text (<18px, <14px bold) | 4.5:1 | 7:1 |
72
+ | Large text (≥18px, ≥14px bold) | 3:1 | 4.5:1 |
73
+ | UI components & graphics | 3:1 | — |
74
+
75
+ ### Testing
76
+
77
+ ```css
78
+ /* Check in DevTools: Elements → Computed → color */
79
+ /* Or use: contrast-ratio.com, WebAIM contrast checker */
80
+ ```
81
+
82
+ **Common traps:**
83
+ - Light gray text on white (#999 on #fff = 2.8:1 — fails)
84
+ - Colored text on colored background (check every combination)
85
+ - Placeholder text (often too light)
86
+ - Disabled states (still need 3:1 for the border/icon)
87
+
88
+ ---
89
+
90
+ ## Dark Mode
91
+
92
+ ### Strategy: Don't Invert — Remap
93
+
94
+ ```css
95
+ /* Light mode */
96
+ --bg: oklch(0.98 0.005 80);
97
+ --text: oklch(0.15 0.01 80);
98
+ --surface: oklch(0.95 0.005 80);
99
+
100
+ /* Dark mode — not simple inversion */
101
+ --bg: oklch(0.15 0.01 250); /* Slightly cool */
102
+ --text: oklch(0.92 0.005 250); /* Not pure white */
103
+ --surface: oklch(0.20 0.01 250); /* Subtle elevation */
104
+ ```
105
+
106
+ **Rules:**
107
+ - Dark mode backgrounds should never be pure black (#000)
108
+ - Reduce chroma slightly for dark mode (vivid colors are harsher on dark)
109
+ - Use elevation (lighter surfaces) instead of shadows for depth
110
+ - Accent colors may need lightness adjustment to maintain contrast
111
+
112
+ ---
113
+
114
+ ## Color Accessibility
115
+
116
+ - Never use color alone to convey meaning (add icons, text, patterns)
117
+ - Provide sufficient contrast between adjacent colors
118
+ - Test with color blindness simulators (protanopia, deuteranopia, tritanopia)
119
+ - Link text must be distinguishable from surrounding text (not just color — add underline)
120
+
121
+ ---
122
+
123
+ ## Practical Palette Template
124
+
125
+ ```css
126
+ :root {
127
+ /* Neutrals */
128
+ --gray-50: oklch(0.98 0.005 80);
129
+ --gray-100: oklch(0.95 0.005 80);
130
+ --gray-200: oklch(0.90 0.005 80);
131
+ --gray-400: oklch(0.70 0.005 80);
132
+ --gray-600: oklch(0.50 0.01 80);
133
+ --gray-800: oklch(0.25 0.01 80);
134
+ --gray-950: oklch(0.13 0.01 80);
135
+
136
+ /* Accent */
137
+ --accent-100: oklch(0.92 0.05 250);
138
+ --accent-500: oklch(0.60 0.20 250);
139
+ --accent-900: oklch(0.30 0.10 250);
140
+
141
+ /* Semantic */
142
+ --color-error: oklch(0.55 0.20 25);
143
+ --color-warning: oklch(0.70 0.15 80);
144
+ --color-success: oklch(0.60 0.15 150);
145
+ }
146
+ ```
@@ -0,0 +1,208 @@
1
+ # Interaction Design Reference
2
+
3
+ Guide to interactive states, focus management, forms, and keyboard navigation.
4
+
5
+ ---
6
+
7
+ ## The 8 Interactive States
8
+
9
+ Every interactive element should define these states:
10
+
11
+ | State | Description | Visual Treatment |
12
+ |-------|-------------|-----------------|
13
+ | **Default** | Base appearance | Standard styling |
14
+ | **Hover** | Mouse over (desktop) | Subtle background change, cursor: pointer |
15
+ | **Focus** | Keyboard focused | Visible focus ring (2px+ offset) |
16
+ | **Active** | Being pressed | Slight scale-down or color shift |
17
+ | **Disabled** | Not available | Reduced opacity (0.5), cursor: not-allowed |
18
+ | **Loading** | Processing action | Spinner or skeleton, disable re-click |
19
+ | **Error** | Invalid state | Red border/text, error message |
20
+ | **Success** | Completed action | Green check, confirmation message |
21
+
22
+ ### Implementation
23
+
24
+ ```css
25
+ .button {
26
+ /* Default */
27
+ background: var(--accent-500);
28
+ color: white;
29
+ cursor: pointer;
30
+ transition: background 150ms ease-out;
31
+ }
32
+
33
+ .button:hover { background: var(--accent-600); }
34
+
35
+ .button:focus-visible {
36
+ outline: 2px solid var(--accent-500);
37
+ outline-offset: 2px;
38
+ }
39
+
40
+ .button:active { transform: scale(0.98); }
41
+
42
+ .button:disabled {
43
+ opacity: 0.5;
44
+ cursor: not-allowed;
45
+ pointer-events: none;
46
+ }
47
+ ```
48
+
49
+ ---
50
+
51
+ ## Focus Management
52
+
53
+ ### Focus Rings
54
+
55
+ ```css
56
+ /* Global focus style */
57
+ :focus-visible {
58
+ outline: 2px solid var(--accent-500);
59
+ outline-offset: 2px;
60
+ }
61
+
62
+ /* Remove default outline only when using focus-visible */
63
+ :focus:not(:focus-visible) {
64
+ outline: none;
65
+ }
66
+ ```
67
+
68
+ **Rules:**
69
+ - Focus rings must be visible on all backgrounds
70
+ - Use `outline` not `box-shadow` (outlines respect `outline-offset` and don't affect layout)
71
+ - Minimum 2px width, contrasting color
72
+ - `focus-visible` only shows for keyboard navigation, not mouse clicks
73
+
74
+ ### Focus Trapping (Modals)
75
+
76
+ ```javascript
77
+ // When modal opens:
78
+ // 1. Move focus to first focusable element
79
+ // 2. Trap Tab/Shift+Tab within modal
80
+ // 3. Close on Escape
81
+ // 4. Return focus to trigger element on close
82
+ ```
83
+
84
+ ### Focus Restoration
85
+
86
+ After closing a modal, dropdown, or sidebar, return focus to the element that triggered it.
87
+
88
+ ---
89
+
90
+ ## Form Patterns
91
+
92
+ ### Labels
93
+
94
+ - Every input needs a visible `<label>` (not just placeholder)
95
+ - Labels above inputs (not beside — better for mobile and scanning)
96
+ - Required fields: use `*` after label text + `aria-required="true"`
97
+
98
+ ### Validation
99
+
100
+ ```css
101
+ /* Show errors on blur, not on type */
102
+ .input:not(:focus):invalid {
103
+ border-color: var(--color-error);
104
+ }
105
+
106
+ .error-message {
107
+ color: var(--color-error);
108
+ font-size: 0.875rem;
109
+ margin-top: 4px;
110
+ }
111
+ ```
112
+
113
+ **Rules:**
114
+ - Validate on blur (not on every keystroke)
115
+ - Show error messages below the field, not in alerts/toasts
116
+ - Don't clear the input on error — let users correct
117
+ - Use `aria-describedby` to associate error messages with inputs
118
+ - Provide positive feedback for complex fields (password strength)
119
+
120
+ ### Input Sizing
121
+
122
+ - Text inputs: minimum width to fit expected content
123
+ - Select/dropdown: wide enough for longest option
124
+ - Textarea: show at least 3 lines by default
125
+ - Touch targets: 44x44px minimum (48px recommended)
126
+
127
+ ---
128
+
129
+ ## Keyboard Navigation
130
+
131
+ ### Essential Patterns
132
+
133
+ | Key | Action |
134
+ |-----|--------|
135
+ | Tab | Move to next focusable element |
136
+ | Shift + Tab | Move to previous focusable element |
137
+ | Enter / Space | Activate focused element |
138
+ | Escape | Close overlay, cancel action |
139
+ | Arrow keys | Navigate within components (tabs, menus, radio groups) |
140
+
141
+ ### Tab Order
142
+
143
+ - Follow visual reading order (top-left to bottom-right for LTR)
144
+ - Don't use `tabindex > 0` — rearranging tab order confuses users
145
+ - Use `tabindex="-1"` for programmatically focusable elements
146
+ - Use `tabindex="0"` to make non-interactive elements focusable (sparingly)
147
+
148
+ ### Skip Links
149
+
150
+ ```html
151
+ <a href="#main-content" class="skip-link">Skip to main content</a>
152
+
153
+ <style>
154
+ .skip-link {
155
+ position: absolute;
156
+ left: -9999px;
157
+ }
158
+ .skip-link:focus {
159
+ position: fixed;
160
+ top: 8px;
161
+ left: 8px;
162
+ z-index: 999;
163
+ }
164
+ </style>
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Loading States
170
+
171
+ ### Button Loading
172
+
173
+ ```html
174
+ <button disabled aria-busy="true">
175
+ <span class="spinner" aria-hidden="true"></span>
176
+ Saving...
177
+ </button>
178
+ ```
179
+
180
+ - Disable the button to prevent double-clicks
181
+ - Show a spinner inside the button (not replacing it)
182
+ - Update button text to reflect action ("Save" → "Saving...")
183
+ - Use `aria-busy="true"` for screen readers
184
+
185
+ ### Page/Section Loading
186
+
187
+ 1. **Skeleton screen** — preferred for known content layouts
188
+ 2. **Spinner** — for unknown content or short waits (<2s)
189
+ 3. **Progress bar** — for file uploads, multi-step processes
190
+ 4. **Optimistic UI** — show expected result immediately, rollback on failure
191
+
192
+ ---
193
+
194
+ ## Click/Touch Targets
195
+
196
+ - Minimum 44x44px (WCAG 2.5.8)
197
+ - Recommended 48x48px for primary actions
198
+ - Minimum 8px gap between adjacent targets
199
+ - Extend hit area with padding, not just visual size:
200
+
201
+ ```css
202
+ .icon-button {
203
+ /* Visual size: 24px icon */
204
+ /* Hit area: 44px with padding */
205
+ padding: 10px;
206
+ margin: -10px; /* Prevent layout shift */
207
+ }
208
+ ```
@@ -0,0 +1,167 @@
1
+ # Motion Design Reference
2
+
3
+ Guide to animation, transitions, and motion in frontend interfaces.
4
+
5
+ ---
6
+
7
+ ## Duration Rules
8
+
9
+ ### The 100 / 300 / 500 Rule
10
+
11
+ | Duration | Use Case | Example |
12
+ |----------|----------|---------|
13
+ | 100-150ms | Micro-interactions | Button press, toggle, hover state |
14
+ | 200-300ms | Standard transitions | Panel open, tab switch, fade in |
15
+ | 400-500ms | Complex animations | Page transition, modal entrance, list reorder |
16
+
17
+ **Rules:**
18
+ - Never exceed 500ms for UI transitions (feels sluggish)
19
+ - Entrances can be slightly slower than exits (300ms in, 200ms out)
20
+ - Content-shifting animations need to be fast (≤200ms) to avoid feeling broken
21
+
22
+ ---
23
+
24
+ ## Easing Curves
25
+
26
+ ### Standard Curves
27
+
28
+ ```css
29
+ /* Entering the screen — starts fast, decelerates */
30
+ --ease-out: cubic-bezier(0.0, 0.0, 0.2, 1.0);
31
+
32
+ /* Leaving the screen — starts slow, accelerates */
33
+ --ease-in: cubic-bezier(0.4, 0.0, 1.0, 1.0);
34
+
35
+ /* Moving on screen — accelerates then decelerates */
36
+ --ease-in-out: cubic-bezier(0.4, 0.0, 0.2, 1.0);
37
+
38
+ /* Playful spring effect */
39
+ --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1.0);
40
+ ```
41
+
42
+ ### When to Use Each
43
+
44
+ | Curve | Use When |
45
+ |-------|----------|
46
+ | ease-out | Elements appearing, expanding, entering view |
47
+ | ease-in | Elements disappearing, collapsing, leaving view |
48
+ | ease-in-out | Elements moving position on screen |
49
+ | spring | Toggles, switches, playful micro-interactions |
50
+ | linear | Progress bars, continuous animations, opacity fades |
51
+
52
+ ---
53
+
54
+ ## Reduced Motion
55
+
56
+ **Always respect `prefers-reduced-motion`:**
57
+
58
+ ```css
59
+ /* Default: full animation */
60
+ .element {
61
+ transition: transform 300ms var(--ease-out), opacity 300ms var(--ease-out);
62
+ }
63
+
64
+ /* Reduced motion: instant or minimal */
65
+ @media (prefers-reduced-motion: reduce) {
66
+ .element {
67
+ transition: opacity 100ms linear;
68
+ /* Remove transform animations, keep opacity */
69
+ }
70
+
71
+ /* Disable all non-essential animations */
72
+ *,
73
+ *::before,
74
+ *::after {
75
+ animation-duration: 0.01ms !important;
76
+ animation-iteration-count: 1 !important;
77
+ transition-duration: 0.01ms !important;
78
+ }
79
+ }
80
+ ```
81
+
82
+ **What to keep in reduced motion:**
83
+ - Opacity transitions (shorter duration)
84
+ - Color changes
85
+ - Essential state indicators
86
+
87
+ **What to remove:**
88
+ - Transform animations (slide, scale, rotate)
89
+ - Parallax effects
90
+ - Auto-playing animations
91
+ - Decorative motion
92
+
93
+ ---
94
+
95
+ ## Perceived Performance
96
+
97
+ Use motion to make loading feel faster:
98
+
99
+ ### Skeleton Screens
100
+
101
+ ```css
102
+ .skeleton {
103
+ background: linear-gradient(
104
+ 90deg,
105
+ oklch(0.92 0 0) 0%,
106
+ oklch(0.96 0 0) 50%,
107
+ oklch(0.92 0 0) 100%
108
+ );
109
+ background-size: 200% 100%;
110
+ animation: shimmer 1.5s ease-in-out infinite;
111
+ }
112
+
113
+ @keyframes shimmer {
114
+ 0% { background-position: 200% 0; }
115
+ 100% { background-position: -200% 0; }
116
+ }
117
+ ```
118
+
119
+ ### Progressive Loading
120
+
121
+ 1. Show skeleton layout immediately
122
+ 2. Fade in critical content first (text, primary actions)
123
+ 3. Load images/media progressively
124
+ 4. Animate list items in with staggered delay (50ms between items, max 5 items)
125
+
126
+ ---
127
+
128
+ ## Animation Patterns
129
+
130
+ ### Enter / Exit
131
+
132
+ ```css
133
+ /* Fade up enter */
134
+ @keyframes fadeUp {
135
+ from { opacity: 0; transform: translateY(8px); }
136
+ to { opacity: 1; transform: translateY(0); }
137
+ }
138
+
139
+ /* Scale enter (modals, popovers) */
140
+ @keyframes scaleIn {
141
+ from { opacity: 0; transform: scale(0.95); }
142
+ to { opacity: 1; transform: scale(1); }
143
+ }
144
+ ```
145
+
146
+ ### Stagger
147
+
148
+ ```css
149
+ .list-item {
150
+ animation: fadeUp 300ms var(--ease-out) both;
151
+ }
152
+
153
+ .list-item:nth-child(1) { animation-delay: 0ms; }
154
+ .list-item:nth-child(2) { animation-delay: 50ms; }
155
+ .list-item:nth-child(3) { animation-delay: 100ms; }
156
+ /* Cap at 5 items — don't stagger infinitely */
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Performance Guidelines
162
+
163
+ - Animate only `transform` and `opacity` (GPU-accelerated, no layout recalc)
164
+ - Avoid animating `width`, `height`, `top`, `left`, `margin`, `padding`
165
+ - Use `will-change` sparingly and only on elements about to animate
166
+ - Test on low-end devices — smooth on MacBook Pro ≠ smooth everywhere
167
+ - Prefer CSS transitions/animations over JavaScript when possible
@@ -0,0 +1,180 @@
1
+ # Responsive Design Reference
2
+
3
+ Guide to mobile-first responsive design, breakpoints, and adaptive layouts.
4
+
5
+ ---
6
+
7
+ ## Mobile-First Approach
8
+
9
+ Write base styles for mobile, then add complexity for larger screens:
10
+
11
+ ```css
12
+ /* Base: mobile (320px+) */
13
+ .grid { display: flex; flex-direction: column; gap: 16px; }
14
+
15
+ /* Tablet (768px+) */
16
+ @media (min-width: 768px) {
17
+ .grid { flex-direction: row; flex-wrap: wrap; }
18
+ .grid > * { flex: 1 1 calc(50% - 8px); }
19
+ }
20
+
21
+ /* Desktop (1024px+) */
22
+ @media (min-width: 1024px) {
23
+ .grid > * { flex: 1 1 calc(33.333% - 11px); }
24
+ }
25
+ ```
26
+
27
+ **Why mobile-first:**
28
+ - Forces you to prioritize content
29
+ - Progressive enhancement is more robust than graceful degradation
30
+ - Mobile CSS is simpler (fewer overrides needed)
31
+
32
+ ---
33
+
34
+ ## Content-Driven Breakpoints
35
+
36
+ Don't use device-specific breakpoints. Break where the content breaks:
37
+
38
+ ```css
39
+ /* Bad: targeting specific devices */
40
+ @media (min-width: 375px) { } /* iPhone */
41
+ @media (min-width: 414px) { } /* iPhone Plus */
42
+
43
+ /* Good: where content needs it */
44
+ @media (min-width: 40em) { } /* ~640px — content gets cramped */
45
+ @media (min-width: 52em) { } /* ~832px — space for 2 columns */
46
+ @media (min-width: 72em) { } /* ~1152px — space for sidebar */
47
+ ```
48
+
49
+ ### Recommended Breakpoint Scale
50
+
51
+ | Name | Width | Use Case |
52
+ |------|-------|----------|
53
+ | sm | 640px | Phone landscape, small tablet |
54
+ | md | 768px | Tablet portrait, two-column |
55
+ | lg | 1024px | Tablet landscape, small desktop |
56
+ | xl | 1280px | Desktop |
57
+ | 2xl | 1536px | Large desktop |
58
+
59
+ ---
60
+
61
+ ## Container Queries
62
+
63
+ Use container queries for component-level responsive design:
64
+
65
+ ```css
66
+ /* Define the container */
67
+ .card-wrapper {
68
+ container-type: inline-size;
69
+ container-name: card;
70
+ }
71
+
72
+ /* Respond to container size, not viewport */
73
+ @container card (min-width: 300px) {
74
+ .card { flex-direction: row; }
75
+ }
76
+
77
+ @container card (max-width: 299px) {
78
+ .card { flex-direction: column; }
79
+ }
80
+ ```
81
+
82
+ **When to use container queries vs media queries:**
83
+ - **Container queries**: Reusable components that may be placed in different-width containers
84
+ - **Media queries**: Page-level layout decisions (columns, navigation mode)
85
+
86
+ ---
87
+
88
+ ## Input Detection
89
+
90
+ Adapt UI based on input method:
91
+
92
+ ```css
93
+ /* Fine pointer (mouse) — smaller targets OK */
94
+ @media (pointer: fine) {
95
+ .button { padding: 8px 16px; }
96
+ }
97
+
98
+ /* Coarse pointer (touch) — larger targets */
99
+ @media (pointer: coarse) {
100
+ .button { padding: 12px 24px; min-height: 48px; }
101
+ }
102
+
103
+ /* Hover capability */
104
+ @media (hover: hover) {
105
+ .card:hover { box-shadow: var(--shadow-md); }
106
+ }
107
+
108
+ @media (hover: none) {
109
+ /* Don't rely on hover states for mobile */
110
+ }
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Safe Areas
116
+
117
+ Handle device-specific safe areas (notch, home indicator):
118
+
119
+ ```css
120
+ /* iOS safe area insets */
121
+ .app {
122
+ padding-top: env(safe-area-inset-top);
123
+ padding-bottom: env(safe-area-inset-bottom);
124
+ padding-left: env(safe-area-inset-left);
125
+ padding-right: env(safe-area-inset-right);
126
+ }
127
+
128
+ /* Fixed bottom navigation */
129
+ .bottom-nav {
130
+ padding-bottom: calc(16px + env(safe-area-inset-bottom));
131
+ }
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Responsive Images
137
+
138
+ ```html
139
+ <!-- srcset for resolution switching -->
140
+ <img
141
+ src="image-400.jpg"
142
+ srcset="image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w"
143
+ sizes="(min-width: 1024px) 33vw, (min-width: 768px) 50vw, 100vw"
144
+ alt="Description"
145
+ loading="lazy"
146
+ />
147
+ ```
148
+
149
+ ```css
150
+ /* Responsive image defaults */
151
+ img {
152
+ max-width: 100%;
153
+ height: auto;
154
+ display: block;
155
+ }
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Responsive Typography
161
+
162
+ Use fluid type instead of breakpoint-based size changes:
163
+
164
+ ```css
165
+ /* Better than @media jumps */
166
+ h1 { font-size: clamp(1.75rem, 4vw + 1rem, 3.5rem); }
167
+ body { font-size: clamp(1rem, 0.5vw + 0.875rem, 1.125rem); }
168
+ ```
169
+
170
+ ---
171
+
172
+ ## Testing Checklist
173
+
174
+ - [ ] No horizontal scroll at any viewport width (320px minimum)
175
+ - [ ] Touch targets ≥ 44x44px on mobile
176
+ - [ ] Text readable without zooming on mobile
177
+ - [ ] Navigation accessible on all screen sizes
178
+ - [ ] Images scale appropriately
179
+ - [ ] Forms usable on mobile (proper input types, no tiny fields)
180
+ - [ ] Content priority matches viewport size (most important content visible first on mobile)