import SwiftUI #if canImport(UIKit) import UIKit #elseif canImport(AppKit) import AppKit #endif // MARK: - Colors enum AppColors { // Brandbook 2026 (Pedi Foods) // Primary now follows the "FOODS" dark green tone from the logo. static let primary = Color(hex: "#345D54") // Secondary keeps the vivid lime from the symbol/logo body. static let secondary = Color(hex: "#D5D841") static let tertiary = Color(hex: "#A7BF42") static let brandDark = Color(hex: "#1F2D40") static let brandSoft = Color(hex: "#F2F5E3") static let backgroundLight = Color(hex: "#F3F5F7") static let backgroundDark = Color(hex: "#1F2D40") static let surface = Color(hex: "#FFFFFF") static let textPrimary = Color(hex: "#000000") static let textInverse = Color(hex: "#FFFFFF") static let textMuted = Color(hex: "#667085") } enum AppDarkColors { static let background = Color(hex: "#1F2D40") static let surface = Color(hex: "#FFFFFF", alpha: 0.08) static let textPrimary = Color(hex: "#FFFFFF") static let textSecondary = Color(hex: "#D0D5DD") static let primary = AppColors.primary static let secondary = AppColors.secondary static let tertiary = AppColors.tertiary } // MARK: - Typography enum AppTypography { // Brandbook typography: Nexa (fallback: system font) static let fontFamily = "Nexa-Regular" static let heading1 = resolvedFont(size: 28, fallbackWeight: .bold) static let heading25 = resolvedFont(size: 25, fallbackWeight: .bold) static let heading2 = resolvedFont(size: 20, fallbackWeight: .semibold) static let heading3 = resolvedFont(size: 16, fallbackWeight: .semibold) static let body = resolvedFont(size: 16, fallbackWeight: .regular) static let button = resolvedFont(size: 14, fallbackWeight: .semibold) static let caption = resolvedFont(size: 10, fallbackWeight: .regular) static let overline = resolvedFont(size: 11, fallbackWeight: .regular) static let bodyLineHeight: CGFloat = 1.6 static let buttonLetterSpacing: CGFloat = 0.08 static let captionLetterSpacing: CGFloat = 0.12 private static func resolvedFont(size: CGFloat, fallbackWeight: Font.Weight) -> Font { if isBrandFontAvailable { return Font.custom(fontFamily, size: size) } return .system(size: size, weight: fallbackWeight, design: .default) } private static var isBrandFontAvailable: Bool { #if canImport(UIKit) return UIFont(name: fontFamily, size: 16) != nil #elseif canImport(AppKit) return NSFont(name: fontFamily, size: 16) != nil #else return false #endif } } // MARK: - Layout enum AppLayout { static let radiusMD: CGFloat = 12 static let radiusLG: CGFloat = 16 static let radiusXL: CGFloat = 24 static let radiusFull: CGFloat = 9999 static let spacing: [CGFloat] = [4, 8, 12, 16, 24, 32] } // MARK: - Shadow struct ShadowSpec { let color: Color let radius: CGFloat let y: CGFloat } enum AppShadow { static let soft = ShadowSpec(color: Color.black.opacity(0.08), radius: 20, y: 6) static let glow = ShadowSpec(color: AppColors.tertiary.opacity(0.2), radius: 24, y: 8) } // MARK: - Helpers extension Color { init(hex: String, alpha: Double = 1.0) { let cleaned = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) var int: UInt64 = 0 Scanner(string: cleaned).scanHexInt64(&int) let r, g, b: UInt64 switch cleaned.count { case 6: // RRGGBB r = (int >> 16) & 0xFF g = (int >> 8) & 0xFF b = int & 0xFF case 3: // RGB r = ((int >> 8) & 0xF) * 17 g = ((int >> 4) & 0xF) * 17 b = (int & 0xF) * 17 default: r = 0; g = 0; b = 0 } self.init(.sRGB, red: Double(r) / 255, green: Double(g) / 255, blue: Double(b) / 255, opacity: alpha) } }