critical priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

A `AppColorTokens` class extending `ThemeExtension<AppColorTokens>` is defined in `lib/core/theme/app_color_tokens.dart`
The class exposes named fields for all four certification status colors: `statusActive`, `statusExpiringSoon`, `statusExpired`, `statusPaused` (both foreground and background variants for each)
Surface tokens are present: `surfacePrimary`, `surfaceSecondary`, `surfaceElevated`, `surfaceOverlay`
Text hierarchy tokens are present: `textPrimary`, `textSecondary`, `textTertiary`, `textDisabled`, `textOnAccent`
Interactive element tokens are present: `interactivePrimary`, `interactivePrimaryHover`, `interactiveDestructive`, `interactiveDisabled`
Both a `light` and a `dark` static factory/constructor exist, each providing distinct hex values appropriate for that mode
`copyWith` and `lerp` are correctly implemented as required by `ThemeExtension` contract
All color values pass WCAG 2.2 AA contrast ratio (4.5:1 for normal text, 3:1 for large text) verified by a contrast-check utility or documented table
No raw hex literals appear anywhere outside `AppColorTokens` — all downstream code references token fields only

Technical Requirements

frameworks
Flutter
data models
MentorStatus (consumed for status color mapping)
performance requirements
Color token lookup is O(1) field access — no runtime computation or map lookup
ui components
ThemeExtension<AppColorTokens>

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Extend `ThemeExtension` and override `copyWith` and `lerp`. For `lerp`, use `Color.lerp` for each field. Define `static const AppColorTokens light = AppColorTokens(...)` and `static const AppColorTokens dark = AppColorTokens(...)`. Certification status colors should follow a traffic-light-adjacent palette that avoids pure red/green to remain accessible for color-blind users: consider amber for `expiringSoon`, a desaturated slate for `paused`, a muted crimson for `expired`, and a calm teal/blue for `active`.

Document the hex values and their WCAG contrast ratios in a inline comment block for future designers. This class must have zero Flutter widget dependencies so it can be unit-tested without `pumpWidget`.

Testing Requirements

Write widget tests using `flutter_test`. Test 1: `AppColorTokens.light` and `AppColorTokens.dark` are non-null and have distinct values for at least one token (e.g., `surfacePrimary`). Test 2: `lerp` between light and dark at `t=0.5` produces intermediate values without throwing. Test 3: `copyWith` correctly overrides a single field while preserving all others.

Optionally, a contrast-ratio helper test asserting that each status foreground/background pair meets WCAG AA 4.5:1.

Component
Design Token Theme
infrastructure low
Epic Risks (2)
high impact medium prob integration

The design token theme extension may conflict with existing ThemeData extensions already registered in the app, causing runtime assertion errors or token resolution failures across all screens that consume the tokens.

Mitigation & Contingency

Mitigation: Audit all existing ThemeData extensions before implementation. Use a unique extension key namespace and add integration tests that instantiate the combined theme in a test app harness.

Contingency: If conflicts arise, isolate design tokens behind a dedicated provider singleton (Riverpod) rather than a ThemeData extension, updating all consuming widgets to read from the provider instead.

medium impact medium prob scope

The 30-day warning threshold for expiring_soon status may differ between HLF's stated requirement in workshops (60 days mentioned in user stories) and the 30-day value in component documentation, causing disagreement during acceptance testing.

Mitigation & Contingency

Mitigation: Explicitly confirm the threshold value with HLF stakeholder before implementation. Make the threshold a named constant (kCertificationWarnDays) so it can be updated without logic changes.

Contingency: If stakeholder confirms 60 days post-implementation, update the constant and re-run the unit test suite — no architectural change required.