import 'package:flutter/material.dart'; import 'lawheatmap_tokens.dart'; /// ThemeData assembly for the F∆I Law-Heatmap client. /// /// Dark mode is the default (consistent with fai_web's /// `color-scheme: dark`). Light mode falls back to the paper /// palette for printing/screenshot work. class LawHeatmapTheme { LawHeatmapTheme._(); static ThemeData dark() => _build(Brightness.dark); static ThemeData light() => _build(Brightness.light); static ThemeData _build(Brightness brightness) { final isDark = brightness == Brightness.dark; final canvas = isDark ? LawHeatmapColors.ink : LawHeatmapColors.paper; final surface = isDark ? LawHeatmapColors.inkRaised : LawHeatmapColors.paperRaised; final onSurface = isDark ? const Color(0xFFE9E7E2) : const Color(0xFF1A1B1E); final colorScheme = ColorScheme( brightness: brightness, primary: LawHeatmapColors.signal, onPrimary: LawHeatmapColors.ink, secondary: LawHeatmapColors.mute, onSecondary: onSurface, error: const Color(0xFFD8723A), onError: LawHeatmapColors.ink, surface: surface, onSurface: onSurface, ); final textTheme = _textTheme(onSurface); return ThemeData( useMaterial3: true, brightness: brightness, colorScheme: colorScheme, scaffoldBackgroundColor: canvas, canvasColor: canvas, fontFamily: LawHeatmapTypography.body, textTheme: textTheme, cardTheme: CardThemeData( color: surface, elevation: 0, margin: EdgeInsets.zero, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(LawHeatmapRadius.md), side: BorderSide(color: Color(0x24FFFFFF)), ), ), dividerTheme: DividerThemeData( color: onSurface.withValues(alpha: LawHeatmapColors.hairlineDarkOpacity), thickness: 1, space: 1, ), filledButtonTheme: FilledButtonThemeData( style: FilledButton.styleFrom( backgroundColor: LawHeatmapColors.signal, foregroundColor: LawHeatmapColors.ink, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(LawHeatmapRadius.sm), ), textStyle: textTheme.labelLarge, padding: const EdgeInsets.symmetric( horizontal: LawHeatmapSpace.lg, vertical: LawHeatmapSpace.md, ), ), ), ); } static TextTheme _textTheme(Color onSurface) { const display = LawHeatmapTypography.display; const body = LawHeatmapTypography.body; return TextTheme( displaySmall: TextStyle( fontFamily: display, fontSize: 28, fontWeight: FontWeight.w600, letterSpacing: -0.02 * 28, color: onSurface, ), headlineSmall: TextStyle( fontFamily: display, fontSize: 20, fontWeight: FontWeight.w600, letterSpacing: -0.02 * 20, color: onSurface, ), titleMedium: TextStyle( fontFamily: body, fontSize: 16, fontWeight: FontWeight.w500, color: onSurface, ), bodyLarge: TextStyle( fontFamily: body, fontSize: 14, height: 1.45, color: onSurface, ), labelLarge: TextStyle( fontFamily: body, fontSize: 13, fontWeight: FontWeight.w500, color: onSurface, ), labelSmall: TextStyle( fontFamily: body, fontSize: 11, fontWeight: FontWeight.w500, color: onSurface.withValues(alpha: 0.72), ), ); } /// Convenience: JetBrains-Mono variant of an existing style for /// technical content (ELI/CELEX, SHA-256, audit-event IDs). static TextStyle mono(TextStyle base) => base.copyWith(fontFamily: LawHeatmapTypography.mono); }