1
//! Discovers system-native styling for colors, fonts, and other metrics.
2
//!
3
//! This module provides a best-effort attempt to query the host operating system
4
//! for its UI theme information. This is gated behind the **`io`** feature flag.
5
//!
6
//! **End-user customization (`AZ_RICING`):**
7
//! By default (if the `io` feature is enabled), Azul looks for an
8
//! application-specific stylesheet at `~/.config/azul/styles/<app_name>.css`
9
//! (or `%APPDATA%\azul\styles\<app_name>.css` on Windows) and applies it as
10
//! the last layer of the cascade, letting end-users "rice" any Azul app.
11
//!
12
//! The `AZ_RICING` env var has three modes (case-insensitive):
13
//!
14
//! - unset (default): load the user CSS if present; on Linux, the
15
//!   detection chain is `KDE > GNOME > riced > defaults`.
16
//! - `AZ_RICING=off` (aliases: `disabled`, `none`, `0`): skip the user
17
//!   CSS file and the riced-desktop sources (Hyprland config, pywal
18
//!   cache). Use for kiosk builds or CI runs that mustn't pick up local
19
//!   customization.
20
//! - `AZ_RICING=force` (aliases: `prefer`, `aggressive`, `1`): on Linux,
21
//!   reorder the detection chain so riced-desktop sources win over
22
//!   GNOME/KDE — useful for tiling-WM users whose `XDG_CURRENT_DESKTOP`
23
//!   still says `gnome`. The user CSS file still loads.
24

            
25
#![cfg(feature = "parser")]
26

            
27
use alloc::{
28
    boxed::Box,
29
    string::{String, ToString},
30
    vec::Vec,
31
};
32
use crate::{
33
    corety::{AzString, OptionF32, OptionString, OptionU16},
34
    css::Css,
35
    parser2::{new_from_str, CssParseWarnMsg},
36
    props::{
37
        basic::{
38
            color::{parse_css_color, ColorU, OptionColorU},
39
            pixel::{PixelValue, OptionPixelValue},
40
        },
41
        style::scrollbar::{ComputedScrollbarStyle, OverscrollBehavior, ScrollBehavior, ScrollPhysics},
42
    },
43
};
44

            
45
// --- End-user customization mode ---
46

            
47
/// User-customization mode controlled by the `AZ_RICING` env var.
48
///
49
/// See the module-level documentation for the full description.
50
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51
pub enum RicingMode {
52
    /// `AZ_RICING=off` (or `disabled` / `none` / `0`). Skip the user
53
    /// CSS file *and* the riced-desktop sources. Vanilla detection.
54
    Off,
55
    /// Unset. Load the user CSS if present; standard detection chain
56
    /// (`KDE > GNOME > riced > defaults` on Linux).
57
    Default,
58
    /// `AZ_RICING=force` (or `prefer` / `aggressive` / `1`). Reorder
59
    /// the Linux detection chain so riced-desktop sources win over
60
    /// GNOME/KDE. The user CSS file still loads.
61
    Force,
62
}
63

            
64
impl Default for RicingMode {
65
    fn default() -> Self { RicingMode::Default }
66
}
67

            
68
/// Read the `AZ_RICING` env var and classify it. Case-insensitive.
69
/// Anything we don't recognise falls through to `Default` so a typo
70
/// degrades gracefully instead of disabling the feature silently.
71
pub fn ricing_mode() -> RicingMode {
72
    let raw = match std::env::var("AZ_RICING") {
73
        Ok(s) => s,
74
        Err(_) => return RicingMode::Default,
75
    };
76
    match raw.trim().to_ascii_lowercase().as_str() {
77
        "off" | "disabled" | "none" | "0" | "false" => RicingMode::Off,
78
        "force" | "prefer" | "aggressive" | "1" | "true" => RicingMode::Force,
79
        _ => RicingMode::Default,
80
    }
81
}
82

            
83
/// True when the user CSS file at `~/.config/azul/styles/<app>.css`
84
/// should be read. False only when `AZ_RICING=off` is set.
85
pub fn ricing_enabled() -> bool {
86
    !matches!(ricing_mode(), RicingMode::Off)
87
}
88

            
89
// --- Public Data Structures ---
90

            
91
/// Represents the detected platform.
92
#[derive(Debug, Default, Clone, PartialEq, Eq)]
93
#[repr(C, u8)]
94
pub enum Platform {
95
    Windows,
96
    MacOs,
97
    Linux(DesktopEnvironment),
98
    Android,
99
    Ios,
100
    #[default]
101
    Unknown,
102
}
103

            
104
impl Platform {
105
    /// Get the current platform at compile time.
106
    #[inline]
107
4690
    pub fn current() -> Self {
108
        #[cfg(target_os = "macos")]
109
        { Platform::MacOs }
110
        #[cfg(target_os = "windows")]
111
        { Platform::Windows }
112
        #[cfg(target_os = "linux")]
113
4690
        { Platform::Linux(DesktopEnvironment::Other(AzString::from_const_str("unknown"))) }
114
        #[cfg(target_os = "android")]
115
        { Platform::Android }
116
        #[cfg(target_os = "ios")]
117
        { Platform::Ios }
118
        #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux", target_os = "android", target_os = "ios")))]
119
        { Platform::Unknown }
120
4690
    }
121
}
122

            
123
/// Represents the detected Linux Desktop Environment.
124
#[derive(Debug, Clone, PartialEq, Eq)]
125
#[repr(C, u8)]
126
pub enum DesktopEnvironment {
127
    Gnome,
128
    Kde,
129
    Other(AzString),
130
}
131

            
132
/// The overall theme type.
133
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
134
#[repr(C)]
135
pub enum Theme {
136
    #[default]
137
    Light,
138
    Dark,
139
}
140

            
141
/// A unified collection of discovered system style properties.
142
#[derive(Debug, Default, Clone, PartialEq)]
143
#[repr(C)]
144
pub struct SystemStyle {
145
    pub fonts: SystemFonts,
146
    pub metrics: SystemMetrics,
147
    /// Linux-specific customisation (icon theme, cursor theme, GTK theme, ...)
148
    pub linux: LinuxCustomization,
149
    pub platform: Platform,
150
    /// Focus ring / indicator visual style
151
    pub focus_visuals: FocusVisuals,
152
    /// System language/locale in BCP 47 format (e.g., "en-US", "de-DE")
153
    /// Detected from OS settings at startup
154
    pub language: AzString,
155
    /// An optional, user-provided stylesheet loaded from a conventional
156
    /// location (`~/.config/azul/styles/<app_name>.css`), allowing for
157
    /// application-specific "ricing". Only loaded when the "io" feature
158
    /// is enabled and `AZ_RICING` is not set to `off`.
159
    pub app_specific_stylesheet: Option<Box<Css>>,
160
    /// Scrollbar style information (boxed to ensure stable FFI size)
161
    pub scrollbar: Option<Box<ComputedScrollbarStyle>>,
162
    /// Global scroll physics configuration (momentum, friction, rubber-banding).
163
    /// Platform-specific defaults are applied during system style discovery.
164
    /// Applications can override this to change the "feel" of scrolling globally.
165
    pub scroll_physics: ScrollPhysics,
166
    pub theme: Theme,
167
    /// Detected OS version (e.g., Windows 11 22H2, macOS Sonoma, etc.)
168
    pub os_version: crate::dynamic_selector::OsVersion,
169
    /// User prefers reduced motion (accessibility setting)
170
    pub prefers_reduced_motion: crate::dynamic_selector::BoolCondition,
171
    /// User prefers high contrast (accessibility setting)
172
    pub prefers_high_contrast: crate::dynamic_selector::BoolCondition,
173
    /// Detailed accessibility settings (superset of prefers_reduced_motion / prefers_high_contrast)
174
    pub accessibility: AccessibilitySettings,
175
    /// Input interaction timing / distance thresholds from the OS
176
    pub input: InputMetrics,
177
    /// Text rendering / anti-aliasing hints from the OS
178
    pub text_rendering: TextRenderingHints,
179
    /// OS-level scrollbar visibility / click-behaviour preferences
180
    pub scrollbar_preferences: ScrollbarPreferences,
181
    /// Visual hints: icons in menus/buttons, toolbar style, tooltips
182
    pub visual_hints: VisualHints,
183
    /// Animation enable/disable, speed factor, focus indicator behaviour
184
    pub animation: AnimationMetrics,
185
    pub colors: SystemColors,
186
    /// Icon-specific styling options (grayscale, tinting, etc.)
187
    pub icon_style: IconStyleOptions,
188
    /// Audio feedback preferences (event sounds, input sounds)
189
    pub audio: AudioMetrics,
190
}
191

            
192
/// Icon-specific styling options for accessibility and theming.
193
///
194
/// These settings affect how icons are rendered, supporting accessibility
195
/// needs like reduced colors and high contrast modes.
196
#[derive(Debug, Default, Clone, PartialEq)]
197
#[repr(C)]
198
pub struct IconStyleOptions {
199
    /// If true, icons should be rendered in grayscale (for color-blind users
200
    /// or reduced color preference). Applies a CSS grayscale filter.
201
    pub prefer_grayscale: bool,
202
    /// Optional tint color to apply to icons. Useful for matching icons
203
    /// to the current theme or for high contrast modes.
204
    pub tint_color: OptionColorU,
205
    /// If true, icons should inherit the current text color instead of
206
    /// using their original colors. Works well with font-based icons.
207
    pub inherit_text_color: bool,
208
}
209

            
210
/// System font types that can be resolved at runtime based on OS settings.
211
/// 
212
/// This enum allows specifying semantic font roles that get resolved to
213
/// actual font families based on the current platform and user preferences.
214
/// For example, `Monospace` resolves to:
215
/// - macOS: SF Mono or Menlo
216
/// - Windows: Cascadia Mono or Consolas
217
/// - Linux: Ubuntu Mono or DejaVu Sans Mono
218
/// 
219
/// Font variants (bold, italic) can be combined with the base type.
220
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
221
#[repr(C)]
222
#[derive(Default)]
223
pub enum SystemFontType {
224
    /// UI font for buttons, labels, menus (SF Pro, Segoe UI, Cantarell)
225
    #[default]
226
    Ui,
227
    /// Bold variant of UI font
228
    UiBold,
229
    /// Monospace font for code (SF Mono, Consolas, Ubuntu Mono)
230
    Monospace,
231
    /// Bold variant of monospace font
232
    MonospaceBold,
233
    /// Italic variant of monospace font
234
    MonospaceItalic,
235
    /// Font for window titles
236
    Title,
237
    /// Bold variant of title font
238
    TitleBold,
239
    /// Font for menu items
240
    Menu,
241
    /// Small/caption font
242
    Small,
243
    /// Serif font for reading content (New York on macOS, Georgia on Windows)
244
    Serif,
245
    /// Bold variant of serif font
246
    SerifBold,
247
}
248

            
249

            
250
impl SystemFontType {
251
    /// Parse a SystemFontType from a CSS string.
252
    /// 
253
    /// Supported formats:
254
    /// - `system:ui`, `system:ui:bold`
255
    /// - `system:monospace`, `system:monospace:bold`, `system:monospace:italic`
256
    /// - `system:title`, `system:title:bold`
257
    /// - `system:menu`
258
    /// - `system:small`
259
    /// - `system:serif`, `system:serif:bold`
260
27
    pub fn from_css_str(s: &str) -> Option<Self> {
261
27
        let s = s.trim();
262
27
        if !s.starts_with("system:") {
263
            return None;
264
27
        }
265
27
        let rest = &s[7..]; // Skip "system:"
266
27
        match rest {
267
27
            "ui" => Some(SystemFontType::Ui),
268
23
            "ui:bold" => Some(SystemFontType::UiBold),
269
21
            "monospace" => Some(SystemFontType::Monospace),
270
19
            "monospace:bold" => Some(SystemFontType::MonospaceBold),
271
16
            "monospace:italic" => Some(SystemFontType::MonospaceItalic),
272
13
            "title" => Some(SystemFontType::Title),
273
11
            "title:bold" => Some(SystemFontType::TitleBold),
274
9
            "menu" => Some(SystemFontType::Menu),
275
7
            "small" => Some(SystemFontType::Small),
276
5
            "serif" => Some(SystemFontType::Serif),
277
3
            "serif:bold" => Some(SystemFontType::SerifBold),
278
1
            _ => None,
279
        }
280
27
    }
281
    
282
    /// Get the CSS syntax for this system font type.
283
11
    pub fn as_css_str(&self) -> &'static str {
284
11
        match self {
285
1
            SystemFontType::Ui => "system:ui",
286
1
            SystemFontType::UiBold => "system:ui:bold",
287
1
            SystemFontType::Monospace => "system:monospace",
288
1
            SystemFontType::MonospaceBold => "system:monospace:bold",
289
1
            SystemFontType::MonospaceItalic => "system:monospace:italic",
290
1
            SystemFontType::Title => "system:title",
291
1
            SystemFontType::TitleBold => "system:title:bold",
292
1
            SystemFontType::Menu => "system:menu",
293
1
            SystemFontType::Small => "system:small",
294
1
            SystemFontType::Serif => "system:serif",
295
1
            SystemFontType::SerifBold => "system:serif:bold",
296
        }
297
11
    }
