critical priority medium complexity frontend pending frontend specialist Tier 6

Acceptance Criteria

Every interactive element on OrgSelectionScreen and MultiOrgContextSwitcher has a non-empty semanticsLabel and correct SemanticsRole (button, header, image, etc.)
All tappable widgets (org cards, buttons, close icons) have a minimum touch target of 44×44 logical pixels enforced via SizedBox or Semantics minTouchTargetSize
Text contrast ratio ≥ 4.5:1 verified against design tokens for normal text; UI component borders and icons achieve ≥ 3:1 contrast on all org-branded backgrounds
Focus traversal order on both screens is linear (top-to-bottom, left-to-right) and matches visual layout; no focus traps exist except inside modal dialogs
TalkBack (Android) announces: org name, whether org is currently active, loading spinner state ('Loading organizations'), and inline error messages without requiring user navigation
VoiceOver (iOS) announces the same content as TalkBack; live regions (SemanticsProperties.liveRegion) are applied to loading and error widgets
Switch-access traversal covers all interactive elements in correct order with no unreachable elements
Focus indicator is visible on all interactive elements when using keyboard or switch access (FocusNode with custom decoration or Flutter default highlight visible)
Loading state disables interactive elements and announces 'Loading' to screen readers via Semantics.liveRegion
Error states announce the full error message text to screen readers immediately upon appearance
Code comments document the semantic structure of each screen (which widgets have custom Semantics wrappers and why)
No accessibility regressions introduced in any previously accessible widget on either screen

Technical Requirements

frameworks
Flutter
flutter_test
data models
Organization
UserOrganizationContext
performance requirements
Semantics tree build must not add more than 5ms to frame render time on mid-range Android devices
Live region announcements must fire within one frame of state change
security requirements
semanticsLabel must not expose internal org IDs or sensitive metadata — display only user-facing org name
ui components
Semantics wrapper widget on all org cards
ExcludeSemantics wrapper on decorative icons
MergeSemantics on composite card widgets
SizedBox(width: 44, height: 44) minimum touch target enforcer
Focus-aware highlight border on focusable elements
LiveRegion Semantics on loading and error containers

Execution Context

Execution Tier
Tier 6

Tier 6 - 158 tasks

Can start after Tier 5 completes

Implementation Notes

Use Flutter's built-in Semantics widget as the primary tool — avoid third-party accessibility packages. Wrap composite org cards with MergeSemantics so TalkBack reads them as a single item (org name + active badge) rather than several fragments. Apply ExcludeSemantics to purely decorative elements (dividers, background shapes). For loading spinners, wrap with Semantics(liveRegion: true, label: 'Loading organizations') so VoiceOver/TalkBack announces state changes without user interaction.

Contrast ratios must be verified programmatically against the project's design token colors — use the WCAG 2.1 relative luminance formula or the accessibility_tools package in debug mode. Touch targets: prefer wrapping with a SizedBox(width: 48, height: 48) rather than increasing visual padding — use Semantics(explicitChildNodes: false) to keep the merged label. For the MultiOrgContextSwitcher confirmation dialog, ensure focus moves into the dialog on open and returns to the trigger element on close. Document each Semantics wrapper with a comment explaining the semantic role and label strategy.

This is a critical requirement per the workshop findings: all three organizations (NHF, Blindeforbundet, HLF) have users with motor, cognitive, and sensory disabilities, and screen reader support was explicitly requested.

Testing Requirements

Write widget tests using flutter_test that: (1) pump OrgSelectionScreen and assert Semantics tree contains expected labels for each org card using tester.getSemantics(); (2) verify touch target sizes by checking RenderBox constraints are ≥ 44×44; (3) simulate loading state and assert live region Semantics node fires with correct label; (4) simulate error state and assert error message appears in Semantics tree; (5) verify focus order by tabbing through all focusable elements and asserting sequence. Run Flutter accessibility checker (SemanticsController.ensureSemantics) in all widget tests. Manual testing required on real TalkBack (Android 12+) and VoiceOver (iOS 16+) devices before marking complete. Document manual test results in PR description.

Epic Risks (2)
low impact high prob technical

OrgSelectionScreen and OrgContextSwitcher render partner-specific logos, colors, and text from dynamic data. Golden tests (pixel-comparison screenshots) will fail whenever branding assets are updated in the backend, causing CI failures that block unrelated PRs and eroding developer trust in the test suite.

Mitigation & Contingency

Mitigation: Use fixture-based golden tests with static mock Organization models containing embedded test assets rather than network-fetched assets. Separate branding asset acceptance tests into a dedicated CI job that only runs on branding-related PRs and is maintained by the design team.

Contingency: If golden test maintenance overhead becomes excessive, replace pixel-comparison goldens with semantic widget tests that assert widget tree structure and key property values, reserving golden tests for only the most stable, design-critical elements.

high impact medium prob scope

Several partner organizations (especially Blindeforbundet) have users who rely entirely on VoiceOver or TalkBack. Complex branded card layouts with overlaid logos, names, and selection states are notoriously difficult to make fully accessible; missing semantics or incorrect focus order could make the selection screen completely unusable for screen reader users before launch.

Mitigation & Contingency

Mitigation: Involve an accessibility specialist in the design review before any widget implementation begins. Use Flutter's Semantics widget with explicit label, hint, and button role on OrgCardWidget. Conduct manual screen reader testing on both iOS (VoiceOver) and Android (TalkBack) for every sprint that touches these screens, not just before release.

Contingency: If full WCAG compliance cannot be achieved within the sprint, implement a simplified text-list fallback mode that activates when the system detects an active screen reader, presenting orgs as plain accessible list tiles instead of the branded card layout.