critical priority medium complexity frontend pending frontend specialist Tier 1

Acceptance Criteria

ColorScheme.fromSeed() or ColorScheme constructor is called exclusively with Color values sourced from DesignTokenProvider — zero hardcoded hex literals exist inside the builder class
Both ColorScheme.light and ColorScheme.dark variants are produced from a single palette input without duplicating mapping logic
All Material 3 ColorScheme roles (primary, onPrimary, primaryContainer, onPrimaryContainer, secondary, onSecondary, secondaryContainer, onSecondaryContainer, tertiary, onTertiary, tertiaryContainer, onTertiaryContainer, error, onError, errorContainer, onErrorContainer, surface, onSurface, surfaceVariant, onSurfaceVariant, outline, outlineVariant, shadow, scrim, inverseSurface, onInverseSurface, inversePrimary) are explicitly mapped — no role left at Material default
Passing a palette with a primary color that fails WCAG 2.2 AA (contrast ratio < 4.5:1 against its on-color) throws a ContrastAssertionError in debug mode
Substituting any token value in the palette produces a deterministic, fully updated ColorScheme without side effects
Unit tests confirm the assembled ColorScheme matches the expected Material 3 tonal palette derivation for the NHF, Blindeforbundet, HLF, and Barnekreftforeningen seed colors
No Color value is derived from dart:ui Color constructors with literal integers — all colors pass through the palette abstraction layer

Technical Requirements

frameworks
Flutter
Material 3 (useMaterial3: true)
Riverpod
apis
Flutter ColorScheme API
Flutter ThemeData API
DesignTokenProvider interface (internal)
data models
accessibility_preferences
performance requirements
ColorScheme assembly must complete synchronously — no async operations in the builder
Rebuilding the ColorScheme when the theme notifier changes must not trigger full widget tree rebuilds beyond MaterialApp
security requirements
No organisation brand colors or palette data stored outside the token provider — no global mutable state
ui components
MaterialApp theme/darkTheme props consumer

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Integration Task

Handles integration between different epics or system components. Requires coordination across multiple development streams.

Implementation Notes

Use ColorScheme.fromSeed(seedColor: tokenProvider.primarySeed, brightness: Brightness.light/dark) as the baseline and then override individual roles with surface and container tokens from the palette. Avoid ColorScheme.fromSwatch — it is a pre-M3 API. Store the mapping in a dedicated ColorSchemeAssembler class that takes a ContrastSafePalette (output of task-001) and returns a record or sealed class containing both variants. Keep the mapping table as a pure function with no side effects to make it trivially testable.

The accessibility_preferences entity's contrast_mode field (standard / high / inverted) must be threaded through as a parameter so the assembler can select the appropriate palette variant produced upstream.

Testing Requirements

Unit tests (flutter_test) covering: (1) light and dark ColorScheme produced from the same palette input are structurally correct, (2) all 30 ColorScheme roles are non-null and sourced from tokens, (3) swapping the primary token updates all derived tonal roles, (4) a low-contrast palette triggers ContrastAssertionError in debug mode, (5) each of the four org seed colors (NHF, Blindeforbundet, HLF, Barnekreftforeningen) produces a valid scheme. No widget tests required at this layer — pure Dart unit tests suffice. Minimum 90% line coverage on the color scheme assembly class.

Component
Accessible Theme Builder
infrastructure medium
Epic Risks (2)
high impact low prob scope

One or more of the four partner organisations may supply brand primary colors that cannot be paired with any standard foreground at 4.5:1 contrast (for example, a mid-range hue that is too light for dark text and too dark for white text). Rejecting these colors programmatically could cause a political dispute with the organisation and delay the feature.

Mitigation & Contingency

Mitigation: Before implementation begins, run all four organisations' existing brand primary colors through the contrast-ratio-validator against both white (#FFFFFF) and a near-black (#1A1A1A). Share the results with each organisation's contact person ahead of the theme builder sprint so any problematic colors can be adjusted collaboratively with advance notice.

Contingency: If an organisation insists on a non-compliant brand color, produce a compliant near-match (lightened or darkened along the hue's luminance axis) and present both options with contrast ratio evidence. Document the adjusted token in the manifest with an explicit note that the original brand color was non-compliant, and obtain written sign-off from the organisation.

medium impact medium prob scope

Flutter's ThemeData contains over 30 component theme properties. If the theme-builder only addresses the most common ones (Button, InputDecoration, Card) and leaves others at Flutter defaults, downstream feature teams may unknowingly use default-themed widgets that do not meet sizing or contrast requirements.

Mitigation & Contingency

Mitigation: Produce a full inventory of all ThemeData component theme properties and map each to either a token-driven override or an explicit pass-through decision documented in the theme builder code. Prioritise the inventory by frequency of use in the existing codebase (identified via Grep). Include a check in the CI lint runner that flags widgets using Flutter default component themes not covered by the theme builder.

Contingency: If the full inventory scope exceeds the sprint budget, ship with the highest-frequency components covered and add a tracked backlog item for each uncovered component theme, pairing with a temporary lint suppression comment that includes the backlog reference.