298
    
299
    /// Returns true if this system font type implies bold weight.
300
    /// Used when resolving system fonts to pass the correct weight to fontconfig.
301
    pub fn is_bold(&self) -> bool {
302
        matches!(
303
            self,
304
            SystemFontType::UiBold
305
                | SystemFontType::MonospaceBold
306
                | SystemFontType::TitleBold
307
                | SystemFontType::SerifBold
308
        )
309
    }
310
    
311
    /// Returns true if this system font type implies italic style.
312
    pub fn is_italic(&self) -> bool {
313
        matches!(self, SystemFontType::MonospaceItalic)
314
    }
315
}
316

            
317
/// Accessibility settings detected from the operating system.
318
/// 
319
/// These settings allow apps to adapt their UI for users with accessibility needs.
320
/// Detection methods:
321
/// - macOS: UIAccessibility APIs (isBoldTextEnabled, isReduceMotionEnabled, etc.)
322
/// - Windows: SystemParametersInfo (SPI_GETHIGHCONTRAST, SPI_GETCLIENTAREAANIMATION)
323
/// - Linux: gsettings (org.gnome.desktop.interface, org.gnome.desktop.a11y)
324
#[derive(Debug, Default, Clone, PartialEq)]
325
#[repr(C)]
326
pub struct AccessibilitySettings {
327
    /// Text scaling factor (1.0 = normal, 1.5 = 150%, etc.)
328
    pub text_scale_factor: f32,
329
    /// User prefers bold text for better readability
330
    /// macOS: UIAccessibility.isBoldTextEnabled
331
    /// Windows: N/A (font scaling)
332
    /// Linux: org.gnome.desktop.interface text-scaling-factor
333
    pub prefers_bold_text: bool,
334
    /// User prefers larger text
335
    /// macOS: preferredContentSizeCategory
336
    /// Windows: SystemParametersInfo text scale factor
337
    /// Linux: org.gnome.desktop.interface text-scaling-factor
338
    pub prefers_larger_text: bool,
339
    /// User prefers high contrast colors
340
    /// macOS: UIAccessibility.isDarkerSystemColorsEnabled
341
    /// Windows: SPI_GETHIGHCONTRAST
342
    /// Linux: org.gnome.desktop.a11y.interface high-contrast
343
    pub prefers_high_contrast: bool,
344
    /// User prefers reduced motion/animations
345
    /// macOS: UIAccessibility.isReduceMotionEnabled
346
    /// Windows: SPI_GETCLIENTAREAANIMATION (inverted)
347
    /// Linux: org.gnome.desktop.interface enable-animations (inverted)
348
    pub prefers_reduced_motion: bool,
349
    /// User prefers reduced transparency
350
    /// macOS: UIAccessibility.isReduceTransparencyEnabled
351
    /// Windows: N/A
352
    /// Linux: N/A
353
    pub prefers_reduced_transparency: bool,
354
    /// Screen reader is active (VoiceOver, Narrator, Orca)
355
    pub screen_reader_active: bool,
356
    /// User prefers differentiate without color
357
    /// macOS: UIAccessibility.shouldDifferentiateWithoutColor
358
    pub differentiate_without_color: bool,
359
}
360

            
361
/// Common system colors used for UI elements.
362
/// 
363
/// These colors are queried from the operating system and automatically adapt
364
/// to the current theme (light/dark mode) and accent color settings.
365
/// 
366
/// On macOS, these correspond to NSColor semantic colors.
367
/// On Windows, these come from UISettings.
368
/// On Linux/GTK, these come from the GTK theme.
369
#[derive(Debug, Default, Clone, PartialEq)]
370
#[repr(C)]
371
pub struct SystemColors {
372
    // === Primary semantic colors ===
373
    /// Primary text color (NSColor.textColor on macOS)
374
    pub text: OptionColorU,
375
    /// Secondary text color for less prominent text (NSColor.secondaryLabelColor)
376
    pub secondary_text: OptionColorU,
377
    /// Tertiary text color for disabled/placeholder text (NSColor.tertiaryLabelColor)
378
    pub tertiary_text: OptionColorU,
379
    /// Background color for content areas (NSColor.textBackgroundColor)
380
    pub background: OptionColorU,
381
    
382
    // === Accent colors ===
383
    /// System accent color chosen by user (NSColor.controlAccentColor on macOS)
384
    pub accent: OptionColorU,
385
    /// Text color on accent backgrounds
386
    pub accent_text: OptionColorU,
387
    
388
    // === Control colors ===
389
    /// Button/control background (NSColor.controlColor)
390
    pub button_face: OptionColorU,
391
    /// Button/control text color (NSColor.controlTextColor)
392
    pub button_text: OptionColorU,
393
    /// Disabled control text color (NSColor.disabledControlTextColor)
394
    pub disabled_text: OptionColorU,
395
    
396
    // === Window colors ===
397
    /// Window background color (NSColor.windowBackgroundColor)
398
    pub window_background: OptionColorU,
399
    /// Under-page background color (NSColor.underPageBackgroundColor)
400
    pub under_page_background: OptionColorU,
401
    
402
    // === Selection colors ===
403
    /// Selection background when window is focused (NSColor.selectedContentBackgroundColor)
404
    pub selection_background: OptionColorU,
405
    /// Selection text color when window is focused
406
    pub selection_text: OptionColorU,
407
    /// Selection background when window is NOT focused (NSColor.unemphasizedSelectedContentBackgroundColor)
408
    /// This is used for :backdrop state styling
409
    pub selection_background_inactive: OptionColorU,
410
    /// Selection text color when window is NOT focused
411
    pub selection_text_inactive: OptionColorU,
412
    
413
    // === Additional semantic colors ===
414
    /// Link color (NSColor.linkColor)
415
    pub link: OptionColorU,
416
    /// Separator/divider color (NSColor.separatorColor)
417
    pub separator: OptionColorU,
418
    /// Grid/table line color (NSColor.gridColor)
419
    pub grid: OptionColorU,
420
    /// Find/search highlight color (NSColor.findHighlightColor)
421
    pub find_highlight: OptionColorU,
422
    
423
    // === Sidebar colors (macOS-specific) ===
424
    /// Sidebar background color
425
    pub sidebar_background: OptionColorU,
426
    /// Selected row in sidebar
427
    pub sidebar_selection: OptionColorU,
428
}
429

            
430
/// Common system font settings.
431
/// 
432
/// On macOS, these are queried from NSFont.
433
/// On Windows, these come from SystemParametersInfo.
434
/// On Linux, these come from GTK/gsettings.
435
#[derive(Debug, Default, Clone, PartialEq)]
436
#[repr(C)]
437
pub struct SystemFonts {
438
    /// The primary font used for UI elements like buttons and labels.
439
    /// On macOS: SF Pro (system font)
440
    /// On Windows: Segoe UI
441
    /// On Linux: Cantarell, Ubuntu, or system default
442
    pub ui_font: OptionString,
443
    /// The default font size for UI elements, in points.
444
    pub ui_font_size: OptionF32,
445
    /// The font used for code or other monospaced text.
446
    /// On macOS: SF Mono or Menlo
447
    /// On Windows: Cascadia Mono or Consolas
448
    /// On Linux: Ubuntu Mono or DejaVu Sans Mono
449
    pub monospace_font: OptionString,
450
    /// Monospace font size in points
451
    pub monospace_font_size: OptionF32,
452
    /// Bold variant of the UI font (if different)
453
    pub ui_font_bold: OptionString,
454
    /// Font for window titles
455
    pub title_font: OptionString,
456
    /// Title font size in points
457
    pub title_font_size: OptionF32,
458
    /// Font for menu items
459
    pub menu_font: OptionString,
460
    /// Menu font size in points
461
    pub menu_font_size: OptionF32,
462
    /// Small/caption font for less prominent text
463
    pub small_font: OptionString,
464
    /// Small font size in points
465
    pub small_font_size: OptionF32,
466
}
467

            
468
/// Common system metrics for UI element sizing and spacing.
469
#[derive(Debug, Default, Clone, PartialEq)]
470
#[repr(C)]
471
pub struct SystemMetrics {
472
    /// The corner radius for standard elements like buttons.
473
    pub corner_radius: OptionPixelValue,
474
    /// The width of standard borders.
475
    pub border_width: OptionPixelValue,
476
    /// The horizontal (left/right) padding for buttons and similar controls.
477
    pub button_padding_horizontal: OptionPixelValue,
478
    /// The vertical (top/bottom) padding for buttons and similar controls.
479
    pub button_padding_vertical: OptionPixelValue,
480
    /// Titlebar layout information (button positions, safe areas, etc.)
481
    pub titlebar: TitlebarMetrics,
482
}
483

            
484
/// Which side of the titlebar the window control buttons are on.
485
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
486
#[repr(C)]
487
pub enum TitlebarButtonSide {
488
    /// Buttons are on the left (macOS default)
489
    Left,
490
    /// Buttons are on the right (Windows, most Linux DEs)
491
    #[default]
492
    Right,
493
}
494

            
495
/// Which window control buttons are available in the titlebar.
496
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
497
#[repr(C)]
498
pub struct TitlebarButtons {
499
    /// Close button is available
500
    pub has_close: bool,
501
    /// Minimize button is available
502
    pub has_minimize: bool,
503
    /// Maximize/zoom button is available
504
    pub has_maximize: bool,
505
    /// Fullscreen button is available (macOS green button behavior)
506
    pub has_fullscreen: bool,
507
}
508

            
509
impl Default for TitlebarButtons {
510
42
    fn default() -> Self {
511
42
        Self {
512
42
            has_close: true,
513
42
            has_minimize: true,
514
42
            has_maximize: true,
515
42
            has_fullscreen: false,
516
42
        }
517
42
    }
518
}
519

            
520
/// Safe area insets for devices with notches, rounded corners, or sensor housings.
521
/// 
522
/// On devices like iPhones with notches or Dynamic Island, the safe area
523
/// indicates regions where content should not be placed to avoid being
524
/// obscured by hardware features.
525
#[derive(Debug, Default, Clone, Copy, PartialEq)]
526
#[repr(C)]
527
pub struct SafeAreaInsets {
528
    /// Inset from the top edge (notch, camera housing, etc.)
529
    pub top: OptionPixelValue,
530
    /// Inset from the bottom edge (home indicator on iPhone)
531
    pub bottom: OptionPixelValue,
532
    /// Inset from the left edge (rounded corners)
533
    pub left: OptionPixelValue,
534
    /// Inset from the right edge (rounded corners)
535
    pub right: OptionPixelValue,
536
}
537

            
538
/// Metrics for titlebar layout and window chrome.
539
/// 
540
/// This provides information needed to correctly position custom titlebar
541
/// content when using `WindowDecorations::NoTitle` (expanded title mode).
542
#[derive(Debug, Clone, PartialEq)]
543
#[repr(C)]
544
pub struct TitlebarMetrics {
545
    /// Which side the window control buttons are on
546
    pub button_side: TitlebarButtonSide,
547
    /// Which buttons are available
548
    pub buttons: TitlebarButtons,
549
    /// Height of the titlebar in pixels
550
    pub height: OptionPixelValue,
551
    /// Width reserved for window control buttons (close/min/max)
552
    /// This is the space to avoid when drawing custom title text
553
    pub button_area_width: OptionPixelValue,
554
    /// Horizontal padding inside the titlebar
555
    pub padding_horizontal: OptionPixelValue,
556
    /// Safe area insets for notched/rounded displays
557
    pub safe_area: SafeAreaInsets,
558
    /// Title text font (from SystemFonts::title_font)
559
    pub title_font: OptionString,
560
    /// Title text font size
561
    pub title_font_size: OptionF32,
562
    /// Title text font weight (400 = normal, 600 = semibold, 700 = bold)
563
    pub title_font_weight: OptionU16,
564
}
565

            
566
impl Default for TitlebarMetrics {
567
42
    fn default() -> Self {
568
42
        Self {
569
42
            button_side: TitlebarButtonSide::Right,
570
42
            buttons: TitlebarButtons::default(),
571
42
            height: OptionPixelValue::Some(PixelValue::px(32.0)),
572
42
            button_area_width: OptionPixelValue::Some(PixelValue::px(100.0)),
573
42
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(8.0)),
574
42
            safe_area: SafeAreaInsets::default(),
575
42
            title_font: OptionString::None,
576
42
            title_font_size: OptionF32::Some(13.0),
577
42
            title_font_weight: OptionU16::Some(600), // Semibold
578
42
        }
579
42
    }
