import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; // --- Neo-brutalism palette (mirrors web app/globals.css + Tailwind usage) --- const kBrutalBlack = Color(0xFF000000); // borders, shadows, body text const kBrutalYellow = Color(0xFFFFD21E); // warning / accent const kBrutalWhite = Color(0xFFFFFFFF); // card / unselected button const kBrutalCream = Color(0xFFF8FBFF); // page background — matches web #F8FBFF const kBrutalRed = Color(0xFFF43F5E); // error / wrong answer — matches web #F43F5E const kBrutalGreen = Color(0xFF22C55E); // correct answer const kBrutalBlue = Color(0xFF3B82F6); // secondary accent (web blue) const kBrutalTeal = Color(0xFF0EA5A4); // primary brand (web teal) const kBrutalMuted = Color(0xFF777777); // secondary text — matches web #777777 const kBrutalSlate = Color(0xFF3C3C3C); // body text — matches web #3C3C3C // --- Back-compat aliases (old screens still reference these names) --- const kPrimary = kBrutalTeal; // teal is the primary brand color (web) const kPrimaryShadow = kBrutalBlack; const kSecondary = kBrutalBlue; const kSecondaryShadow = kBrutalBlack; const kWarning = kBrutalYellow; const kDanger = kBrutalRed; const kDangerShadow = kBrutalBlack; const kForeground = kBrutalSlate; const kMuted = kBrutalMuted; const kBackground = kBrutalCream; const kCard = kBrutalWhite; const kCardFeature = kBrutalWhite; const kBorder = kBrutalBlack; // Universal corner radius — neo-brutal: small, never soft. const double kBrutalRadius = 4; TextStyle brutalFont({ double? fontSize, FontWeight fontWeight = FontWeight.w800, Color? color, double? height, double? letterSpacing, TextDecoration? decoration, FontStyle? fontStyle, }) { return GoogleFonts.almarai( fontSize: fontSize, fontWeight: fontWeight, color: color, height: height, letterSpacing: letterSpacing, decoration: decoration, fontStyle: fontStyle, ); } ThemeData buildTheme() { final textTheme = GoogleFonts.almaraiTextTheme( ThemeData.light().textTheme.apply( bodyColor: kBrutalSlate, displayColor: kBrutalBlack, ), ); return ThemeData( useMaterial3: true, brightness: Brightness.light, scaffoldBackgroundColor: kBrutalCream, colorScheme: const ColorScheme.light( primary: kBrutalTeal, onPrimary: kBrutalWhite, secondary: kBrutalBlue, onSecondary: kBrutalWhite, surface: kBrutalWhite, onSurface: kBrutalSlate, outline: kBrutalBlack, error: kBrutalRed, onError: kBrutalWhite, ), textTheme: textTheme, appBarTheme: AppBarTheme( backgroundColor: kBrutalCream, foregroundColor: kBrutalBlack, elevation: 0, centerTitle: false, surfaceTintColor: Colors.transparent, systemOverlayStyle: SystemUiOverlayStyle.dark, titleTextStyle: GoogleFonts.almarai( color: kBrutalBlack, fontWeight: FontWeight.w900, fontSize: 20, ), iconTheme: const IconThemeData(color: kBrutalBlack), ), filledButtonTheme: FilledButtonThemeData( style: FilledButton.styleFrom( backgroundColor: kBrutalTeal, foregroundColor: kBrutalWhite, disabledBackgroundColor: kBrutalWhite, disabledForegroundColor: kBrutalMuted, minimumSize: const Size(0, 52), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kBrutalRadius), side: const BorderSide(color: kBrutalBlack, width: 2), ), textStyle: GoogleFonts.almarai(fontWeight: FontWeight.w900, fontSize: 15), elevation: 0, ), ), outlinedButtonTheme: OutlinedButtonThemeData( style: OutlinedButton.styleFrom( foregroundColor: kBrutalBlack, backgroundColor: kBrutalWhite, minimumSize: const Size(0, 52), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kBrutalRadius), side: const BorderSide(color: kBrutalBlack, width: 2), ), textStyle: GoogleFonts.almarai(fontWeight: FontWeight.w900, fontSize: 15), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: kBrutalBlack, textStyle: GoogleFonts.almarai(fontWeight: FontWeight.w900), ), ), cardTheme: CardThemeData( color: kBrutalWhite, elevation: 0, surfaceTintColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kBrutalRadius), side: const BorderSide(color: kBrutalBlack, width: 2), ), ), navigationBarTheme: NavigationBarThemeData( height: 72, backgroundColor: kBrutalWhite, indicatorColor: kBrutalTeal, surfaceTintColor: Colors.transparent, indicatorShape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kBrutalRadius), side: const BorderSide(color: kBrutalBlack, width: 2), ), iconTheme: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.selected)) { return const IconThemeData(color: kBrutalWhite); } return const IconThemeData(color: kBrutalBlack); }), labelTextStyle: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.selected)) { return GoogleFonts.almarai(color: kBrutalBlack, fontSize: 12, fontWeight: FontWeight.w900); } return GoogleFonts.almarai(color: kBrutalMuted, fontSize: 12, fontWeight: FontWeight.w800); }), ), tabBarTheme: TabBarThemeData( labelColor: kBrutalBlack, unselectedLabelColor: kBrutalMuted, indicatorSize: TabBarIndicatorSize.tab, labelStyle: GoogleFonts.almarai(fontWeight: FontWeight.w900), unselectedLabelStyle: GoogleFonts.almarai(fontWeight: FontWeight.w800), ), dividerColor: kBrutalBlack, inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: kBrutalWhite, contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), border: OutlineInputBorder( borderRadius: BorderRadius.circular(kBrutalRadius), borderSide: const BorderSide(color: kBrutalBlack, width: 2), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(kBrutalRadius), borderSide: const BorderSide(color: kBrutalBlack, width: 2), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(kBrutalRadius), borderSide: const BorderSide(color: kBrutalBlue, width: 3), ), hintStyle: GoogleFonts.almarai(color: kBrutalMuted, fontWeight: FontWeight.w700), labelStyle: GoogleFonts.almarai(color: kBrutalMuted, fontWeight: FontWeight.w800), ), chipTheme: ChipThemeData( backgroundColor: kBrutalWhite, selectedColor: kBrutalTeal, disabledColor: kBrutalWhite, labelStyle: GoogleFonts.almarai(color: kBrutalBlack, fontWeight: FontWeight.w900), secondaryLabelStyle: GoogleFonts.almarai(color: kBrutalWhite, fontWeight: FontWeight.w900), side: const BorderSide(color: kBrutalBlack, width: 2), shape: const StadiumBorder(side: BorderSide(color: kBrutalBlack, width: 2)), ), snackBarTheme: SnackBarThemeData( backgroundColor: kBrutalBlack, contentTextStyle: GoogleFonts.almarai(color: kBrutalWhite, fontWeight: FontWeight.w800), behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kBrutalRadius), side: const BorderSide(color: kBrutalBlack, width: 2), ), ), dialogTheme: DialogThemeData( backgroundColor: kBrutalWhite, surfaceTintColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kBrutalRadius), side: const BorderSide(color: kBrutalBlack, width: 3), ), titleTextStyle: GoogleFonts.almarai(color: kBrutalBlack, fontSize: 20, fontWeight: FontWeight.w900), contentTextStyle: GoogleFonts.almarai(color: kBrutalSlate, fontWeight: FontWeight.w800), ), bottomSheetTheme: const BottomSheetThemeData( backgroundColor: kBrutalWhite, surfaceTintColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(kBrutalRadius)), side: BorderSide(color: kBrutalBlack, width: 3), ), ), ); } // --- Decorations --- /// Neo-brutal card: thick black border + hard black offset shadow. /// [offset] shrinks to indicate a pressed state (web: translate-1). BoxDecoration brutalCard({ Color color = kBrutalWhite, double offset = 4, double radius = kBrutalRadius, Color borderColor = kBrutalBlack, double borderWidth = 2, }) { return BoxDecoration( color: color, borderRadius: BorderRadius.circular(radius), border: Border.all(color: borderColor, width: borderWidth), boxShadow: [ BoxShadow(color: kBrutalBlack, offset: Offset(offset, offset), blurRadius: 0), ], ); } /// Pressed/active variant — collapses to a 1px shadow, yellow fill by default. BoxDecoration brutalCardPressed({ Color color = kBrutalYellow, double radius = kBrutalRadius, }) => brutalCard(color: color, offset: 1, radius: radius); /// Back-compat alias — existing screens call this. Maps to the brutal version. BoxDecoration duoCardDecoration({Color color = kBrutalWhite}) => brutalCard(color: color);