odd-studio 1.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.
@@ -0,0 +1,415 @@
1
+ # ODD Studio — Accessibility Verification Protocol
2
+
3
+ Accessibility is the practice of building software that works for everyone — including people who use keyboards instead of mice, screen readers instead of displays, or who have configured their devices to reduce motion or increase text size.
4
+
5
+ This document is written for domain experts, not developers. You do not need to understand the code to verify accessibility. You need to know what to look for and how to look for it.
6
+
7
+ ---
8
+
9
+ ## Why Accessibility Matters to You
10
+
11
+ ### The regulatory reason
12
+
13
+ In the United Kingdom, the Equality Act 2010 requires that digital services not discriminate against disabled people. The Public Sector Bodies Accessibility Regulations 2018 mandate WCAG 2.1 AA compliance for public sector websites. Many private sector obligations follow from the Equality Act. If your platform serves students, employees, patients, or the public, you have legal obligations around accessibility.
14
+
15
+ In the United States, the ADA (Americans with Disabilities Act) has been interpreted to cover websites. Title III cases are regularly filed against organisations whose digital products are inaccessible.
16
+
17
+ Inaccessibility is not a technical edge case. It is a legal liability and a barrier to the people you are trying to serve.
18
+
19
+ ### The moral reason
20
+
21
+ Approximately 1 in 5 people in the UK has a disability of some kind. Of those, many experience difficulty using software that was not designed with them in mind: people who are blind or have low vision, people with motor disabilities who cannot use a mouse, people with cognitive disabilities who struggle with complex or confusing interfaces, people with hearing loss who cannot rely on audio cues.
22
+
23
+ When you build inaccessible software in a domain you care about — education, healthcare, housing, professional services — you are excluding the people in that domain who already face the most barriers.
24
+
25
+ ### The practical reason
26
+
27
+ Accessible design is better design for everyone.
28
+
29
+ - Keyboard navigation makes power users faster
30
+ - High-contrast text is easier to read in sunlight or on cheap monitors
31
+ - Clear error messages help everyone, not just people with cognitive disabilities
32
+ - Large touch targets are easier to use for everyone, not just people with motor impairments
33
+ - Captions on video benefit people in noisy environments, not just deaf viewers
34
+
35
+ When you build for accessibility, you build for edge cases. Edge cases reveal design weaknesses that affect everyone.
36
+
37
+ ---
38
+
39
+ ## The WCAG 2.1 AA Standard
40
+
41
+ WCAG stands for Web Content Accessibility Guidelines. It is published by the World Wide Web Consortium (W3C) and is the internationally recognised standard for web accessibility.
42
+
43
+ Version 2.1 Level AA is the standard most organisations target. It is what regulators check. It is what ODD Studio verifies.
44
+
45
+ WCAG is organised around 4 principles. Every guideline belongs to one.
46
+
47
+ ---
48
+
49
+ ## The 4 Principles
50
+
51
+ ### Perceivable
52
+
53
+ Information must be presentable to users in ways they can perceive. If a user cannot see, the information must be available to them another way.
54
+
55
+ **In a real domain example:** Imagine you are building an education platform. A student who is blind uses a screen reader — software that reads the page aloud. If your student application form only communicates status through colour (red = error, green = success), that student cannot perceive the status. The principle of Perceivable requires that you also communicate status through text.
56
+
57
+ **What this means in practice:**
58
+ - Images have descriptive text alternatives
59
+ - Colour is never the only way to communicate information
60
+ - Text can be resized up to 200% without losing functionality
61
+ - Audio and video have captions or transcripts
62
+
63
+ ### Operable
64
+
65
+ Interface components must be operable by users who cannot use a mouse.
66
+
67
+ **In a real domain example:** A senior student who has arthritis navigates your platform using only a keyboard. She presses Tab to move between form fields and Enter to submit. If your Submit button cannot be reached by Tab, or if a dropdown menu only works with a mouse hover, she cannot complete the application. The principle of Operable requires that every interactive element be reachable and usable by keyboard.
68
+
69
+ **What this means in practice:**
70
+ - All functionality is available from a keyboard
71
+ - No content causes seizures (no flashing more than 3 times per second)
72
+ - Users can pause, stop, or hide any moving or auto-updating content
73
+ - Users have enough time to read and use content (timeouts warn and can be extended)
74
+
75
+ ### Understandable
76
+
77
+ Information and interface operation must be understandable.
78
+
79
+ **In a real domain example:** A teacher submits a course update form. It fails validation. The error message reads: "ERR_422: Field constraint violation on entity.courseTitle". The teacher does not know what to do. The principle of Understandable requires that error messages be written in language the user can act on.
80
+
81
+ **What this means in practice:**
82
+ - Text is readable and understandable (appropriate language, no unexplained jargon)
83
+ - Content behaves predictably — navigation in the same position, consistent component behaviour
84
+ - Error messages identify the problem and suggest a fix
85
+ - Form instructions appear before the form, not only in placeholder text
86
+
87
+ ### Robust
88
+
89
+ Content must be robust enough to be interpreted by a wide variety of user agents, including assistive technologies.
90
+
91
+ **In a real domain example:** A student uses an older version of a screen reader that expects standard HTML semantics. If your developer built the "button" as a styled `<div>` element without ARIA roles, the screen reader cannot identify it as a button and cannot interact with it. The principle of Robust requires that you use standard, semantic HTML or supplement non-standard elements with correct ARIA roles.
92
+
93
+ **What this means in practice:**
94
+ - HTML elements are used according to their purpose (buttons for actions, links for navigation)
95
+ - All interactive components have name, role, and value exposed to assistive technologies
96
+ - Status messages are programmatically determinable (the screen reader can find them)
97
+
98
+ ---
99
+
100
+ ## Step-by-Step Verification Procedure
101
+
102
+ You can run all of these tests in a standard browser without any additional software (except screen reader testing, which requires a free download).
103
+
104
+ ---
105
+
106
+ ### Test 1 — Keyboard-Only Navigation
107
+
108
+ **What you are testing:** Can a user complete every task on this screen using only a keyboard?
109
+
110
+ **How to do it:**
111
+
112
+ 1. Put your mouse to one side. Do not touch it during this test.
113
+ 2. Load the page you are testing.
114
+ 3. Press Tab. A visible focus ring should appear on the first interactive element.
115
+ 4. Keep pressing Tab. Observe:
116
+ - Does the focus ring move to every interactive element? (buttons, links, form fields, dropdown triggers)
117
+ - Does it move in a logical order? (top to bottom, left to right — following the visual layout)
118
+ - Is the focus ring clearly visible at every step?
119
+ 5. When focus is on a button, press Enter or Space. Does the button activate?
120
+ 6. When focus is on a link, press Enter. Does it navigate?
121
+ 7. When focus is on a Select or Dropdown, press Enter to open it, arrow keys to navigate, Enter to select.
122
+ 8. When a Dialog opens, confirm focus moves into the dialog. Press Tab inside the dialog — confirm focus stays within the dialog (it should not escape to the page behind). Press Escape — confirm the dialog closes and focus returns to the element that opened it.
123
+
124
+ **Pass criteria:**
125
+ - Every interactive element reachable by Tab
126
+ - Focus ring visible at every step
127
+ - All actions completable by keyboard
128
+ - Dialogs trap and return focus correctly
129
+
130
+ **Fail example:** "When I Tab to the Approve button on the Applications screen and press Enter, the confirmation dialog opens but focus stays on the button behind the dialog. I cannot reach the Confirm button without using the mouse."
131
+
132
+ ---
133
+
134
+ ### Test 2 — Screen Reader Spot-Check
135
+
136
+ **What you are testing:** Does the page make sense when read aloud by a screen reader?
137
+
138
+ **What you need:**
139
+ - On macOS: VoiceOver is built in. Press Cmd+F5 to turn it on.
140
+ - On Windows: NVDA is free. Download from nvaccess.org.
141
+ - On iOS: VoiceOver is built in. Settings > Accessibility > VoiceOver.
142
+
143
+ **How to do it (VoiceOver on macOS):**
144
+
145
+ 1. Press Cmd+F5 to start VoiceOver.
146
+ 2. Press Ctrl+Option+Right Arrow to move to the next element on the page.
147
+ 3. Listen to what VoiceOver reads. Evaluate:
148
+ - Does each form field have a clear label? ("Application date, date field" — not just "date field")
149
+ - Do buttons have meaningful names? ("Approve application from Sarah Chen" — not just "button" or "icon")
150
+ - Do images have appropriate descriptions? (or are decorative images skipped silently?)
151
+ - When an error appears, does VoiceOver announce it? (without you having to navigate to it)
152
+ - When a success toast appears, does VoiceOver announce it?
153
+ 4. Press Cmd+F5 to stop VoiceOver.
154
+
155
+ You do not need to navigate the entire page. Spot-check the most important elements: forms, primary actions, status indicators, and notifications.
156
+
157
+ **Pass criteria:**
158
+ - Every form field announces its label
159
+ - Every button announces its purpose (not just "button")
160
+ - Errors and success messages are announced automatically
161
+ - Decorative images are silent
162
+
163
+ **Fail example:** "When I reach the Approve button with VoiceOver, it reads 'button'. It does not say what the button does or which application it refers to. I cannot use this without the mouse."
164
+
165
+ ---
166
+
167
+ ### Test 3 — Colour Contrast Check
168
+
169
+ **What you are testing:** Is the text readable for people with colour vision deficiencies or in low-contrast conditions?
170
+
171
+ **How to do it (Chrome DevTools):**
172
+
173
+ 1. Open Chrome DevTools (F12 or Cmd+Option+I).
174
+ 2. Click the Elements tab.
175
+ 3. Click the cursor icon (Inspect Element) and click on a piece of body text.
176
+ 4. In the Styles panel on the right, find the `color` property.
177
+ 5. Click the colour swatch next to the value.
178
+ 6. A colour picker opens. At the bottom, it shows the contrast ratio against the background.
179
+ 7. The ratio must be 4.5:1 or higher for normal text, 3:1 or higher for large text (18px bold or 24px regular).
180
+
181
+ **Also check:**
182
+ - Placeholder text in form fields (this commonly fails — placeholder text is often too light)
183
+ - Muted/secondary text
184
+ - Text on coloured backgrounds (badges, buttons, alerts)
185
+ - Link text within body copy
186
+
187
+ **Pass criteria:**
188
+ - Normal text: contrast ratio 4.5:1 or above
189
+ - Large text: contrast ratio 3:1 or above
190
+ - No information conveyed by colour alone
191
+
192
+ **Fail example:** "The 'Pending' status badge uses light grey text on a light grey background. DevTools shows a contrast ratio of 2.1:1. This fails WCAG AA."
193
+
194
+ ---
195
+
196
+ ### Test 4 — Form Error Test
197
+
198
+ **What you are testing:** Are error messages helpful and correctly announced?
199
+
200
+ **How to do it:**
201
+
202
+ 1. Find any form in the outcome you are testing.
203
+ 2. Submit it empty (or with invalid values where the form requires specific formats).
204
+ 3. Observe:
205
+ - Does an error message appear?
206
+ - Is it adjacent to the field that caused the error (not only at the top of the form)?
207
+ - Does the error message say specifically what is wrong? ("Enter a valid email address" not "Invalid input")
208
+ - Does the error message say how to fix it? ("Email addresses must include an @ symbol")
209
+ - Is the user's input preserved? (they should not have to re-type the whole form)
210
+ 4. Fix one field and resubmit. Does the error for that field disappear while errors on other fields remain?
211
+ 5. Fix all errors and submit. Does a clear success message appear?
212
+
213
+ **Pass criteria:**
214
+ - Error messages are specific and actionable
215
+ - Errors appear adjacent to the relevant field
216
+ - Input is preserved on error
217
+ - Success is clearly confirmed
218
+
219
+ **Fail example:** "When I submit the enrolment form without filling in the student's date of birth, a red banner appears at the top saying 'Please check your form'. There is no indication which field is wrong or what I need to enter. The form is cleared."
220
+
221
+ ---
222
+
223
+ ### Test 5 — Mobile Touch Target Test
224
+
225
+ **What you are testing:** Are interactive elements large enough to tap reliably on a touchscreen?
226
+
227
+ **How to do it:**
228
+
229
+ 1. Open Chrome DevTools and switch to responsive mode (the device icon, or Cmd+Shift+M).
230
+ 2. Set the viewport to 375px wide (iPhone SE).
231
+ 3. For each interactive element on the page, visually estimate whether it is at least 44x44 pixels.
232
+ 4. Pay particular attention to:
233
+ - Icon buttons (close, menu, edit, delete — these are commonly too small)
234
+ - Checkboxes and radio buttons
235
+ - Links within body copy
236
+ - Table action buttons that stack on mobile
237
+
238
+ To measure precisely: right-click on an element > Inspect. In DevTools, hover over the element in the Elements panel. The dimensions appear as a tooltip.
239
+
240
+ **Pass criteria:**
241
+ - All buttons, links, and form controls: minimum 44x44px touch target
242
+ - Spacing between targets: minimum 8px (targets should not be so close that an adjacent tap is easy to trigger accidentally)
243
+
244
+ **Fail example:** "On mobile, the delete button in the student list is an X icon that is 24x24 pixels. It is next to an edit icon also 24x24 pixels with 4px between them. Both fail the touch target requirement."
245
+
246
+ ---
247
+
248
+ ## Common Violations and Their Fixes
249
+
250
+ ### Violation: Icon-only button with no accessible label
251
+
252
+ **What it looks like:** A button that is just a trash can icon, no text.
253
+
254
+ **Why it fails:** A screen reader reads it as "button" with no further description.
255
+
256
+ **Fix in shadcn/Tailwind:**
257
+ ```tsx
258
+ <Button variant="ghost" size="icon" aria-label="Delete application from Sarah Chen">
259
+ <Trash2 className="h-4 w-4" />
260
+ </Button>
261
+ ```
262
+
263
+ ---
264
+
265
+ ### Violation: Form field with placeholder text but no label
266
+
267
+ **What it looks like:** An input that says "Enter your email" inside the field, with no label above it.
268
+
269
+ **Why it fails:** Placeholder text disappears when the user starts typing. Screen readers may not associate it correctly. Users with cognitive disabilities lose context mid-entry.
270
+
271
+ **Fix in shadcn/Tailwind:**
272
+ ```tsx
273
+ <div className="space-y-2">
274
+ <Label htmlFor="email">Email address</Label>
275
+ <Input id="email" type="email" placeholder="name@example.com" />
276
+ </div>
277
+ ```
278
+
279
+ ---
280
+
281
+ ### Violation: Error message not connected to field
282
+
283
+ **What it looks like:** An error paragraph that appears near the form but is not semantically linked to the field it describes.
284
+
285
+ **Why it fails:** Screen readers cannot associate the error with the field.
286
+
287
+ **Fix:**
288
+ ```tsx
289
+ <div className="space-y-2">
290
+ <Label htmlFor="email">Email address</Label>
291
+ <Input
292
+ id="email"
293
+ type="email"
294
+ aria-describedby="email-error"
295
+ aria-invalid={!!error}
296
+ />
297
+ {error && (
298
+ <p id="email-error" className="text-sm text-destructive">
299
+ {error}
300
+ </p>
301
+ )}
302
+ </div>
303
+ ```
304
+
305
+ ---
306
+
307
+ ### Violation: Colour as the only status indicator
308
+
309
+ **What it looks like:** A table where pending rows are grey, approved rows are green, and rejected rows are red — with no text labels.
310
+
311
+ **Why it fails:** Colour-blind users cannot distinguish red from green. Screen readers cannot convey colour.
312
+
313
+ **Fix:** Use shadcn `Badge` components with both colour and text:
314
+ ```tsx
315
+ <Badge variant={status === 'approved' ? 'default' : status === 'rejected' ? 'destructive' : 'secondary'}>
316
+ {status.charAt(0).toUpperCase() + status.slice(1)}
317
+ </Badge>
318
+ ```
319
+
320
+ ---
321
+
322
+ ### Violation: Focus not visible
323
+
324
+ **What it looks like:** Interactive elements that look the same whether focused or not.
325
+
326
+ **Why it fails:** Keyboard users cannot tell where they are on the page.
327
+
328
+ **Fix:** Never remove the `outline` without a replacement. shadcn components include `focus-visible:ring-2 focus-visible:ring-ring` by default. Do not remove these classes.
329
+
330
+ ---
331
+
332
+ ## The Reduce Motion Preference
333
+
334
+ Some users configure their operating system to reduce motion because they experience nausea, dizziness, or disorientation from animated interfaces. This is common in people with vestibular disorders, migraines, or certain neurological conditions.
335
+
336
+ The operating system exposes this preference as a CSS media query: `prefers-reduced-motion: reduce`.
337
+
338
+ Framer Motion reads this preference through its `useReducedMotion` hook. Use it on any animation that involves movement (translate, scale, rotate). Opacity transitions (fade in/out) are generally safe to keep even when motion is reduced.
339
+
340
+ **Pattern to use in every animated component:**
341
+ ```tsx
342
+ import { motion, useReducedMotion } from 'framer-motion';
343
+
344
+ function AnimatedList({ items }) {
345
+ const prefersReducedMotion = useReducedMotion();
346
+
347
+ const containerVariants = {
348
+ hidden: {},
349
+ visible: {
350
+ transition: {
351
+ staggerChildren: prefersReducedMotion ? 0 : 0.05,
352
+ },
353
+ },
354
+ };
355
+
356
+ const itemVariants = {
357
+ hidden: {
358
+ opacity: 0,
359
+ y: prefersReducedMotion ? 0 : 8,
360
+ },
361
+ visible: {
362
+ opacity: 1,
363
+ y: 0,
364
+ },
365
+ };
366
+
367
+ return (
368
+ <motion.ul variants={containerVariants} initial="hidden" animate="visible">
369
+ {items.map(item => (
370
+ <motion.li key={item.id} variants={itemVariants}>
371
+ {item.content}
372
+ </motion.li>
373
+ ))}
374
+ </motion.ul>
375
+ );
376
+ }
377
+ ```
378
+
379
+ When `prefersReducedMotion` is true, items still fade in (opacity transition) but do not slide (y transition is 0). The stagger is removed so all items appear simultaneously.
380
+
381
+ ---
382
+
383
+ ## Writing Accessibility Verification Steps into Outcome Documents
384
+
385
+ Every UI outcome should include accessibility verification steps alongside the standard walkthrough steps. These are not separate — they are part of the definition of done.
386
+
387
+ When writing or reviewing outcome documents, add this section after the walkthrough:
388
+
389
+ ```
390
+ ACCESSIBILITY VERIFICATION
391
+
392
+ Keyboard:
393
+ - [ ] Tab from page entry through all interactive elements in logical order
394
+ - [ ] [Specific action] completable by keyboard alone
395
+ - [ ] All dialogs trap and return focus correctly
396
+
397
+ Screen reader:
398
+ - [ ] All form fields announce their labels
399
+ - [ ] [Specific button] announces "[expected announcement]"
400
+ - [ ] Success/error states announced automatically
401
+
402
+ Colour contrast:
403
+ - [ ] Body text passes 4.5:1 on all backgrounds in this view
404
+ - [ ] Status badges (Pending/Approved/Rejected) pass 4.5:1
405
+
406
+ Mobile:
407
+ - [ ] All touch targets 44px minimum at 375px viewport
408
+ - [ ] [Specific element] does not overflow on mobile
409
+
410
+ Errors:
411
+ - [ ] Error messages are specific and adjacent to the field
412
+ - [ ] User input is preserved when validation fails
413
+ ```
414
+
415
+ These steps are run by the QA agent during the verification walkthrough and reported back in domain language.