high priority low complexity testing pending frontend specialist Tier 5

Acceptance Criteria

All text and badge elements across the four components achieve a minimum 4.5:1 contrast ratio against their background as measured by a colour contrast analyser
Every interactive element (toggle, shortcut, dialog buttons) has a minimum touch target of 44×44 dp confirmed via Flutter layout inspector
Focus order in PauseConfirmationDialog follows reading order (consequence text → reason field → cancel → confirm) verified by TalkBack on Android and VoiceOver on iOS
A live-region (SemanticsProperties.liveRegion or equivalent) fires an announcement when BLoC emits a state change on PauseReactivateToggle and PauseStatusBanner
All semantic labels on icon-only buttons and badges are non-empty and descriptive (e.g., 'Reactivate mentor')
Content remains fully readable and not clipped at 200% system font scale on a 360dp-wide device
No violations remain unfixed at PR merge — any accepted trade-off must be documented with rationale in the PR description
flutter_accessibility_lint runs in CI with zero new warnings introduced by these four components
Manual TalkBack walkthrough documented with screen recording or written test script in the PR

Technical Requirements

frameworks
Flutter
flutter_test
flutter_accessibility_lint
ui components
PauseReactivateToggle
PauseConfirmationDialog
PauseStatusBanner
PauseMentorStatusBadge

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Use Flutter's Semantics widget to wrap elements that need explicit live-region behaviour: Semantics(liveRegion: true, child: ...). For the 44dp touch target requirement, wrap small elements in a SizedBox with constraints or use Material's minimumSize in ButtonStyle. For focus order in the dialog, use FocusTraversalGroup with OrderedTraversalPolicy to enforce the correct sequence. Contrast issues are most common on grey-on-grey badges — switch to design token colours from the project's token system rather than hard-coding hex values.

Document each violation found during the audit as a bullet in the PR, including before/after contrast ratios and the fix applied. This task directly addresses the universell utforming requirement from the NHF and Blindeforbundet workshops, which identified screen reader support and cognitive accessibility as critical.

Testing Requirements

Automated: run flutter_accessibility_lint as part of the existing lint step in CI. Additionally, write one semantics-level widget test per component using tester.getSemantics() and SemanticsNode assertions to verify label, liveRegion, and isFocusable properties.

Manual: perform a TalkBack walkthrough on an Android emulator (API 31+) and a VoiceOver walkthrough on an iOS simulator (iOS 16+), navigating through the pause/reactivate flow end-to-end. Test dynamic type by setting system font scale to 2.0 in device settings and verifying no overflow or clipped content.

Component
Pause Confirmation Dialog
ui low
Epic Risks (3)
medium impact medium prob technical

PauseConfirmationDialog must meet WCAG 2.2 AA focus trap requirements: when the dialog opens, focus must move to the first interactive element; when it closes, focus must return to the triggering toggle. Flutter's default showDialog does not always guarantee correct focus restoration on Android, which could trap screen-reader users.

Mitigation & Contingency

Mitigation: Use a custom modal implementation wrapping Flutter's Dialog with explicit FocusScope management and test with TalkBack on Android and VoiceOver on iOS during development, not just in final QA. Reference the accessible-modal-sheet pattern already used elsewhere in the codebase.

Contingency: If full WCAG focus management cannot be achieved within the sprint, ship the feature with a documented accessibility defect and schedule a dedicated accessibility remediation task. Communicate the known gap to the accessibility stakeholder at HLF/NHF.

low impact medium prob technical

If the user taps the PauseReactivateToggle rapidly before the BLoC emits a loading state, multiple PauseMentorEvents could be added to the BLoC stream, resulting in duplicate service calls and inconsistent UI state (toggle flickering between states).

Mitigation & Contingency

Mitigation: Disable the toggle widget immediately on first tap by emitting MentorStatusLoading synchronously before the async service call begins. Use BLoC's event transformer with droppable() to discard subsequent events while a transition is in progress.

Contingency: If BLoC event deduplication is not sufficient, add a debounce at the widget level (300 ms) and a server-side idempotency check in MentorStatusService that no-ops if the requested transition is already in progress.

low impact low prob security

PauseStatusBanner must conditionally render the reactivate shortcut only for users with coordinator permission. If the permission check relies on a stale role state in the Riverpod provider, a peer mentor could briefly see a reactivate action they are not authorised to use, which could cause a confusing permission-denied error if tapped.

Mitigation & Contingency

Mitigation: Source the permission check directly from the role-resolution Riverpod provider (which is kept in sync with Supabase auth) rather than from local component state. Add a widget test asserting the shortcut is absent when the user role is peer_mentor.

Contingency: If the shortcut is accidentally shown to an unauthorised user, the underlying MentorStatusService enforces role validation server-side, so the worst outcome is a visible error message rather than an actual unauthorised state change.