import 'package:flutter/material.dart'; /// ───────────────────────────────────────────────────────────────────────── /// "Futuristic Hospital — Dr. Sulaiman Al Habib (HMG)" design tokens. /// /// LIGHT MODE variant: clean white clinical surfaces with HMG red (#D02127) /// as the single brand accent — used for primary actions, focus states, /// active scanner glow, and status highlights. Panels are white cards with /// soft red-tinted shadows/borders instead of the previous dark glass look, /// keeping a crisp, futuristic-kiosk feel while staying bright and readable. /// /// Drop this file in lib/theme/app_theme.dart and wrap MaterialApp with /// `theme: AppTheme.light()`. /// ───────────────────────────────────────────────────────────────────────── class AppTheme { AppTheme._(); // Core brand colors — HMG red & white static const Color red = Color(0xFFD02127); // HMG primary brand red static const Color redDark = Color(0xFFA8191F); // pressed / deep variant static const Color redTint = Color(0xFFFCE9EA); // faint red surface tint static const Color background = Color(0xFFFFFFFF); // page background static const Color surface = Color(0xFFFFFFFF); // card surfaces static const Color surfaceMuted = Color(0xFFF7F4F4); // sunken fields, chips static const Color saudiGreen = Color(0xFF1E9E6B); // success / verified (semantic only) static const Color amberAlert = Color(0xFFC8821A); // pending / connecting static const Color redAlert = Color(0xFFD02127); // error reuses brand red static const Color textPrimary = Color(0xFF1A1213); static const Color textMuted = Color(0xFF7A6C6D); static const Color hairline = Color(0xFFE7DCDD); // Backward-compatible aliases — anywhere older screen code references // AppTheme.cyan / AppTheme.gold / AppTheme.ink*, it now resolves to the // light-mode equivalents so existing screens compile unchanged. static const Color cyan = red; static const Color gold = red; static const Color ink = background; static const Color inkRaised = surface; static const Color inkRaised2 = surfaceMuted; static ThemeData light() { final scheme = ColorScheme.fromSeed( seedColor: red, brightness: Brightness.light, primary: red, secondary: redDark, error: redAlert, surface: surface, ).copyWith( surfaceContainerLowest: background, surfaceContainerLow: surface, surfaceContainer: surfaceMuted, surfaceContainerHigh: surfaceMuted, outline: hairline, outlineVariant: hairline, onSurface: textPrimary, onSurfaceVariant: textMuted, onPrimary: Colors.white, ); return ThemeData( useMaterial3: true, brightness: Brightness.light, colorScheme: scheme, scaffoldBackgroundColor: background, fontFamily: 'Roboto', textTheme: const TextTheme().apply( bodyColor: textPrimary, displayColor: textPrimary, ), appBarTheme: const AppBarTheme( backgroundColor: background, surfaceTintColor: Colors.transparent, elevation: 0, foregroundColor: textPrimary, titleTextStyle: TextStyle( color: textPrimary, fontSize: 20, fontWeight: FontWeight.w700, letterSpacing: 0.2, ), ), cardTheme: CardThemeData( color: surface, elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), side: const BorderSide(color: hairline), ), ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: surfaceMuted, labelStyle: const TextStyle(color: textMuted), hintStyle: const TextStyle(color: textMuted), border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: const BorderSide(color: hairline), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: const BorderSide(color: hairline), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: const BorderSide(color: red, width: 1.4), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: const BorderSide(color: redAlert), ), ), filledButtonTheme: FilledButtonThemeData( style: FilledButton.styleFrom( backgroundColor: red, foregroundColor: Colors.white, minimumSize: const Size.fromHeight(54), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), textStyle: const TextStyle(fontWeight: FontWeight.w700, fontSize: 15), ), ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: surfaceMuted, foregroundColor: textPrimary, elevation: 0, minimumSize: const Size.fromHeight(54), side: const BorderSide(color: hairline), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), textStyle: const TextStyle(fontWeight: FontWeight.w700, fontSize: 15), ), ), dividerTheme: const DividerThemeData(color: hairline, thickness: 1), ); } } /// A reusable card-style panel with a soft red-tinted shadow/border — the /// signature surface treatment of this light theme. Replaces the old dark /// "glow panel"; same API so existing screens compile unchanged. class GlowPanel extends StatelessWidget { final Widget child; final Color glowColor; final EdgeInsetsGeometry padding; final double borderRadius; const GlowPanel({ super.key, required this.child, this.glowColor = AppTheme.red, this.padding = const EdgeInsets.all(20), this.borderRadius = 20, }); @override Widget build(BuildContext context) { return Container( padding: padding, decoration: BoxDecoration( color: AppTheme.surface, borderRadius: BorderRadius.circular(borderRadius), border: Border.all(color: glowColor.withValues(alpha: 0.22)), boxShadow: [ BoxShadow( color: glowColor.withValues(alpha: 0.10), blurRadius: 20, offset: const Offset(0, 6), ), const BoxShadow( color: Color(0x0A1A1213), blurRadius: 12, offset: Offset(0, 2), ), ], ), child: child, ); } } /// Subtle hex/grid backdrop to reinforce the "med-tech kiosk" feel without /// hurting readability. Cheap to render — pure CustomPaint, no images. /// In light mode this is a very faint red grid on white. class TechGridBackground extends StatelessWidget { final Widget child; const TechGridBackground({super.key, required this.child}); @override Widget build(BuildContext context) { return Stack( children: [ Positioned.fill( child: DecoratedBox( decoration: BoxDecoration( gradient: RadialGradient( center: const Alignment(0.9, -0.9), radius: 1.4, colors: [ AppTheme.red.withValues(alpha: 0.05), AppTheme.background, ], ), ), ), ), Positioned.fill(child: CustomPaint(painter: _GridPainter())), child, ], ); } } class _GridPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = AppTheme.red.withValues(alpha: 0.025) ..strokeWidth = 1; const step = 36.0; for (double x = 0; x < size.width; x += step) { canvas.drawLine(Offset(x, 0), Offset(x, size.height), paint); } for (double y = 0; y < size.height; y += step) { canvas.drawLine(Offset(0, y), Offset(size.width, y), paint); } } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; } /// Centers content and clamps width on tablets/desktop so forms don't /// stretch edge-to-edge on large screens. class ResponsiveCenter extends StatelessWidget { final Widget child; final double maxWidth; const ResponsiveCenter({super.key, required this.child, this.maxWidth = 760}); @override Widget build(BuildContext context) { return Align( alignment: Alignment.topCenter, child: ConstrainedBox( constraints: BoxConstraints(maxWidth: maxWidth), child: child, ), ); } } /// Breakpoint helper. bool isTablet(BuildContext context) => MediaQuery.sizeOf(context).shortestSide >= 600;