580
}
581

            
582
impl TitlebarMetrics {
583
    /// Windows-style titlebar (buttons on right)
584
    pub fn windows() -> Self {
585
        Self {
586
            button_side: TitlebarButtonSide::Right,
587
            buttons: TitlebarButtons {
588
                has_close: true,
589
                has_minimize: true,
590
                has_maximize: true,
591
                has_fullscreen: false,
592
            },
593
            height: OptionPixelValue::Some(PixelValue::px(32.0)),
594
            button_area_width: OptionPixelValue::Some(PixelValue::px(138.0)), // 3 buttons * 46px
595
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(8.0)),
596
            safe_area: SafeAreaInsets::default(),
597
            title_font: OptionString::Some("Segoe UI Variable Text".into()),
598
            title_font_size: OptionF32::Some(12.0),
599
            title_font_weight: OptionU16::Some(400), // Normal
600
        }
601
    }
602
    
603
    /// macOS-style titlebar (buttons on left, "traffic lights")
604
    pub fn macos() -> Self {
605
        Self {
606
            button_side: TitlebarButtonSide::Left,
607
            buttons: TitlebarButtons {
608
                has_close: true,
609
                has_minimize: true,
610
                has_maximize: false, // macOS has fullscreen instead
611
                has_fullscreen: true,
612
            },
613
            height: OptionPixelValue::Some(PixelValue::px(28.0)),
614
            button_area_width: OptionPixelValue::Some(PixelValue::px(78.0)), // 3 buttons with gaps
615
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(8.0)),
616
            safe_area: SafeAreaInsets::default(),
617
            title_font: OptionString::Some(".SF NS".into()),
618
            title_font_size: OptionF32::Some(13.0),
619
            title_font_weight: OptionU16::Some(600), // Semibold
620
        }
621
    }
622
    
623
    /// Linux GNOME-style titlebar (buttons on right by default)
624
    pub fn linux_gnome() -> Self {
625
        Self {
626
            button_side: TitlebarButtonSide::Right, // Default, can be changed in settings
627
            buttons: TitlebarButtons {
628
                has_close: true,
629
                has_minimize: true,
630
                has_maximize: true,
631
                has_fullscreen: false,
632
            },
633
            height: OptionPixelValue::Some(PixelValue::px(35.0)),
634
            button_area_width: OptionPixelValue::Some(PixelValue::px(100.0)),
635
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(12.0)),
636
            safe_area: SafeAreaInsets::default(),
637
            title_font: OptionString::Some("Cantarell".into()),
638
            title_font_size: OptionF32::Some(11.0),
639
            title_font_weight: OptionU16::Some(700), // Bold
640
        }
641
    }
642
    
643
    /// iOS-style safe area (for notched devices)
644
    pub fn ios() -> Self {
645
        Self {
646
            button_side: TitlebarButtonSide::Left,
647
            buttons: TitlebarButtons {
648
                has_close: false, // iOS apps don't have close buttons
649
                has_minimize: false,
650
                has_maximize: false,
651
                has_fullscreen: false,
652
            },
653
            height: OptionPixelValue::Some(PixelValue::px(44.0)),
654
            button_area_width: OptionPixelValue::Some(PixelValue::px(0.0)),
655
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(16.0)),
656
            safe_area: SafeAreaInsets {
657
                // iPhone notch safe area
658
                top: OptionPixelValue::Some(PixelValue::px(47.0)),
659
                bottom: OptionPixelValue::Some(PixelValue::px(34.0)),
660
                left: OptionPixelValue::None,
661
                right: OptionPixelValue::None,
662
            },
663
            title_font: OptionString::Some(".SFUI-Semibold".into()),
664
            title_font_size: OptionF32::Some(17.0),
665
            title_font_weight: OptionU16::Some(600),
666
        }
667
    }
668
    
669
    /// Android-style titlebar (action bar)
670
    pub fn android() -> Self {
671
        Self {
672
            button_side: TitlebarButtonSide::Left, // Back button on left
673
            buttons: TitlebarButtons {
674
                has_close: false,
675
                has_minimize: false,
676
                has_maximize: false,
677
                has_fullscreen: false,
678
            },
679
            height: OptionPixelValue::Some(PixelValue::px(56.0)),
680
            button_area_width: OptionPixelValue::Some(PixelValue::px(48.0)), // Back button
681
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(16.0)),
682
            safe_area: SafeAreaInsets::default(),
683
            title_font: OptionString::Some("Roboto Medium".into()),
684
            title_font_size: OptionF32::Some(20.0),
685
            title_font_weight: OptionU16::Some(500),
686
        }
687
    }
