Accessibility

Accessibility is treated as a correctness requirement here, not a finishing pass. This is what the app does and how to verify it — a checklist you can copy into your own project.

VoiceOver

Dynamic Type

All text uses DesignSystem.Font.*, which maps to the system text styles (.body, .headline, .title, …) and scales with the user’s preferred size automatically. Poster dimensions are intentionally fixed — they are decorative frames, and the text beside them grows independently.

Reduce Motion

The only continuous animation in the app is the skeleton shimmer. SkeletonView reads @Environment(\.accessibilityReduceMotion) and, when it is on, renders a static dimmed block instead of the pulsing phaseAnimator. There are no repeatForever animations anywhere — that is both a Reduce Motion courtesy and the fix for a real AsyncRenderer crash (see the commit history).

Reduce Transparency

The trailer’s close button is the one place a material (.ultraThinMaterial) is used directly. It reads @Environment(\.accessibilityReduceTransparency) and swaps to an opaque DesignSystem.Color.cardBackground when the setting is on. The system navigation and tab bars handle their own translucency.

Hit targets

Interactive controls meet the 44×44 pt minimum. The trailer close button is sized to DesignSystem.Size.Button.minimumTapTarget explicitly; list rows and cards are comfortably larger.

Localization

Accessibility strings are localized like every other string — hints, labels, and the loading announcement live in the per-module String Catalogs in English and German, never hard-coded. Price and date formatting is locale-aware through FormatStyle.

How to verify