critical priority low complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

Every text element on the no-access screen passes WCAG 2.2 AA minimum 4.5:1 contrast ratio when measured against its direct background colour
Large text elements (≥18pt normal or ≥14pt bold) meet the relaxed 3:1 ratio threshold per WCAG 2.2 AA
All colour values are sourced exclusively from the design token system — no hardcoded hex or ARGB literals appear in the widget file
Each colour token usage is annotated with a single-line inline comment stating the token name and its computed contrast ratio against the background (e.g., // AppColors.textPrimary on AppColors.surfaceNeutral → 7.2:1)
The denial/no-access message body text achieves at least 4.5:1 against the screen background in both light and dark theme variants
Placeholder, hint, and secondary text elements that convey information meet the 4.5:1 threshold; purely decorative text is exempt and marked with a comment
The portal link text colour meets 4.5:1 in its default, focused, and visited states against the card or background surface
The logout button label meets 4.5:1 against the button fill colour
A manual spot-check using the Flutter DevTools accessibility panel shows zero contrast failures for the widget tree
No existing visual design or layout from dependent tasks is altered — only colour token assignments are changed

Technical Requirements

frameworks
Flutter
flutter_test
performance requirements
Colour token resolution must not introduce additional widget rebuilds — tokens are resolved once at build time
ui components
AppColors design tokens (contrast-safe-color-palette)
Text widgets for denial message, heading, body, and captions
TextButton / InkWell label for portal link
ElevatedButton / OutlinedButton label for logout

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Start by listing every Text, RichText, and SelectableText widget in the no-access-screen-widget tree. Cross-reference each against the design token palette using an online contrast checker (e.g., WebAIM) with the actual token hex values. For any failure, replace the colour assignment with the nearest passing token — prefer AppColors.textPrimary (highest contrast) for body copy and AppColors.textSecondary only where it meets the threshold. Avoid using Opacity wrappers to adjust colour — this reduces effective contrast without changing the token value and is harder to audit.

If a token does not exist that meets the threshold for a given background, escalate to the design system owner before inventing a new value. The contrast requirement applies to both light and dark ThemeData — use Theme.of(context) branches if needed. Document the final contrast ratio next to each token reference so future developers can verify at a glance without re-running the audit.

Testing Requirements

Write or extend the existing flutter_test widget test suite for 049-no-access-screen-widget. Add a test group 'contrast_audit' containing at least: (1) a test that instantiates the widget in light theme and asserts that all Text widgets use only approved design token colours (check via widget.style.color identity against AppColors constants); (2) a parallel test for dark theme. Additionally run meetsGuideline(textContrastGuideline) from package:flutter_test/flutter_test.dart against the pumped widget in both themes.

Golden tests from task-012 will provide regression coverage — ensure contrast fixes are visible in the golden baseline.

Component
No-Access Screen
ui low
Epic Risks (2)
medium impact medium prob technical

Flutter's live region (SemanticsProperties.liveRegion) announcement may be delayed or swallowed by the OS accessibility engine if the Semantics tree is not fully built when the screen mounts, causing screen-reader users to miss the denial announcement.

Mitigation & Contingency

Mitigation: Trigger the live region announcement from a post-frame callback (WidgetsBinding.addPostFrameCallback) to ensure the Semantics tree is committed before the announcement fires. Test on both VoiceOver (iOS) and TalkBack (Android) physical devices.

Contingency: If live region timing is unreliable, fall back to using SemanticsService.announce() directly in the initState post-frame callback, which provides more deterministic announcement timing.

low impact low prob scope

The organisation logo may fail to load (network error, missing asset) leaving a broken image in an otherwise functional screen, degrading the professional appearance and potentially confusing users.

Mitigation & Contingency

Mitigation: Wrap the logo widget in an error builder that renders a styled fallback (organisation name text or a generic icon) when the logo asset or network image fails to load.

Contingency: If logo loading is persistently unreliable across organisations, remove the logo from the no-access screen entirely in favour of a text-only header using the organisation's display name from the design token system.