688
}
689

            
690
// ── Input interaction metrics ────────────────────────────────────────────
691

            
692
/// Input interaction timing and distance thresholds from the OS.
693
///
694
/// These values are queried from the operating system to match the user's
695
/// configured double-click speed, drag sensitivity, caret blink rate, etc.
696
///
697
/// # Platform APIs
698
/// - **macOS:** `NSEvent.doubleClickInterval`
699
/// - **Windows:** `GetDoubleClickTime()`, `GetSystemMetrics(SM_CXDOUBLECLK)`,
700
///   `GetCaretBlinkTime()`, `SystemParametersInfo(SPI_GETWHEELSCROLLLINES)`
701
/// - **Linux:** XDG Desktop Portal / gsettings
702
#[derive(Debug, Clone, Copy, PartialEq)]
703
#[repr(C)]
704
pub struct InputMetrics {
705
    /// Max milliseconds between clicks to register a double-click.
706
    pub double_click_time_ms: u32,
707
    /// Max pixels the mouse can move between clicks and still count.
708
    pub double_click_distance_px: f32,
709
    /// Pixels the mouse must move while held down before a drag starts.
710
    pub drag_threshold_px: f32,
711
    /// Caret blink rate in milliseconds (0 = no blink).
712
    pub caret_blink_rate_ms: u32,
713
    /// Width of the text caret/cursor in pixels (typically 1–2).
714
    pub caret_width_px: f32,
715
    /// Lines to scroll per mouse wheel notch.
716
    pub wheel_scroll_lines: u32,
717
    /// Milliseconds to wait before a hover triggers (e.g. tooltip delay).
718
    /// Windows: `SystemParametersInfo(SPI_GETMOUSEHOVERTIME)` — default 400.
719
    pub hover_time_ms: u32,
720
}
721

            
722
impl Default for InputMetrics {
723
42
    fn default() -> Self {
724
42
        Self {
725
42
            double_click_time_ms: 500,
726
42
            double_click_distance_px: 4.0,
727
42
            drag_threshold_px: 5.0,
728
42
            caret_blink_rate_ms: 530,
729
42
            caret_width_px: 1.0,
730
42
            wheel_scroll_lines: 3,
731
42
            hover_time_ms: 400,
732
42
        }
733
42
    }
734
}
735

            
736
// ── Text rendering hints ─────────────────────────────────────────────────
737

            
738
/// Subpixel rendering layout for font smoothing.
739
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
740
#[repr(C)]
741
pub enum SubpixelType {
742
    /// No subpixel rendering (grayscale anti-aliasing only).
743
    #[default]
744
    None,
745
    /// Horizontal RGB subpixel layout (most common for LCD monitors).
746
    Rgb,
747
    /// Horizontal BGR subpixel layout.
748
    Bgr,
749
    /// Vertical RGB subpixel layout.
750
    VRgb,
751
    /// Vertical BGR subpixel layout.
752
    VBgr,
753
}
754

            
755
/// Text rendering configuration from the OS.
756
///
757
/// These hints allow the framework to match the host's font smoothing
758
/// settings for crisp, consistent text rendering.
759
#[derive(Debug, Clone, Copy, PartialEq)]
760
#[repr(C)]
761
pub struct TextRenderingHints {
762
    /// Subpixel rendering type.
763
    pub subpixel_type: SubpixelType,
764
    /// Font smoothing gamma (1000 = default, higher = more contrast).
765
    pub font_smoothing_gamma: u32,
766
    /// Whether font smoothing (anti-aliasing) is enabled.
767
    pub font_smoothing_enabled: bool,
768
    /// User prefers increased text contrast.
769
    pub increased_contrast: bool,
770
}
771

            
772
impl Default for TextRenderingHints {
773
42
    fn default() -> Self {
774
42
        Self {
775
42
            subpixel_type: SubpixelType::None,
776
42
            font_smoothing_gamma: 1000,
777
42
            font_smoothing_enabled: true,
778
42
            increased_contrast: false,
779
42
        }
780
42
    }
781
}
782

            
783
// ── Focus ring visuals ───────────────────────────────────────────────────
784

            
785
/// Focus ring / indicator visual style.
786
///
787
/// When an element receives keyboard focus the OS typically draws a visible
788
/// ring or border.  These values come from the OS preferences.
789
#[derive(Debug, Default, Clone, Copy, PartialEq)]
790
#[repr(C)]
791
pub struct FocusVisuals {
792
    /// Focus ring / indicator colour.
793
    /// macOS: `NSColor.keyboardFocusIndicatorColor`
794
    pub focus_ring_color: OptionColorU,
795
    /// Width of focus border / ring.
796
    /// Windows: `SystemParametersInfo(SPI_GETFOCUSBORDERWIDTH)`
797
    pub focus_border_width: OptionPixelValue,
798
    /// Height of focus border / ring.
799
    pub focus_border_height: OptionPixelValue,
800
}
801

            
802
// ── Scrollbar preferences ────────────────────────────────────────────────
803

            
804
/// When scrollbars should be shown (OS-level preference).
805
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
806
#[repr(C)]
807
pub enum ScrollbarVisibility {
808
    /// Always show scrollbars.
809
    Always,
810
    /// Show only while scrolling, then fade out.
811
    #[default]
812
    WhenScrolling,
813
    /// Automatic: depends on input device (trackpad → overlay, mouse → always).
814
    Automatic,
815
}
816

            
817
/// What happens when clicking the scrollbar track area.
818
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
819
#[repr(C)]
820
pub enum ScrollbarTrackClick {
821
    /// Jump to the clicked position.
822
    JumpToPosition,
823
    /// Scroll by one page.
824
    #[default]
825
    PageUpDown,
826
}
827

            
828
/// OS-level scrollbar behaviour preferences.
829
///
830
/// These are separate from the CSS scrollbar *appearance* (`ComputedScrollbarStyle`).
831
/// They control *when* scrollbars appear and *how* clicking the track behaves.
832
#[derive(Debug, Clone, Copy, PartialEq)]
833
#[repr(C)]
834
pub struct ScrollbarPreferences {
835
    /// How scrollbars should be shown.
836
    /// macOS: `NSScroller.preferredScrollerStyle`
837
    pub visibility: ScrollbarVisibility,
838
    /// What happens when clicking the scrollbar track.
839
    pub track_click: ScrollbarTrackClick,
840
}
841

            
842
impl Default for ScrollbarPreferences {
843
42
    fn default() -> Self {
844
42
        Self {
845
42
            visibility: ScrollbarVisibility::WhenScrolling,
846
42
            track_click: ScrollbarTrackClick::PageUpDown,
847
42
        }
848
42
    }
849
}
850

            
851
// ── Linux-specific customisation ─────────────────────────────────────────
852

            
853
/// Linux-specific customisation settings.
854
///
855
/// Read from GTK / KDE / XDG settings on Linux; `Default` (all `None` / 0)
856
/// on other platforms.
857
#[derive(Debug, Default, Clone, PartialEq)]
858
#[repr(C)]
859
pub struct LinuxCustomization {
860
    /// GTK theme name (e.g. "Adwaita", "Breeze", "Numix").
861
    pub gtk_theme: OptionString,
862
    /// Icon theme name (e.g. "Papirus", "Numix", "Breeze").
863
    pub icon_theme: OptionString,
864
    /// Cursor theme name (e.g. "Breeze_Snow", "DMZ-Black").
865
    pub cursor_theme: OptionString,
866
    /// Cursor size in pixels (0 = unset / use OS default).
867
    pub cursor_size: u32,
868
    /// GTK button layout string (e.g. "close,minimize,maximize:menu").
869
    /// Determines button side and order for CSD titlebars on Linux.
870
    pub titlebar_button_layout: OptionString,
871
}
872

            
873
// ── Visual hints (icons in menus / buttons / toolbar style) ──────────────
874

            
875
/// Toolbar display style (icons, text, or both).
876
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
877
#[repr(C)]
878
pub enum ToolbarStyle {
879
    /// Show only icons in toolbars.
880
    #[default]
881
    IconsOnly,
882
    /// Show only text labels in toolbars.
883
    TextOnly,
884
    /// Show text beside the icon (horizontal).
885
    TextBesideIcon,
886
    /// Show text below the icon (vertical).
887
    TextBelowIcon,
888
}
889

            
890
/// Visual hints from the OS about how icons and decorations should be shown.
891
///
892
/// These preferences differ heavily between Linux desktops (KDE vs GNOME)
893
/// and are less configurable on macOS / Windows where HIG rules apply.
894
#[derive(Debug, Clone, Copy, PartialEq)]
895
#[repr(C)]
896
pub struct VisualHints {
897
    /// Toolbar display style.
898
    /// Linux: `org.gnome.desktop.interface toolbar-style`, KDE `ToolButtonStyle`.
899
    pub toolbar_style: ToolbarStyle,
900
    /// Show icons on push buttons?  (Common in KDE, rare in Win/Mac.)
901
    /// Linux: `org.gnome.desktop.interface buttons-have-icons`, KDE ShowIconsOnPushButtons.
902
    pub show_button_images: bool,
903
    /// Show icons in context menus?  (GNOME defaults off since 3.x; Win/Mac/KDE usually on.)
904
    /// Linux: `org.gnome.desktop.interface menus-have-icons`.
905
    pub show_menu_images: bool,
906
    /// Should tooltips be shown on hover?
907
    pub show_tooltips: bool,
908
    /// Flash the window taskbar entry on alert?
909
    pub flash_on_alert: bool,
910
}
911

            
912
impl Default for VisualHints {
913
42
    fn default() -> Self {
914
42
        Self {
915
42
            toolbar_style: ToolbarStyle::IconsOnly,
916
42
            show_button_images: false,
917
42
            show_menu_images: true,
918
42
            show_tooltips: true,
919
42
            flash_on_alert: true,
920
42
        }
921
42
    }
922
}
923

            
924
// ── Animation metrics ────────────────────────────────────────────────────
925

            
926
/// Focus indicator behaviour (always visible vs keyboard-only).
927
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
928
#[repr(C)]
929
pub enum FocusBehavior {
930
    /// Focus indicators are always visible when an element has focus.
931
    #[default]
932
    AlwaysVisible,
933
    /// Focus indicators are hidden until the user presses a keyboard key
934
    /// (Alt, Tab, arrow keys, etc.).  Windows: `SPI_GETKEYBOARDCUES`.
935
    KeyboardOnly,
936
}
937

            
938
/// Animation-related preferences from the OS.
939
///
940
/// These control whether UI animations (transitions, fades, slides) should
941
/// play and at what speed.
942
///
943
/// # Platform APIs
944
/// - **Windows:** `SystemParametersInfo(SPI_GETCLIENTAREAANIMATION)`,
945
///   `SPI_GETKEYBOARDCUES`
946
/// - **macOS:** `NSWorkspace.accessibilityDisplayShouldReduceMotion`
947
/// - **Linux:** `org.gnome.desktop.interface enable-animations`,
948
///   KDE `AnimationDurationFactor`
949
#[derive(Debug, Clone, Copy, PartialEq)]
950
#[repr(C)]
951
pub struct AnimationMetrics {
952
    /// Global enable/disable for UI animations.
953
    pub animations_enabled: bool,
954
    /// Animation speed factor (1.0 = normal, 0.5 = 2× faster, 2.0 = 2× slower).
955
    /// Primarily used in KDE.
956
    pub animation_duration_factor: f32,
957
    /// When to show focus rectangles / rings.
958
    pub focus_indicator_behavior: FocusBehavior,
959
}
960

            
961
impl Default for AnimationMetrics {
962
42
    fn default() -> Self {
963
42
        Self {
964
42
            animations_enabled: true,
965
42
            animation_duration_factor: 1.0,
966
42
            focus_indicator_behavior: FocusBehavior::AlwaysVisible,
967
42
        }
968
42
    }
969
}
970

            
971
// ── Audio metrics ────────────────────────────────────────────────────────
972

            
973
/// Audio-feedback preferences from the OS.
974
///
975
/// Controls whether the app should make sounds on events (error pings,
976
/// notifications) or on input (clicks, key presses).
977
///
978
/// # Platform APIs
979
/// - **Windows:** `SystemParametersInfo(SPI_GETBEEP)`
980
/// - **macOS:** `NSSound.soundEffectAudioVolume`
981
/// - **Linux:** `org.gnome.desktop.sound event-sounds`,
982
///   `org.gnome.desktop.sound input-feedback-sounds`
983
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
984
#[repr(C)]
985
pub struct AudioMetrics {
986
    /// Should the app make sounds on events?  (Error ping, notification, etc.)
987
    pub event_sounds_enabled: bool,
988
    /// Should the app make sounds on input?  (Clicks, typing feedback.)
989
    pub input_feedback_sounds_enabled: bool,
990
}
991

            
992
impl Default for AudioMetrics {
993
42
    fn default() -> Self {
994
42
        Self {
995
42
            event_sounds_enabled: true,
996
42
            input_feedback_sounds_enabled: false,
997
42
        }
998
42
    }
999
}
/// Apple system font family names for font fallback chains.
/// 
/// These are the canonical names for Apple's system fonts, which should
/// be used in font fallback chains for proper rendering on Apple platforms.
/// Note: The names here must match what rust-fontconfig indexes from the font metadata.
pub mod apple_fonts {
    /// System Font - Primary system font for macOS
    /// This is how rust-fontconfig indexes the SF Pro font family
    pub const SYSTEM_FONT: &str = "System Font";
    /// SF NS variants as indexed by rust-fontconfig
    pub const SF_NS_ROUNDED: &str = "SF NS Rounded";
    /// SF Compact - System font optimized for watchOS
    /// Optimized for small sizes and narrow columns
    pub const SF_COMPACT: &str = "SF Compact";
    /// SF Mono - Monospaced font used in Xcode
    /// Enables alignment between rows and columns of text
    pub const SF_MONO: &str = "SF NS Mono Light";
    /// New York - Serif font for reading
    /// Performs as traditional reading face at small sizes
    pub const NEW_YORK: &str = "New York";
    /// SF Arabic - Arabic system font
    pub const SF_ARABIC: &str = "SF Arabic";
    /// SF Armenian - Armenian system font
    pub const SF_ARMENIAN: &str = "SF Armenian";
    /// SF Georgian - Georgian system font
    pub const SF_GEORGIAN: &str = "SF Georgian";
    /// SF Hebrew - Hebrew system font with niqqud support
    pub const SF_HEBREW: &str = "SF Hebrew";
    /// Legacy macOS fonts for fallback
    pub const MENLO: &str = "Menlo";
    pub const MENLO_REGULAR: &str = "Menlo Regular";
    pub const MENLO_BOLD: &str = "Menlo Bold";
    pub const MONACO: &str = "Monaco";
    pub const LUCIDA_GRANDE: &str = "Lucida Grande";
    pub const LUCIDA_GRANDE_BOLD: &str = "Lucida Grande Bold";
    pub const HELVETICA_NEUE: &str = "Helvetica Neue";
    pub const HELVETICA_NEUE_BOLD: &str = "Helvetica Neue Bold";
}
/// Windows system font family names.
pub mod windows_fonts {
    /// Modern Windows 11 fonts
    pub const SEGOE_UI_VARIABLE: &str = "Segoe UI Variable";
    pub const SEGOE_UI_VARIABLE_TEXT: &str = "Segoe UI Variable Text";
    pub const SEGOE_UI_VARIABLE_DISPLAY: &str = "Segoe UI Variable Display";
    /// Standard Windows fonts
    pub const SEGOE_UI: &str = "Segoe UI";
    pub const CONSOLAS: &str = "Consolas";
    pub const CASCADIA_CODE: &str = "Cascadia Code";
    pub const CASCADIA_MONO: &str = "Cascadia Mono";
    /// Legacy Windows fonts
    pub const TAHOMA: &str = "Tahoma";
    pub const MS_SANS_SERIF: &str = "MS Sans Serif";
    pub const LUCIDA_CONSOLE: &str = "Lucida Console";
    pub const COURIER_NEW: &str = "Courier New";
}
/// Linux/GTK common font family names.
pub mod linux_fonts {
    /// GNOME default fonts
    pub const CANTARELL: &str = "Cantarell";
    pub const ADWAITA: &str = "Adwaita";
    /// Ubuntu fonts
    pub const UBUNTU: &str = "Ubuntu";
    pub const UBUNTU_MONO: &str = "Ubuntu Mono";
    /// DejaVu fonts (widely available)
    pub const DEJAVU_SANS: &str = "DejaVu Sans";
    pub const DEJAVU_SANS_MONO: &str = "DejaVu Sans Mono";
    pub const DEJAVU_SERIF: &str = "DejaVu Serif";
    /// Liberation fonts (metrically compatible with Windows fonts)
    pub const LIBERATION_SANS: &str = "Liberation Sans";
    pub const LIBERATION_MONO: &str = "Liberation Mono";
    pub const LIBERATION_SERIF: &str = "Liberation Serif";
    /// Noto fonts (broad Unicode coverage)
    pub const NOTO_SANS: &str = "Noto Sans";
    pub const NOTO_MONO: &str = "Noto Sans Mono";
    pub const NOTO_SERIF: &str = "Noto Serif";
    /// KDE default fonts
    pub const HACK: &str = "Hack";
    /// Generic fallback names
    pub const MONOSPACE: &str = "Monospace";
    pub const SANS_SERIF: &str = "Sans";
    pub const SERIF: &str = "Serif";
}
impl SystemFontType {
    /// Returns the font fallback chain for this font type on the given platform.
    /// 
    /// The returned list contains font family names in order of preference.
    /// The first available font should be used.
    pub fn get_fallback_chain(&self, platform: &Platform) -> Vec<&'static str> {
        match platform {
            Platform::MacOs | Platform::Ios => self.macos_fallback_chain(),
            Platform::Windows => self.windows_fallback_chain(),
            Platform::Linux(_) => self.linux_fallback_chain(),
            Platform::Android => self.android_fallback_chain(),
            Platform::Unknown => self.generic_fallback_chain(),
        }
    }
    fn macos_fallback_chain(&self) -> Vec<&'static str> {
        match self {
            // For Normal weight, try System Font first, then Helvetica Neue
            SystemFontType::Ui => vec![
                apple_fonts::SYSTEM_FONT,
                apple_fonts::HELVETICA_NEUE,
                apple_fonts::LUCIDA_GRANDE,
            ],
            // For Bold weight, use Helvetica Neue first (System Font has no Bold variant in fontconfig)
            SystemFontType::UiBold => vec![
                apple_fonts::HELVETICA_NEUE, // Will be queried with weight=Bold -> "Helvetica Neue Bold"
                apple_fonts::LUCIDA_GRANDE,
            ],
            // Monospace fonts: Menlo has bold variant
            SystemFontType::Monospace => vec![
                apple_fonts::MENLO,
                apple_fonts::MONACO,
            ],
            SystemFontType::MonospaceBold | SystemFontType::MonospaceItalic => vec![
                apple_fonts::MENLO, // Menlo Bold exists
                apple_fonts::MONACO,
            ],
            // Title: same strategy - use Helvetica Neue for bold
            SystemFontType::Title => vec![
                apple_fonts::SYSTEM_FONT,
                apple_fonts::HELVETICA_NEUE,
            ],
            SystemFontType::TitleBold => vec![
                apple_fonts::HELVETICA_NEUE, // Will be queried with weight=Bold
                apple_fonts::LUCIDA_GRANDE,
            ],
            SystemFontType::Menu => vec![
                apple_fonts::SYSTEM_FONT,
                apple_fonts::HELVETICA_NEUE,
            ],
            SystemFontType::Small => vec![
                apple_fonts::SYSTEM_FONT,
                apple_fonts::HELVETICA_NEUE,
            ],
            // Serif fonts - Georgia has bold variant
            SystemFontType::Serif => vec![
                apple_fonts::NEW_YORK,
                "Georgia",
                "Times New Roman",
            ],
            SystemFontType::SerifBold => vec![
                "Georgia", // Georgia Bold exists
                "Times New Roman",
            ],
        }
    }
    fn windows_fallback_chain(&self) -> Vec<&'static str> {
        match self {
            SystemFontType::Ui | SystemFontType::UiBold => vec![
                windows_fonts::SEGOE_UI_VARIABLE_TEXT,
                windows_fonts::SEGOE_UI,
                windows_fonts::TAHOMA,
            ],
            SystemFontType::Monospace | SystemFontType::MonospaceBold | SystemFontType::MonospaceItalic => vec![
                windows_fonts::CASCADIA_MONO,
                windows_fonts::CASCADIA_CODE,
                windows_fonts::CONSOLAS,
                windows_fonts::LUCIDA_CONSOLE,
                windows_fonts::COURIER_NEW,
            ],
            SystemFontType::Title | SystemFontType::TitleBold => vec![
                windows_fonts::SEGOE_UI_VARIABLE_DISPLAY,
                windows_fonts::SEGOE_UI,
            ],
            SystemFontType::Menu => vec![
                windows_fonts::SEGOE_UI,
                windows_fonts::TAHOMA,
            ],
            SystemFontType::Small => vec![
                windows_fonts::SEGOE_UI,
            ],
            SystemFontType::Serif | SystemFontType::SerifBold => vec![
                "Cambria",
                "Georgia",
                "Times New Roman",
            ],
        }
    }
    fn linux_fallback_chain(&self) -> Vec<&'static str> {
        match self {
            SystemFontType::Ui | SystemFontType::UiBold => vec![
                linux_fonts::CANTARELL,
                linux_fonts::UBUNTU,
                linux_fonts::NOTO_SANS,
                linux_fonts::DEJAVU_SANS,
                linux_fonts::LIBERATION_SANS,
                linux_fonts::SANS_SERIF,
            ],
            SystemFontType::Monospace | SystemFontType::MonospaceBold | SystemFontType::MonospaceItalic => vec![
                linux_fonts::UBUNTU_MONO,
                linux_fonts::HACK,
                linux_fonts::NOTO_MONO,
                linux_fonts::DEJAVU_SANS_MONO,
                linux_fonts::LIBERATION_MONO,
                linux_fonts::MONOSPACE,
            ],
            SystemFontType::Title | SystemFontType::TitleBold => vec![
                linux_fonts::CANTARELL,
                linux_fonts::UBUNTU,
                linux_fonts::NOTO_SANS,
            ],
            SystemFontType::Menu => vec![
                linux_fonts::CANTARELL,
                linux_fonts::UBUNTU,
                linux_fonts::NOTO_SANS,
            ],
            SystemFontType::Small => vec![
                linux_fonts::CANTARELL,
                linux_fonts::UBUNTU,
                linux_fonts::NOTO_SANS,
            ],
            SystemFontType::Serif | SystemFontType::SerifBold => vec![
                linux_fonts::NOTO_SERIF,
                linux_fonts::DEJAVU_SERIF,
                linux_fonts::LIBERATION_SERIF,
                linux_fonts::SERIF,
            ],
        }
    }
    fn android_fallback_chain(&self) -> Vec<&'static str> {
        match self {
            SystemFontType::Ui | SystemFontType::UiBold => vec!["Roboto", "Noto Sans"],
            SystemFontType::Monospace | SystemFontType::MonospaceBold | SystemFontType::MonospaceItalic => {
                vec!["Roboto Mono", "Droid Sans Mono", "monospace"]
            }
            SystemFontType::Title | SystemFontType::TitleBold => vec!["Roboto", "Noto Sans"],
            SystemFontType::Menu => vec!["Roboto"],
            SystemFontType::Small => vec!["Roboto"],
            SystemFontType::Serif | SystemFontType::SerifBold => vec!["Noto Serif", "Droid Serif", "serif"],
        }
    }
    fn generic_fallback_chain(&self) -> Vec<&'static str> {
        match self {
            SystemFontType::Ui | SystemFontType::UiBold => vec!["sans-serif"],
            SystemFontType::Monospace | SystemFontType::MonospaceBold | SystemFontType::MonospaceItalic => {
                vec!["monospace"]
            }
            SystemFontType::Title | SystemFontType::TitleBold => vec!["sans-serif"],
            SystemFontType::Menu => vec!["sans-serif"],
            SystemFontType::Small => vec!["sans-serif"],
            SystemFontType::Serif | SystemFontType::SerifBold => vec!["serif"],
        }
    }
}
impl SystemStyle {
    /// Format the SystemStyle as a human-readable JSON string for debugging.
    ///
    /// This does NOT use serde — it manually formats the most important fields
    /// so that they can be verified against OS-reported values in a test script.
    pub fn to_json_string(&self) -> AzString {
        use alloc::format;
        fn opt_color(c: &OptionColorU) -> alloc::string::String {
            match c.as_ref() {
                Some(c) => format!("\"#{:02x}{:02x}{:02x}{:02x}\"", c.r, c.g, c.b, c.a),
                None => "null".into(),
            }
        }
        fn opt_str(s: &OptionString) -> alloc::string::String {
            match s.as_ref() {
                Some(s) => format!("\"{}\"", s.as_str()),
                None => "null".into(),
            }
        }
        fn opt_f32(v: &OptionF32) -> alloc::string::String {
            match v.into_option() {
                Some(v) => format!("{:.2}", v),
                None => "null".into(),
            }
        }
        fn opt_u16(v: &OptionU16) -> alloc::string::String {
            match v.into_option() {
                Some(v) => format!("{}", v),
                None => "null".into(),
            }
        }
        fn opt_px(v: &OptionPixelValue) -> alloc::string::String {
            match v.as_ref() {
                Some(v) => format!("{:.1}", v.to_pixels_internal(0.0, 0.0, 0.0)),
                None => "null".into(),
            }
        }
        let tm = &self.metrics.titlebar;
        let inp = &self.input;
        let tr = &self.text_rendering;
        let acc = &self.accessibility;
        let sp = &self.scrollbar_preferences;
        let lnx = &self.linux;
        let vh = &self.visual_hints;
        let anim = &self.animation;
        let audio = &self.audio;
        let json = format!(
r#"{{
  "theme": "{:?}",
  "platform": "{:?}",
  "os_version": "{:?}:{}",
  "language": "{}",
  "prefers_reduced_motion": {:?},
  "prefers_high_contrast": {:?},
  "colors": {{
    "text": {},
    "secondary_text": {},
    "tertiary_text": {},
    "background": {},
    "accent": {},
    "accent_text": {},
    "button_face": {},
    "button_text": {},
    "disabled_text": {},
    "window_background": {},
    "under_page_background": {},
    "selection_background": {},
    "selection_text": {},
    "selection_background_inactive": {},
    "selection_text_inactive": {},
    "link": {},
    "separator": {},
    "grid": {},
    "find_highlight": {},
    "sidebar_background": {},
    "sidebar_selection": {}
  }},
  "fonts": {{
    "ui_font": {},
    "ui_font_size": {},
    "monospace_font": {},
    "title_font": {},
    "menu_font": {},
    "small_font": {}
  }},
  "titlebar": {{
    "button_side": "{:?}",
    "height": {},
    "button_area_width": {},
    "padding_horizontal": {},
    "title_font": {},
    "title_font_size": {},
    "title_font_weight": {},
    "has_close": {},
    "has_minimize": {},
    "has_maximize": {},
    "has_fullscreen": {}
  }},
  "input": {{
    "double_click_time_ms": {},
    "double_click_distance_px": {:.1},
    "drag_threshold_px": {:.1},
    "caret_blink_rate_ms": {},
    "caret_width_px": {:.1},
    "wheel_scroll_lines": {},
    "hover_time_ms": {}
  }},
  "text_rendering": {{
    "font_smoothing_enabled": {},
    "subpixel_type": "{:?}",
    "font_smoothing_gamma": {},
    "increased_contrast": {}
  }},
  "accessibility": {{
    "prefers_bold_text": {},
    "prefers_larger_text": {},
    "text_scale_factor": {:.2},
    "prefers_high_contrast": {},
    "prefers_reduced_motion": {},
    "prefers_reduced_transparency": {},
    "screen_reader_active": {},
    "differentiate_without_color": {}
  }},
  "scrollbar_preferences": {{
    "visibility": "{:?}",
    "track_click": "{:?}"
  }},
  "linux": {{
    "gtk_theme": {},
    "icon_theme": {},
    "cursor_theme": {},
    "cursor_size": {},
    "titlebar_button_layout": {}
  }},
  "visual_hints": {{
    "show_button_images": {},
    "show_menu_images": {},
    "toolbar_style": "{:?}",
    "show_tooltips": {}
  }},
  "animation": {{
    "animations_enabled": {},
    "animation_duration_factor": {:.2},
    "focus_indicator_behavior": "{:?}"
  }},
  "audio": {{
    "event_sounds_enabled": {},
    "input_feedback_sounds_enabled": {}
  }}
}}"#,
            // top-level
            self.theme,
            self.platform,
            self.os_version.os, self.os_version.version_id,
            self.language.as_str(),
            self.prefers_reduced_motion,
            self.prefers_high_contrast,
            // colors
            opt_color(&self.colors.text),
            opt_color(&self.colors.secondary_text),
            opt_color(&self.colors.tertiary_text),
            opt_color(&self.colors.background),
            opt_color(&self.colors.accent),
            opt_color(&self.colors.accent_text),
            opt_color(&self.colors.button_face),
            opt_color(&self.colors.button_text),
            opt_color(&self.colors.disabled_text),
            opt_color(&self.colors.window_background),
            opt_color(&self.colors.under_page_background),
            opt_color(&self.colors.selection_background),
            opt_color(&self.colors.selection_text),
            opt_color(&self.colors.selection_background_inactive),
            opt_color(&self.colors.selection_text_inactive),
            opt_color(&self.colors.link),
            opt_color(&self.colors.separator),
            opt_color(&self.colors.grid),
            opt_color(&self.colors.find_highlight),
            opt_color(&self.colors.sidebar_background),
            opt_color(&self.colors.sidebar_selection),
            // fonts
            opt_str(&self.fonts.ui_font),
            opt_f32(&self.fonts.ui_font_size),
            opt_str(&self.fonts.monospace_font),
            opt_str(&self.fonts.title_font),
            opt_str(&self.fonts.menu_font),
            opt_str(&self.fonts.small_font),
            // titlebar
            tm.button_side,
            opt_px(&tm.height),
            opt_px(&tm.button_area_width),
            opt_px(&tm.padding_horizontal),
            opt_str(&tm.title_font),
            opt_f32(&tm.title_font_size),
            opt_u16(&tm.title_font_weight),
            tm.buttons.has_close,
            tm.buttons.has_minimize,
            tm.buttons.has_maximize,
            tm.buttons.has_fullscreen,
            // input
            inp.double_click_time_ms,
            inp.double_click_distance_px,
            inp.drag_threshold_px,
            inp.caret_blink_rate_ms,
            inp.caret_width_px,
            inp.wheel_scroll_lines,
            inp.hover_time_ms,
            // text_rendering
            tr.font_smoothing_enabled,
            tr.subpixel_type,
            tr.font_smoothing_gamma,
            tr.increased_contrast,
            // accessibility
            acc.prefers_bold_text,
            acc.prefers_larger_text,
            acc.text_scale_factor,
            acc.prefers_high_contrast,
            acc.prefers_reduced_motion,
            acc.prefers_reduced_transparency,
            acc.screen_reader_active,
            acc.differentiate_without_color,
            // scrollbar_preferences
            sp.visibility,
            sp.track_click,
            // linux
            opt_str(&lnx.gtk_theme),
            opt_str(&lnx.icon_theme),
            opt_str(&lnx.cursor_theme),
            lnx.cursor_size,
            opt_str(&lnx.titlebar_button_layout),
            // visual_hints
            vh.show_button_images,
            vh.show_menu_images,
            vh.toolbar_style,
            vh.show_tooltips,
            // animation
            anim.animations_enabled,
            anim.animation_duration_factor,
            anim.focus_indicator_behavior,
            // audio
            audio.event_sounds_enabled,
            audio.input_feedback_sounds_enabled,
        );
        AzString::from(json)
    }
    /// Returns a platform-appropriate default system style.
    ///
    /// This returns hard-coded defaults based on the target OS. For actual
    /// runtime detection of the user's theme, colors, and fonts, use the
    /// platform discovery in `azul-dll` (called automatically by `App::create()`).
    pub fn detect() -> Self {
        Self::default_for_platform()
    }
    /// Returns hard-coded defaults for the current compile-time platform.
    pub fn default_for_platform() -> Self {
        #[cfg(target_os = "windows")]
        { defaults::windows_11_light() }
        #[cfg(target_os = "macos")]
        { defaults::macos_modern_light() }
        #[cfg(target_os = "linux")]
        { defaults::gnome_adwaita_light() }
        #[cfg(target_os = "android")]
        { defaults::android_material_light() }
        #[cfg(target_os = "ios")]
        { defaults::ios_light() }
        #[cfg(not(any(
            target_os = "linux",
            target_os = "windows",
            target_os = "macos",
            target_os = "android",
            target_os = "ios"
        )))]
        { Self::default() }
    }
    /// Alias for `detect` - kept for internal compatibility, not exposed in FFI.
    #[inline(always)]
    pub fn new() -> Self {
        Self::detect()
    }
    /// Create a CSS stylesheet for CSD (Client-Side Decorations) titlebar
    ///
    /// This generates CSS rules for the CSD titlebar using system colors,
    /// fonts, and metrics to match the native platform look. Returned rules
    /// carry `rule_priority::SYSTEM`.
    pub fn create_csd_stylesheet(&self) -> Css {
        use alloc::format;
        use crate::parser2::new_from_str;
        // Build CSS string from SystemStyle
        let mut css = String::new();
        // Get system colors with fallbacks
        let bg_color = self
            .colors
            .window_background
            .as_option()
            .copied()
            .unwrap_or(ColorU::new_rgb(240, 240, 240));
        let text_color = self
            .colors
            .text
            .as_option()
            .copied()
            .unwrap_or(ColorU::new_rgb(0, 0, 0));
        let accent_color = self
            .colors
            .accent
            .as_option()
            .copied()
            .unwrap_or(ColorU::new_rgb(0, 120, 215));
        let border_color = match self.theme {
            Theme::Dark => ColorU::new_rgb(60, 60, 60),
            Theme::Light => ColorU::new_rgb(200, 200, 200),
        };
        // Get system metrics with fallbacks
        let corner_radius = self
            .metrics
            .corner_radius
            .map(|px| {
                use crate::props::basic::pixel::DEFAULT_FONT_SIZE;
                format!("{}px", px.to_pixels_internal(1.0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE))
            })
            .unwrap_or_else(|| "4px".to_string());
        // Titlebar container
        css.push_str(&format!(
            ".csd-titlebar {{ width: 100%; height: 32px; background: rgb({}, {}, {}); \
             border-bottom: 1px solid rgb({}, {}, {}); display: flex; flex-direction: row; \
             align-items: center; justify-content: space-between; padding: 0 8px; \
             cursor: grab; user-select: none; }} ",
            bg_color.r, bg_color.g, bg_color.b, border_color.r, border_color.g, border_color.b,
        ));
        // Title text
        css.push_str(&format!(
            ".csd-title {{ color: rgb({}, {}, {}); font-size: 13px; flex-grow: 1; text-align: \
             center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; \
             user-select: none; }} ",
            text_color.r, text_color.g, text_color.b,
        ));
        // Button container
        css.push_str(".csd-buttons { display: flex; flex-direction: row; gap: 4px; } ");
        // Buttons
        css.push_str(&format!(
            ".csd-button {{ width: 32px; height: 24px; border-radius: {}; background: \
             transparent; color: rgb({}, {}, {}); font-size: 16px; line-height: 24px; text-align: \
             center; cursor: pointer; user-select: none; }} ",
            corner_radius, text_color.r, text_color.g, text_color.b,
        ));
        // Button hover state
        let hover_color = match self.theme {
            Theme::Dark => ColorU::new_rgb(60, 60, 60),
            Theme::Light => ColorU::new_rgb(220, 220, 220),
        };
        css.push_str(&format!(
            ".csd-button:hover {{ background: rgb({}, {}, {}); }} ",
            hover_color.r, hover_color.g, hover_color.b,
        ));
        // Close button hover (red on all platforms)
        css.push_str(
            ".csd-close:hover { background: rgb(232, 17, 35); color: rgb(255, 255, 255); } ",
        );
        // Platform-specific button styling
        match self.platform {
            Platform::MacOs => {
                // macOS traffic light buttons (left side)
                css.push_str(".csd-buttons { position: absolute; left: 8px; } ");
                css.push_str(
                    ".csd-close { background: rgb(255, 95, 86); width: 12px; height: 12px; \
                     border-radius: 50%; } ",
                );
                css.push_str(
                    ".csd-minimize { background: rgb(255, 189, 46); width: 12px; height: 12px; \
                     border-radius: 50%; } ",
                );
                css.push_str(
                    ".csd-maximize { background: rgb(40, 201, 64); width: 12px; height: 12px; \
                     border-radius: 50%; } ",
                );
            }
            Platform::Linux(_) => {
                // Linux - title on left, buttons on right
                css.push_str(".csd-title { text-align: left; } ");
            }
            _ => {
                // Windows and others - standard layout
            }
        }
        // Parse CSS string into a Css.
        let (mut parsed_css, _warnings) = new_from_str(&css);
        // Tag every rule as system-level so author CSS overrides win.
        for rule in parsed_css.rules.as_mut() {
            rule.priority = crate::css::rule_priority::SYSTEM;
        }
        parsed_css
    }
}
/// Detect the Linux desktop environment from environment variables.
///
/// Checks `XDG_CURRENT_DESKTOP`, `DESKTOP_SESSION`, and specific env markers
/// to identify GNOME, KDE, XFCE, Cinnamon, MATE, Hyprland, Sway, i3, etc.
pub fn detect_linux_desktop_env() -> DesktopEnvironment {
    // Check XDG_CURRENT_DESKTOP first (most reliable)
    if let Ok(desktop) = std::env::var("XDG_CURRENT_DESKTOP") {
        let desktop_lower = desktop.to_lowercase();
        if desktop_lower.contains("gnome") {
            return DesktopEnvironment::Gnome;
        }
        if desktop_lower.contains("kde") || desktop_lower.contains("plasma") {
            return DesktopEnvironment::Kde;
        }
        if desktop_lower.contains("xfce") {
            return DesktopEnvironment::Other(AzString::from_const_str("XFCE"));
        }
        if desktop_lower.contains("unity") {
            return DesktopEnvironment::Other(AzString::from_const_str("Unity"));
        }
        if desktop_lower.contains("cinnamon") {
            return DesktopEnvironment::Other(AzString::from_const_str("Cinnamon"));
        }
        if desktop_lower.contains("mate") {
            return DesktopEnvironment::Other(AzString::from_const_str("MATE"));
        }
        if desktop_lower.contains("lxde") || desktop_lower.contains("lxqt") {
            return DesktopEnvironment::Other(AzString::from(desktop.to_uppercase()));
        }
        if desktop_lower.contains("budgie") {
            return DesktopEnvironment::Other(AzString::from_const_str("Budgie"));
        }
        if desktop_lower.contains("pantheon") {
            return DesktopEnvironment::Other(AzString::from_const_str("Pantheon"));
        }
        if desktop_lower.contains("deepin") {
            return DesktopEnvironment::Other(AzString::from_const_str("Deepin"));
        }
        if desktop_lower.contains("hyprland") {
            return DesktopEnvironment::Other(AzString::from_const_str("Hyprland"));
        }
        if desktop_lower.contains("sway") {
            return DesktopEnvironment::Other(AzString::from_const_str("Sway"));
        }
        if desktop_lower.contains("i3") {
            return DesktopEnvironment::Other(AzString::from_const_str("i3"));
        }
        return DesktopEnvironment::Other(AzString::from(desktop));
    }
    // Check DESKTOP_SESSION as fallback
    if let Ok(session) = std::env::var("DESKTOP_SESSION") {
        let session_lower = session.to_lowercase();
        if session_lower.contains("gnome") {
            return DesktopEnvironment::Gnome;
        }
        if session_lower.contains("plasma") || session_lower.contains("kde") {
            return DesktopEnvironment::Kde;
        }
        if session_lower.contains("xfce") {
            return DesktopEnvironment::Other(AzString::from_const_str("XFCE"));
        }
        if session_lower.contains("cinnamon") {
            return DesktopEnvironment::Other(AzString::from_const_str("Cinnamon"));
        }
        return DesktopEnvironment::Other(AzString::from(session));
    }
    // Check for specific environment markers
    if std::env::var("GNOME_DESKTOP_SESSION_ID").is_ok() {
        return DesktopEnvironment::Gnome;
    }
    if std::env::var("KDE_FULL_SESSION").is_ok() {
        return DesktopEnvironment::Kde;
    }
    if std::env::var("HYPRLAND_INSTANCE_SIGNATURE").is_ok() {
        return DesktopEnvironment::Other(AzString::from_const_str("Hyprland"));
    }
    if std::env::var("SWAYSOCK").is_ok() {
        return DesktopEnvironment::Other(AzString::from_const_str("Sway"));
    }
    if std::env::var("I3SOCK").is_ok() {
        return DesktopEnvironment::Other(AzString::from_const_str("i3"));
    }
    DesktopEnvironment::Other(AzString::from_const_str("Unknown"))
}
/// Detect the system language as a BCP 47 tag.
///
/// Checks `LANGUAGE`, `LC_ALL`, `LC_MESSAGES`, and `LANG` in priority order.
/// Returns `"en-US"` if detection fails. For runtime detection via native
/// OS APIs, the platform discovery in `azul-dll` overrides this.
pub fn detect_system_language() -> AzString {
    let env_vars = ["LANGUAGE", "LC_ALL", "LC_MESSAGES", "LANG"];
    for var in &env_vars {
        if let Ok(value) = std::env::var(var) {
            let value = value.trim();
            if value.is_empty() || value == "C" || value == "POSIX" {
                continue;
            }
            // Parse locale format: "de_DE.UTF-8" or "de_DE" or "de"
            let lang = value
                .split('.')  // Remove .UTF-8 suffix
                .next()
                .unwrap_or(value)
                .split(':')  // LANGUAGE can be "de:en_US:en"
                .next()
                .unwrap_or(value);
            if !lang.is_empty() {
                return AzString::from(lang.replace('_', "-"));
            }
        }
    }
    AzString::from_const_str("en-US")
}
pub mod defaults {
    //! A collection of hard-coded system style defaults that mimic the appearance
    //! of various operating systems and desktop environments. These are used as a
    //! fallback when the "io" feature is disabled, ensuring deterministic styles
    //! for testing and environments where system calls are not desired.
    use crate::{
        corety::{AzString, OptionF32, OptionString},
        dynamic_selector::{BoolCondition, OsVersion},
        props::{
            basic::{
                color::{ColorU, OptionColorU},
                pixel::{PixelValue, OptionPixelValue},
            },
            layout::{
                dimensions::LayoutWidth,
                spacing::{LayoutPaddingLeft, LayoutPaddingRight},
            },
            style::{
                background::StyleBackgroundContent,
                scrollbar::{
                    ComputedScrollbarStyle, OverflowScrolling, OverscrollBehavior, ScrollBehavior,
                    ScrollPhysics, ScrollbarInfo,
                    SCROLLBAR_ANDROID_DARK, SCROLLBAR_ANDROID_LIGHT, SCROLLBAR_CLASSIC_DARK,
                    SCROLLBAR_CLASSIC_LIGHT, SCROLLBAR_IOS_DARK, SCROLLBAR_IOS_LIGHT,
                    SCROLLBAR_MACOS_DARK, SCROLLBAR_MACOS_LIGHT, SCROLLBAR_WINDOWS_DARK,
                    SCROLLBAR_WINDOWS_LIGHT,
                },
            },
        },
        system::{
            DesktopEnvironment, Platform, SystemColors, SystemFonts, SystemMetrics, SystemStyle,
            Theme, IconStyleOptions, TitlebarMetrics,
        },
    };
    // --- Custom Scrollbar Style Constants for Nostalgia ---
    /// A scrollbar style mimicking the classic Windows 95/98/2000/XP look.
    pub const SCROLLBAR_WINDOWS_CLASSIC: ScrollbarInfo = ScrollbarInfo {
        width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(17)),
        padding_left: LayoutPaddingLeft {
            inner: crate::props::basic::pixel::PixelValue::const_px(0),
        },
        padding_right: LayoutPaddingRight {
            inner: crate::props::basic::pixel::PixelValue::const_px(0),
        },
        track: StyleBackgroundContent::Color(ColorU {
            r: 223,
            g: 223,
            b: 223,
            a: 255,
        }), // Scrollbar trough color
        thumb: StyleBackgroundContent::Color(ColorU {
            r: 208,
            g: 208,
            b: 208,
            a: 255,
        }), // Button face color
        button: StyleBackgroundContent::Color(ColorU {
            r: 208,
            g: 208,
            b: 208,
            a: 255,
        }),
        corner: StyleBackgroundContent::Color(ColorU {
            r: 223,
            g: 223,
            b: 223,
            a: 255,
        }),
        resizer: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
        clip_to_container_border: false,
        scroll_behavior: ScrollBehavior::Auto,
        overscroll_behavior_x: OverscrollBehavior::None,
        overscroll_behavior_y: OverscrollBehavior::None,
        overflow_scrolling: OverflowScrolling::Auto,
    };
    /// A scrollbar style mimicking the macOS "Aqua" theme from the early 2000s.
    pub const SCROLLBAR_MACOS_AQUA: ScrollbarInfo = ScrollbarInfo {
        width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(15)),
        padding_left: LayoutPaddingLeft {
            inner: crate::props::basic::pixel::PixelValue::const_px(0),
        },
        padding_right: LayoutPaddingRight {
            inner: crate::props::basic::pixel::PixelValue::const_px(0),
        },
        track: StyleBackgroundContent::Color(ColorU {
            r: 238,
            g: 238,
            b: 238,
            a: 128,
        }), // Translucent track
        thumb: StyleBackgroundContent::Color(ColorU {
            r: 105,
            g: 173,
            b: 255,
            a: 255,
        }), // "Gel" blue
        button: StyleBackgroundContent::Color(ColorU {
            r: 105,
            g: 173,
            b: 255,
            a: 255,
        }),
        corner: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
        resizer: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
        clip_to_container_border: true,
        scroll_behavior: ScrollBehavior::Smooth,
        overscroll_behavior_x: OverscrollBehavior::Auto,
        overscroll_behavior_y: OverscrollBehavior::Auto,
        overflow_scrolling: OverflowScrolling::Auto,
    };
    /// A scrollbar style mimicking the KDE Oxygen theme.
    pub const SCROLLBAR_KDE_OXYGEN: ScrollbarInfo = ScrollbarInfo {
        width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(14)),
        padding_left: LayoutPaddingLeft {
            inner: crate::props::basic::pixel::PixelValue::const_px(2),
        },
        padding_right: LayoutPaddingRight {
            inner: crate::props::basic::pixel::PixelValue::const_px(2),
        },
        track: StyleBackgroundContent::Color(ColorU {
            r: 242,
            g: 242,
            b: 242,
            a: 255,
        }),
        thumb: StyleBackgroundContent::Color(ColorU {
            r: 177,
            g: 177,
            b: 177,
            a: 255,
        }),
        button: StyleBackgroundContent::Color(ColorU {
            r: 216,
            g: 216,
            b: 216,
            a: 255,
        }),
        corner: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
        resizer: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
        clip_to_container_border: false,
        scroll_behavior: ScrollBehavior::Auto,
        overscroll_behavior_x: OverscrollBehavior::Auto,
        overscroll_behavior_y: OverscrollBehavior::Auto,
        overflow_scrolling: OverflowScrolling::Auto,
    };
    /// Helper to convert a detailed `ScrollbarInfo` into the simplified `ComputedScrollbarStyle`.
    fn scrollbar_info_to_computed(info: &ScrollbarInfo) -> ComputedScrollbarStyle {
        ComputedScrollbarStyle {
            width: Some(info.width.clone()),
            thumb_color: match info.thumb {
                StyleBackgroundContent::Color(c) => Some(c),
                _ => None,
            },
            track_color: match info.track {
                StyleBackgroundContent::Color(c) => Some(c),
                _ => None,
            },
        }
    }
    // --- Windows Styles ---
    /// Windows 11 light mode defaults (Segoe UI Variable, WinUI 3 colors).
    pub fn windows_11_light() -> SystemStyle {
        SystemStyle {
            theme: Theme::Light,
            platform: Platform::Windows,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(0, 0, 0)),
                background: OptionColorU::Some(ColorU::new_rgb(243, 243, 243)),
                accent: OptionColorU::Some(ColorU::new_rgb(0, 95, 184)),
                window_background: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                selection_background: OptionColorU::Some(ColorU::new_rgb(0, 120, 215)),
                selection_text: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some("Segoe UI Variable Text".into()),
                ui_font_size: OptionF32::Some(9.0),
                monospace_font: OptionString::Some("Consolas".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(4.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(12.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(6.0)),
                titlebar: TitlebarMetrics::windows(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_WINDOWS_LIGHT))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::WIN_11,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            scroll_physics: ScrollPhysics::windows(),
            ..Default::default()
        }
    }
    /// Windows 11 dark mode defaults (Segoe UI Variable, WinUI 3 dark colors).
    pub fn windows_11_dark() -> SystemStyle {
        SystemStyle {
            theme: Theme::Dark,
            platform: Platform::Windows,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                background: OptionColorU::Some(ColorU::new_rgb(32, 32, 32)),
                accent: OptionColorU::Some(ColorU::new_rgb(0, 120, 215)),
                window_background: OptionColorU::Some(ColorU::new_rgb(25, 25, 25)),
                selection_background: OptionColorU::Some(ColorU::new_rgb(0, 120, 215)),
                selection_text: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some("Segoe UI Variable Text".into()),
                ui_font_size: OptionF32::Some(9.0),
                monospace_font: OptionString::Some("Consolas".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(4.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(12.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(6.0)),
                titlebar: TitlebarMetrics::windows(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_WINDOWS_DARK))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::WIN_11,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            scroll_physics: ScrollPhysics::windows(),
            ..Default::default()
        }
    }
    /// Windows 7 Aero theme defaults (Segoe UI, classic Aero colors).
    pub fn windows_7_aero() -> SystemStyle {
        SystemStyle {
            theme: Theme::Light,
            platform: Platform::Windows,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(0, 0, 0)),
                background: OptionColorU::Some(ColorU::new_rgb(240, 240, 240)),
                accent: OptionColorU::Some(ColorU::new_rgb(51, 153, 255)),
                window_background: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                selection_background: OptionColorU::Some(ColorU::new_rgb(51, 153, 255)),
                selection_text: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some("Segoe UI".into()),
                ui_font_size: OptionF32::Some(9.0),
                monospace_font: OptionString::Some("Consolas".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(6.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(10.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(5.0)),
                titlebar: TitlebarMetrics::windows(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_CLASSIC_LIGHT))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::WIN_7,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            scroll_physics: ScrollPhysics::windows(),
            ..Default::default()
        }
    }
    /// Windows XP Luna theme defaults (Tahoma, classic Luna blue).
    pub fn windows_xp_luna() -> SystemStyle {
        SystemStyle {
            theme: Theme::Light,
            platform: Platform::Windows,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(0, 0, 0)),
                background: OptionColorU::Some(ColorU::new_rgb(236, 233, 216)),
                accent: OptionColorU::Some(ColorU::new_rgb(49, 106, 197)),
                window_background: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                selection_background: OptionColorU::Some(ColorU::new_rgb(49, 106, 197)),
                selection_text: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some("Tahoma".into()),
                ui_font_size: OptionF32::Some(8.0),
                monospace_font: OptionString::Some("Lucida Console".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(3.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(8.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(4.0)),
                titlebar: TitlebarMetrics::windows(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_WINDOWS_CLASSIC))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::WIN_XP,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            scroll_physics: ScrollPhysics::windows(),
            ..Default::default()
        }
    }
    // --- macOS Styles ---
    /// Modern macOS light mode defaults (SF Pro, rounded corners).
    pub fn macos_modern_light() -> SystemStyle {
        SystemStyle {
            platform: Platform::MacOs,
            theme: Theme::Light,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new(0, 0, 0, 221)),
                background: OptionColorU::Some(ColorU::new_rgb(242, 242, 247)),
                accent: OptionColorU::Some(ColorU::new_rgb(0, 122, 255)),
                window_background: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                // Default macOS selection uses accent color with transparency
                selection_background: OptionColorU::Some(ColorU::new(0, 122, 255, 128)),
                selection_text: OptionColorU::Some(ColorU::new_rgb(0, 0, 0)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some(".SF NS".into()),
                ui_font_size: OptionF32::Some(13.0),
                monospace_font: OptionString::Some("Menlo".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(8.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(16.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(6.0)),
                titlebar: TitlebarMetrics::macos(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_MACOS_LIGHT))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::MACOS_SONOMA,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            scroll_physics: ScrollPhysics::macos(),
            ..Default::default()
        }
    }
    /// Modern macOS dark mode defaults (SF Pro, dark background).
    pub fn macos_modern_dark() -> SystemStyle {
        SystemStyle {
            platform: Platform::MacOs,
            theme: Theme::Dark,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new(255, 255, 255, 221)),
                background: OptionColorU::Some(ColorU::new_rgb(28, 28, 30)),
                accent: OptionColorU::Some(ColorU::new_rgb(10, 132, 255)),
                window_background: OptionColorU::Some(ColorU::new_rgb(44, 44, 46)),
                // Default macOS selection uses accent color with transparency
                selection_background: OptionColorU::Some(ColorU::new(10, 132, 255, 128)),
                selection_text: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some(".SF NS".into()),
                ui_font_size: OptionF32::Some(13.0),
                monospace_font: OptionString::Some("SF Mono".into()),
                monospace_font_size: OptionF32::Some(12.0),
                title_font: OptionString::Some(".SF NS".into()),
                title_font_size: OptionF32::Some(13.0),
                menu_font: OptionString::Some(".SF NS".into()),
                menu_font_size: OptionF32::Some(13.0),
                small_font: OptionString::Some(".SF NS".into()),
                small_font_size: OptionF32::Some(11.0),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(8.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(16.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(6.0)),
                titlebar: TitlebarMetrics::macos(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_MACOS_DARK))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::MACOS_SONOMA,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            scroll_physics: ScrollPhysics::macos(),
            ..Default::default()
        }
    }
    /// Classic macOS Aqua theme defaults (Lucida Grande, gel scrollbars).
    pub fn macos_aqua() -> SystemStyle {
        SystemStyle {
            platform: Platform::MacOs,
            theme: Theme::Light,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(0, 0, 0)),
                background: OptionColorU::Some(ColorU::new_rgb(229, 229, 229)),
                accent: OptionColorU::Some(ColorU::new_rgb(63, 128, 234)),
                window_background: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some("Lucida Grande".into()),
                ui_font_size: OptionF32::Some(13.0),
                monospace_font: OptionString::Some("Monaco".into()),
                monospace_font_size: OptionF32::Some(12.0),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(12.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(16.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(6.0)),
                titlebar: TitlebarMetrics::macos(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_MACOS_AQUA))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::MACOS_TIGER,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            scroll_physics: ScrollPhysics::macos(),
            ..Default::default()
        }
    }
    // --- Linux Styles ---
    /// GNOME Adwaita light theme defaults (Cantarell font).
    pub fn gnome_adwaita_light() -> SystemStyle {
        SystemStyle {
            platform: Platform::Linux(DesktopEnvironment::Gnome),
            theme: Theme::Light,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(46, 52, 54)),
                background: OptionColorU::Some(ColorU::new_rgb(249, 249, 249)),
                accent: OptionColorU::Some(ColorU::new_rgb(53, 132, 228)),
                window_background: OptionColorU::Some(ColorU::new_rgb(237, 237, 237)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some("Cantarell".into()),
                ui_font_size: OptionF32::Some(11.0),
                monospace_font: OptionString::Some("Monospace".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(4.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(12.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(8.0)),
                titlebar: TitlebarMetrics::linux_gnome(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_CLASSIC_LIGHT))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::LINUX_6_0,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            ..Default::default()
        }
    }
    /// GNOME Adwaita dark theme defaults (Cantarell font, dark background).
    pub fn gnome_adwaita_dark() -> SystemStyle {
        SystemStyle {
            platform: Platform::Linux(DesktopEnvironment::Gnome),
            theme: Theme::Dark,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(238, 238, 236)),
                background: OptionColorU::Some(ColorU::new_rgb(36, 36, 36)),
                accent: OptionColorU::Some(ColorU::new_rgb(53, 132, 228)),
                window_background: OptionColorU::Some(ColorU::new_rgb(48, 48, 48)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some("Cantarell".into()),
                ui_font_size: OptionF32::Some(11.0),
                monospace_font: OptionString::Some("Monospace".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(4.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(12.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(8.0)),
                titlebar: TitlebarMetrics::linux_gnome(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_CLASSIC_DARK))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::LINUX_6_0,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            ..Default::default()
        }
    }
    /// GTK2 Clearlooks theme defaults (DejaVu Sans, orange accent).
    pub fn gtk2_clearlooks() -> SystemStyle {
        SystemStyle {
            platform: Platform::Linux(DesktopEnvironment::Gnome),
            theme: Theme::Light,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(0, 0, 0)),
                background: OptionColorU::Some(ColorU::new_rgb(239, 239, 239)),
                accent: OptionColorU::Some(ColorU::new_rgb(245, 121, 0)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some("DejaVu Sans".into()),
                ui_font_size: OptionF32::Some(10.0),
                monospace_font: OptionString::Some("DejaVu Sans Mono".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(4.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(10.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(6.0)),
                titlebar: TitlebarMetrics::linux_gnome(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_CLASSIC_LIGHT))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::LINUX_2_6,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            ..Default::default()
        }
    }
    /// KDE Breeze light theme defaults (Noto Sans, Oxygen scrollbars).
    pub fn kde_breeze_light() -> SystemStyle {
        SystemStyle {
            platform: Platform::Linux(DesktopEnvironment::Kde),
            theme: Theme::Light,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(31, 36, 39)),
                background: OptionColorU::Some(ColorU::new_rgb(239, 240, 241)),
                accent: OptionColorU::Some(ColorU::new_rgb(61, 174, 233)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some("Noto Sans".into()),
                ui_font_size: OptionF32::Some(10.0),
                monospace_font: OptionString::Some("Hack".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(4.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(12.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(6.0)),
                titlebar: TitlebarMetrics::linux_gnome(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_KDE_OXYGEN))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::LINUX_6_0,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            ..Default::default()
        }
    }
    // --- Mobile Styles ---
    /// Android Material Design light theme defaults (Roboto font).
    pub fn android_material_light() -> SystemStyle {
        SystemStyle {
            platform: Platform::Android,
            theme: Theme::Light,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(0, 0, 0)),
                background: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                accent: OptionColorU::Some(ColorU::new_rgb(98, 0, 238)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some("Roboto".into()),
                ui_font_size: OptionF32::Some(14.0),
                monospace_font: OptionString::Some("Droid Sans Mono".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(12.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(16.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(10.0)),
                titlebar: TitlebarMetrics::android(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_ANDROID_LIGHT))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::ANDROID_14,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            scroll_physics: ScrollPhysics::android(),
            ..Default::default()
        }
    }
    /// Android Holo dark theme defaults (Roboto font, dark background).
    pub fn android_holo_dark() -> SystemStyle {
        SystemStyle {
            platform: Platform::Android,
            theme: Theme::Dark,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(255, 255, 255)),
                background: OptionColorU::Some(ColorU::new_rgb(0, 0, 0)),
                accent: OptionColorU::Some(ColorU::new_rgb(51, 181, 229)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some("Roboto".into()),
                ui_font_size: OptionF32::Some(14.0),
                monospace_font: OptionString::Some("Droid Sans Mono".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(2.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(12.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(8.0)),
                titlebar: TitlebarMetrics::android(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_ANDROID_DARK))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::ANDROID_ICE_CREAM_SANDWICH,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            scroll_physics: ScrollPhysics::android(),
            ..Default::default()
        }
    }
    /// iOS light theme defaults (SF UI font, rounded corners).
    pub fn ios_light() -> SystemStyle {
        SystemStyle {
            platform: Platform::Ios,
            theme: Theme::Light,
            colors: SystemColors {
                text: OptionColorU::Some(ColorU::new_rgb(0, 0, 0)),
                background: OptionColorU::Some(ColorU::new_rgb(242, 242, 247)),
                accent: OptionColorU::Some(ColorU::new_rgb(0, 122, 255)),
                ..Default::default()
            },
            fonts: SystemFonts {
                ui_font: OptionString::Some(".SFUI-Display-Regular".into()),
                ui_font_size: OptionF32::Some(17.0),
                monospace_font: OptionString::Some("Menlo".into()),
                ..Default::default()
            },
            metrics: SystemMetrics {
                corner_radius: OptionPixelValue::Some(PixelValue::px(10.0)),
                border_width: OptionPixelValue::Some(PixelValue::px(0.5)),
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(20.0)),
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(12.0)),
                titlebar: TitlebarMetrics::ios(),
            },
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_IOS_LIGHT))),
            app_specific_stylesheet: None,
            icon_style: IconStyleOptions::default(),
            language: AzString::from_const_str("en-US"),
            os_version: OsVersion::IOS_17,
            prefers_reduced_motion: BoolCondition::False,
            prefers_high_contrast: BoolCondition::False,
            scroll_physics: ScrollPhysics::ios(),
            ..Default::default()
        }
    }
}