critical priority medium complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

All 15 Material 3 TextTheme roles (displayLarge, displayMedium, displaySmall, headlineLarge, headlineMedium, headlineSmall, titleLarge, titleMedium, titleSmall, bodyLarge, bodyMedium, bodySmall, labelLarge, labelMedium, labelSmall) are explicitly assigned — none left as TextTheme defaults
Every TextStyle's fontSize is the product of the token base size multiplied by the accessibility_preferences font_scale_factor — no literal font size values in the builder
No TextStyle has a fontSize below the manifest minimum (bodySmall floor: 12 sp before scaling)
No TextStyle has a FontWeight below the manifest minimum (labelSmall floor: FontWeight.w500)
Thin/italic font variants (FontWeight.w100, FontWeight.w200, FontStyle.italic) are excluded from all roles per accessibility requirements for NHF/Blindeforbundet users
Applying a font_scale_factor of 1.0, 1.3, and 1.5 each produce a coherent, non-overlapping type scale where displayLarge > displayMedium > ... > labelSmall
TextTheme is applied to both ThemeData (light) and ThemeData (dark) — colour inheritance from ColorScheme.onSurface is verified
VoiceOver/TalkBack semantic labels are not affected by the type scale change — confirmed via widget test with Semantics finder

Technical Requirements

frameworks
Flutter
Material 3
Riverpod
apis
Flutter TextTheme API
Flutter TextStyle API
DesignTokenProvider interface (internal)
Dynamic type scale service (internal)
data models
accessibility_preferences
performance requirements
Text theme assembly must be synchronous
Font scale changes from accessibility_preferences must propagate via Riverpod provider invalidation — no full app restart required
security requirements
font_scale_factor read from accessibility_preferences must be validated to be within the range [0.85, 2.0] before multiplication to prevent layout overflow attacks
ui components
ThemeData.textTheme
ThemeData.primaryTextTheme

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Integration Task

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

Implementation Notes

Create a TextThemeAssembler class with a single build(TypeScaleOutput scale, double fontScaleFactor) method returning a TextTheme. The TypeScaleOutput (from the dynamic type scale service) should provide one TextStyle per role before scaling; the assembler applies fontScaleFactor and enforces floor constraints via a clampTextStyle helper. Never call copyWith on Flutter's default M3 TextTheme — always construct from scratch to avoid inheriting stale defaults. For Blindeforbundet users, ensure the minimum bodySmall size of 14 sp (post-scale) aligns with WCAG 1.4.4 Resize Text.

The font_scale_factor from accessibility_preferences maps to Flutter's textScaleFactor concept but is applied at theme build time rather than at MediaQuery level to maintain consistent layout.

Testing Requirements

Unit tests (flutter_test): (1) all 15 roles are non-null, (2) font sizes scale linearly with font_scale_factor, (3) no style falls below minimum size or weight, (4) italic/thin weights absent from all roles. Widget test: render a scaffold with all 15 text roles applied and verify Semantics tree is intact (no semantic label is empty string). Golden test: snapshot the type scale at scale factors 1.0 and 1.5 for regression detection. Aim for 90% coverage on the text theme assembler 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.