import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; // ── Colour constants ────────────────────────────────────────────────────────── const _darkBackground = Color(0xFF0F0F14); const _darkSurface = Color(0xFF16161F); const _darkSurfaceVar = Color(0xFF1A1A24); const _darkPrimary = Color(0xFF7C3AED); const _darkOnSurface = Color(0xFFE4E4F0); const _darkOnSurfaceVar = Color(0xFF8888A8); const _darkOutline = Color(0xFF2A2A3A); const _lightBackground = Color(0xFFF5F5FB); const _lightSurface = Color(0xFFFFFFFF); const _lightSurfaceVar = Color(0xFFF0F0F8); const _lightPrimary = Color(0xFF7C3AED); const _lightOnSurface = Color(0xFF1A1A1A); const _lightOnSurfaceVar = Color(0xFF666666); const _lightOutline = Color(0xFFDDDDE8); // ── Typography ───────────────────────────────────────────────────────────────── TextTheme _buildTextTheme(TextTheme base) { final fraunces = GoogleFonts.frauncesTextTheme(base); return base.copyWith( // Headings / titles use Fraunces headlineLarge: fraunces.headlineLarge, headlineMedium: fraunces.headlineMedium, headlineSmall: fraunces.headlineSmall, titleLarge: fraunces.titleLarge, titleMedium: fraunces.titleMedium, // Body / labels remain system default ); } // ── Themes ───────────────────────────────────────────────────────────────────── ThemeData fabledDarkTheme() { final cs = ColorScheme( brightness: Brightness.dark, primary: _darkPrimary, onPrimary: Colors.white, primaryContainer: const Color(0xFF5B21B6), onPrimaryContainer: _darkOnSurface, secondary: _darkPrimary, onSecondary: Colors.white, secondaryContainer: _darkSurfaceVar, onSecondaryContainer: _darkOnSurface, tertiary: _darkPrimary, onTertiary: Colors.white, tertiaryContainer: _darkSurfaceVar, onTertiaryContainer: _darkOnSurface, error: const Color(0xFFEF4444), onError: Colors.white, errorContainer: const Color(0xFF7F1D1D), onErrorContainer: const Color(0xFFFEE2E2), surface: _darkSurface, onSurface: _darkOnSurface, surfaceContainerHighest: _darkSurfaceVar, onSurfaceVariant: _darkOnSurfaceVar, outline: _darkOutline, outlineVariant: _darkOutline, shadow: Colors.black, scrim: Colors.black, inverseSurface: _darkOnSurface, onInverseSurface: _darkSurface, inversePrimary: _lightPrimary, ); return ThemeData( useMaterial3: true, colorScheme: cs, scaffoldBackgroundColor: _darkBackground, textTheme: _buildTextTheme(ThemeData.dark().textTheme), cardTheme: CardThemeData( color: _darkSurface, elevation: 2, shadowColor: Colors.black.withValues(alpha: 0.4), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), ), navigationBarTheme: NavigationBarThemeData( backgroundColor: _darkSurface, indicatorColor: _darkPrimary.withValues(alpha: 0.2), ), navigationRailTheme: NavigationRailThemeData( backgroundColor: _darkSurface, indicatorColor: _darkPrimary.withValues(alpha: 0.2), ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: _darkSurfaceVar, border: OutlineInputBorder( borderRadius: BorderRadius.circular(24), borderSide: BorderSide(color: _darkOutline), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(24), borderSide: BorderSide(color: _darkOutline), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(24), borderSide: BorderSide(color: _darkPrimary, width: 2), ), ), dividerTheme: DividerThemeData(color: _darkOutline, thickness: 1), chipTheme: ChipThemeData( backgroundColor: _darkSurfaceVar, labelStyle: TextStyle(color: _darkOnSurfaceVar, fontSize: 12), side: BorderSide(color: _darkOutline), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), ); } ThemeData fabledLightTheme() { final cs = ColorScheme( brightness: Brightness.light, primary: _lightPrimary, onPrimary: Colors.white, primaryContainer: const Color(0xFFEDE5FF), onPrimaryContainer: _lightOnSurface, secondary: _lightPrimary, onSecondary: Colors.white, secondaryContainer: _lightSurfaceVar, onSecondaryContainer: _lightOnSurface, tertiary: _lightPrimary, onTertiary: Colors.white, tertiaryContainer: _lightSurfaceVar, onTertiaryContainer: _lightOnSurface, error: const Color(0xFFDC2626), onError: Colors.white, errorContainer: const Color(0xFFFEE2E2), onErrorContainer: const Color(0xFF7F1D1D), surface: _lightSurface, onSurface: _lightOnSurface, surfaceContainerHighest: _lightSurfaceVar, onSurfaceVariant: _lightOnSurfaceVar, outline: _lightOutline, outlineVariant: _lightOutline, shadow: Colors.black, scrim: Colors.black, inverseSurface: _lightOnSurface, onInverseSurface: _lightSurface, inversePrimary: _darkPrimary, ); return ThemeData( useMaterial3: true, colorScheme: cs, scaffoldBackgroundColor: _lightBackground, textTheme: _buildTextTheme(ThemeData.light().textTheme), cardTheme: CardThemeData( color: _lightSurface, elevation: 1, shadowColor: Colors.black.withValues(alpha: 0.08), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), ), navigationBarTheme: NavigationBarThemeData( backgroundColor: _lightSurface, indicatorColor: _lightPrimary.withValues(alpha: 0.12), ), navigationRailTheme: NavigationRailThemeData( backgroundColor: _lightSurface, indicatorColor: _lightPrimary.withValues(alpha: 0.12), ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: _lightSurfaceVar, border: OutlineInputBorder( borderRadius: BorderRadius.circular(24), borderSide: BorderSide(color: _lightOutline), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(24), borderSide: BorderSide(color: _lightOutline), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(24), borderSide: BorderSide(color: _lightPrimary, width: 2), ), ), dividerTheme: DividerThemeData(color: _lightOutline, thickness: 1), chipTheme: ChipThemeData( backgroundColor: _lightSurfaceVar, labelStyle: TextStyle(color: _lightOnSurfaceVar, fontSize: 12), side: BorderSide(color: _lightOutline), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), ); } // ── GradientButton ───────────────────────────────────────────────────────────── // Use wherever the web app uses the indigo gradient button (send, primary actions). class GradientButton extends StatelessWidget { final VoidCallback? onPressed; final Widget child; final EdgeInsetsGeometry padding; const GradientButton({ super.key, required this.onPressed, required this.child, this.padding = const EdgeInsets.symmetric(horizontal: 20, vertical: 12), }); @override Widget build(BuildContext context) { final disabled = onPressed == null; return AnimatedOpacity( opacity: disabled ? 0.45 : 1.0, duration: const Duration(milliseconds: 150), child: DecoratedBox( decoration: BoxDecoration( gradient: disabled ? null : const LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFF7C3AED), Color(0xFF5B21B6)], ), color: disabled ? const Color(0xFF7C3AED) : null, borderRadius: BorderRadius.circular(12), boxShadow: disabled ? null : [ BoxShadow( color: const Color(0xFF7C3AED).withValues(alpha: 0.45), blurRadius: 8, offset: const Offset(0, 3), ), ], ), child: Material( color: Colors.transparent, child: InkWell( onTap: onPressed, borderRadius: BorderRadius.circular(12), child: Padding(padding: padding, child: child), ), ), ), ); } }