import SwiftUI import UIKit // MARK: - Colors struct AppColors { private init() {} // Brandbook 2026 (Pedi Foods) // Primary now follows the "FOODS" dark green tone from the logo. static let primary = Color(.sRGB, red: 52/255.0, green: 93/255.0, blue: 84/255.0, opacity: 1.0) // Secondary keeps the vivid lime from the symbol/logo body. static let secondary = Color(.sRGB, red: 213/255.0, green: 216/255.0, blue: 65/255.0, opacity: 1.0) static let tertiary = Color(.sRGB, red: 167/255.0, green: 191/255.0, blue: 66/255.0, opacity: 1.0) static let brandDark = Color(.sRGB, red: 31/255.0, green: 45/255.0, blue: 64/255.0, opacity: 1.0) static let brandSoft = Color(.sRGB, red: 242/255.0, green: 245/255.0, blue: 227/255.0, opacity: 1.0) static let backgroundLight = Color(.sRGB, red: 243/255.0, green: 245/255.0, blue: 247/255.0, opacity: 1.0) static let backgroundDark = Color(.sRGB, red: 31/255.0, green: 45/255.0, blue: 64/255.0, opacity: 1.0) static let surface = Color.white static let textPrimary = Color.black static let textInverse = Color.white static let textMuted = Color(.sRGB, red: 102/255.0, green: 112/255.0, blue: 133/255.0, opacity: 1.0) } struct AppDarkColors { private init() {} static let background = Color(.sRGB, red: 31/255.0, green: 45/255.0, blue: 64/255.0, opacity: 1.0) static let surface = Color.white.opacity(0.08) static let textPrimary = Color.white static let textSecondary = Color(.sRGB, red: 208/255.0, green: 213/255.0, blue: 221/255.0, opacity: 1.0) static let primary = AppColors.primary static let secondary = AppColors.secondary static let tertiary = AppColors.tertiary } // MARK: - Typography struct AppTypography { private init() {} // 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 { UIFont(name: fontFamily, size: 16) != nil } } // MARK: - Layout struct AppLayout { private init() {} 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 } struct AppShadow { private init() {} 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 if let val = UInt64(cleaned, radix: 16) { int = val } 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) } }