import SwiftUI #if os(macOS) import AppKit #elseif canImport(UIKit) import UIKit #endif private extension Color { static func adaptive( light: (red: Double, green: Double, blue: Double, opacity: Double), dark: (red: Double, green: Double, blue: Double, opacity: Double) ) -> Color { #if os(macOS) Color( nsColor: NSColor(name: nil) { appearance in let matchedAppearance = appearance.bestMatch(from: [.darkAqua, .vibrantDark, .aqua, .vibrantLight]) let components = matchedAppearance == .darkAqua || matchedAppearance == .vibrantDark ? dark : light return NSColor( red: components.red, green: components.green, blue: components.blue, alpha: components.opacity ) } ) #elseif canImport(UIKit) && !os(watchOS) Color( uiColor: UIColor { traits in let components = traits.userInterfaceStyle == .dark ? dark : light return UIColor( red: components.red, green: components.green, blue: components.blue, alpha: components.opacity ) } ) #elseif os(watchOS) Color( red: dark.red, green: dark.green, blue: dark.blue, opacity: dark.opacity ) #else Color( red: light.red, green: light.green, blue: light.blue, opacity: light.opacity ) #endif } } enum AppTheme { static let accent = Color(red: 0.12, green: 0.40, blue: 0.31) static let warmAccent = Color(red: 0.84, green: 0.71, blue: 0.48) static let border = Color.adaptive( light: (0.00, 0.00, 0.00, 0.08), dark: (1.00, 1.00, 1.00, 0.12) ) static let shadow = Color.adaptive( light: (0.00, 0.00, 0.00, 0.05), dark: (0.00, 0.00, 0.00, 0.32) ) static let cardFill = Color.adaptive( light: (1.00, 1.00, 1.00, 0.96), dark: (0.11, 0.12, 0.14, 0.96) ) static let mutedFill = Color.adaptive( light: (0.972, 0.976, 0.970, 1.00), dark: (0.16, 0.17, 0.19, 1.00) ) static let backgroundTop = Color.adaptive( light: (0.975, 0.978, 0.972, 1.00), dark: (0.08, 0.09, 0.10, 1.00) ) static let backgroundBottom = Color.adaptive( light: (1.00, 1.00, 1.00, 1.00), dark: (0.05, 0.06, 0.07, 1.00) ) static let backgroundGlow = Color.adaptive( light: (0.00, 0.00, 0.00, 0.02), dark: (1.00, 1.00, 1.00, 0.06) ) static let chromeFill = Color.adaptive( light: (1.00, 1.00, 1.00, 0.98), dark: (0.10, 0.11, 0.13, 0.98) ) } enum AppLayout { static let compactHorizontalPadding: CGFloat = 16 static let regularHorizontalPadding: CGFloat = 28 static let compactVerticalPadding: CGFloat = 18 static let regularVerticalPadding: CGFloat = 28 static let compactContentWidth: CGFloat = 720 static let regularContentWidth: CGFloat = 920 static let cardRadius: CGFloat = 24 static let largeCardRadius: CGFloat = 30 static let compactSectionPadding: CGFloat = 18 static let regularSectionPadding: CGFloat = 24 static let compactSectionSpacing: CGFloat = 18 static let regularSectionSpacing: CGFloat = 24 static let compactBottomDockPadding: CGFloat = 120 static let regularBottomPadding: CGFloat = 56 static func horizontalPadding(for compactLayout: Bool) -> CGFloat { compactLayout ? compactHorizontalPadding : regularHorizontalPadding } static func verticalPadding(for compactLayout: Bool) -> CGFloat { compactLayout ? compactVerticalPadding : regularVerticalPadding } static func contentWidth(for compactLayout: Bool) -> CGFloat { compactLayout ? compactContentWidth : regularContentWidth } static func sectionPadding(for compactLayout: Bool) -> CGFloat { compactLayout ? compactSectionPadding : regularSectionPadding } static func sectionSpacing(for compactLayout: Bool) -> CGFloat { compactLayout ? compactSectionSpacing : regularSectionSpacing } } extension View { func appSurface(radius: CGFloat = AppLayout.cardRadius, fill: Color = AppTheme.cardFill) -> some View { background( fill, in: RoundedRectangle(cornerRadius: radius, style: .continuous) ) .overlay( RoundedRectangle(cornerRadius: radius, style: .continuous) .stroke(AppTheme.border, lineWidth: 1) ) .shadow(color: AppTheme.shadow, radius: 12, y: 3) } } struct AppBackground: View { var body: some View { LinearGradient( colors: [ AppTheme.backgroundTop, AppTheme.backgroundBottom ], startPoint: .top, endPoint: .bottom ) .overlay(alignment: .top) { Rectangle() .fill(AppTheme.backgroundGlow) .frame(height: 160) .blur(radius: 60) .offset(y: -90) } .ignoresSafeArea() } } struct AppScrollScreen: View { let compactLayout: Bool var bottomPadding: CGFloat? = nil let content: () -> Content init( compactLayout: Bool, bottomPadding: CGFloat? = nil, @ViewBuilder content: @escaping () -> Content ) { self.compactLayout = compactLayout self.bottomPadding = bottomPadding self.content = content } var body: some View { ScrollView { VStack(alignment: .leading, spacing: AppLayout.sectionSpacing(for: compactLayout)) { content() } .frame(maxWidth: AppLayout.contentWidth(for: compactLayout), alignment: .leading) .padding(.horizontal, AppLayout.horizontalPadding(for: compactLayout)) .padding(.top, AppLayout.verticalPadding(for: compactLayout)) .padding(.bottom, bottomPadding ?? AppLayout.verticalPadding(for: compactLayout)) .frame(maxWidth: .infinity, alignment: compactLayout ? .leading : .center) } .scrollIndicators(.hidden) } } struct AppPanel: View { let compactLayout: Bool let radius: CGFloat let content: () -> Content init( compactLayout: Bool, radius: CGFloat = AppLayout.cardRadius, @ViewBuilder content: @escaping () -> Content ) { self.compactLayout = compactLayout self.radius = radius self.content = content } var body: some View { VStack(alignment: .leading, spacing: 14) { content() } .padding(AppLayout.sectionPadding(for: compactLayout)) .frame(maxWidth: .infinity, alignment: .leading) .appSurface(radius: radius) } } struct AppBadge: View { let title: String var tone: Color = AppTheme.accent var body: some View { Text(title) .font(.caption.weight(.semibold)) .foregroundStyle(tone) .padding(.horizontal, 12) .padding(.vertical, 8) .background(tone.opacity(0.10), in: Capsule()) } } struct AppSectionCard: View { let title: String var subtitle: String? = nil let compactLayout: Bool let content: () -> Content init( title: String, subtitle: String? = nil, compactLayout: Bool, @ViewBuilder content: @escaping () -> Content ) { self.title = title self.subtitle = subtitle self.compactLayout = compactLayout self.content = content } var body: some View { AppPanel(compactLayout: compactLayout) { AppSectionTitle(title: title, subtitle: subtitle) content() } } }