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
8360
    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
8360
        { 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
8360
    }
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, 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
    /// FFI double-drop guard. `SystemStyle` owns two heap pointers
191
    /// (`app_specific_stylesheet`, `scrollbar`). The codegen Az wrapper
192
    /// (`AzSystemStyle`) gets an `impl Drop` -> `AzSystemStyle_delete` ->
193
    /// `drop_in_place::<SystemStyle>`, and is nested by value as
194
    /// `AzAppConfig.system_style`. Dropping an `AzAppConfig` by value
195
    /// therefore drops the real `SystemStyle` once (freeing both Boxes) and
196
    /// then re-runs `_delete` on the SAME bytes via drop-glue -> double free.
197
    /// Same class as GlContextPtr / IconProviderHandle (see core/src/icon.rs).
198
    /// The first `Drop` disarms this flag; the second sees it cleared and
199
    /// neutralizes itself (takes + forgets the already-freed Boxes) so the
200
    /// redundant drop-glue is a no-op. Defaults to `true` (own + free once).
201
    pub run_destructor: bool,
202
}
203

            
204
impl Default for SystemStyle {
205
51
    fn default() -> Self {
206
51
        SystemStyle {
207
51
            fonts: Default::default(),
208
51
            metrics: Default::default(),
209
51
            linux: Default::default(),
210
51
            platform: Default::default(),
211
51
            focus_visuals: Default::default(),
212
51
            language: Default::default(),
213
51
            app_specific_stylesheet: None,
214
51
            scrollbar: None,
215
51
            scroll_physics: Default::default(),
216
51
            theme: Default::default(),
217
51
            os_version: Default::default(),
218
51
            prefers_reduced_motion: Default::default(),
219
51
            prefers_high_contrast: Default::default(),
220
51
            accessibility: Default::default(),
221
51
            input: Default::default(),
222
51
            text_rendering: Default::default(),
223
51
            scrollbar_preferences: Default::default(),
224
51
            visual_hints: Default::default(),
225
51
            animation: Default::default(),
226
51
            colors: Default::default(),
227
51
            icon_style: Default::default(),
228
51
            audio: Default::default(),
229
51
            run_destructor: true,
230
51
        }
231
51
    }
232
}
233

            
234
impl Drop for SystemStyle {
235
153
    fn drop(&mut self) {
236
        // Gate the heap frees on `run_destructor` to defuse the codegen
237
        // double-drop (see the `run_destructor` field docs). drop_in_place
238
        // runs THIS method, then the field drop-glue; so:
239
        //  * FIRST drop (flag set): disarm the flag, then let the field
240
        //    drop-glue free the two Boxes exactly once.
241
        //  * SECOND drop on the same bytes (flag cleared by the first): the
242
        //    Boxes are already freed but the fields still hold dangling
243
        //    `Some(ptr)`. Take them out (-> None) and forget the dangling
244
        //    values so the trailing drop-glue is a no-op (never derefs/frees).
245
153
        if self.run_destructor {
246
153
            self.run_destructor = false;
247
153
        } else {
248
            core::mem::forget(self.app_specific_stylesheet.take());
249
            core::mem::forget(self.scrollbar.take());
250
        }
251
153
    }
252
}
253

            
254
/// Icon-specific styling options for accessibility and theming.
255
///
256
/// These settings affect how icons are rendered, supporting accessibility
257
/// needs like reduced colors and high contrast modes.
258
#[derive(Debug, Default, Clone, PartialEq)]
259
#[repr(C)]
260
pub struct IconStyleOptions {
261
    /// If true, icons should be rendered in grayscale (for color-blind users
262
    /// or reduced color preference). Applies a CSS grayscale filter.
263
    pub prefer_grayscale: bool,
264
    /// Optional tint color to apply to icons. Useful for matching icons
265
    /// to the current theme or for high contrast modes.
266
    pub tint_color: OptionColorU,
267
    /// If true, icons should inherit the current text color instead of
268
    /// using their original colors. Works well with font-based icons.
269
    pub inherit_text_color: bool,
270
}
271

            
272
/// System font types that can be resolved at runtime based on OS settings.
273
/// 
274
/// This enum allows specifying semantic font roles that get resolved to
275
/// actual font families based on the current platform and user preferences.
276
/// For example, `Monospace` resolves to:
277
/// - macOS: SF Mono or Menlo
278
/// - Windows: Cascadia Mono or Consolas
279
/// - Linux: Ubuntu Mono or DejaVu Sans Mono
280
/// 
281
/// Font variants (bold, italic) can be combined with the base type.
282
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
283
#[repr(C)]
284
#[derive(Default)]
285
pub enum SystemFontType {
286
    /// UI font for buttons, labels, menus (SF Pro, Segoe UI, Cantarell)
287
    #[default]
288
    Ui,
289
    /// Bold variant of UI font
290
    UiBold,
291
    /// Monospace font for code (SF Mono, Consolas, Ubuntu Mono)
292
    Monospace,
293
    /// Bold variant of monospace font
294
    MonospaceBold,
295
    /// Italic variant of monospace font
296
    MonospaceItalic,
297
    /// Font for window titles
298
    Title,
299
    /// Bold variant of title font
300
    TitleBold,
301
    /// Font for menu items
302
    Menu,
303
    /// Small/caption font
304
    Small,
305
    /// Serif font for reading content (New York on macOS, Georgia on Windows)
306
    Serif,
307
    /// Bold variant of serif font
308
    SerifBold,
309
}
310

            
311

            
312
impl SystemFontType {
313
    /// Parse a SystemFontType from a CSS string.
314
    /// 
315
    /// Supported formats:
316
    /// - `system:ui`, `system:ui:bold`
317
    /// - `system:monospace`, `system:monospace:bold`, `system:monospace:italic`
318
    /// - `system:title`, `system:title:bold`
319
    /// - `system:menu`
320
    /// - `system:small`
321
    /// - `system:serif`, `system:serif:bold`
322
231
    pub fn from_css_str(s: &str) -> Option<Self> {
323
231
        let s = s.trim();
324
231
        if !s.starts_with("system:") {
325
            return None;
326
231
        }
327
231
        let rest = &s[7..]; // Skip "system:"
328
231
        match rest {
329
231
            "ui" => Some(SystemFontType::Ui),
330
23
            "ui:bold" => Some(SystemFontType::UiBold),
331
21
            "monospace" => Some(SystemFontType::Monospace),
332
19
            "monospace:bold" => Some(SystemFontType::MonospaceBold),
333
16
            "monospace:italic" => Some(SystemFontType::MonospaceItalic),
334
13
            "title" => Some(SystemFontType::Title),
335
11
            "title:bold" => Some(SystemFontType::TitleBold),
336
9
            "menu" => Some(SystemFontType::Menu),
337
7
            "small" => Some(SystemFontType::Small),
338
5
            "serif" => Some(SystemFontType::Serif),
339
3
            "serif:bold" => Some(SystemFontType::SerifBold),
340
1
            _ => None,
341
        }
342
231
    }
343
    
344
    /// Get the CSS syntax for this system font type.
345
11
    pub fn as_css_str(&self) -> &'static str {
346
11
        match self {
347
1
            SystemFontType::Ui => "system:ui",
348
1
            SystemFontType::UiBold => "system:ui:bold",
349
1
            SystemFontType::Monospace => "system:monospace",
350
1
            SystemFontType::MonospaceBold => "system:monospace:bold",
351
1
            SystemFontType::MonospaceItalic => "system:monospace:italic",
352
1
            SystemFontType::Title => "system:title",
353
1
            SystemFontType::TitleBold => "system:title:bold",
354
1
            SystemFontType::Menu => "system:menu",
355
1
            SystemFontType::Small => "system:small",
356
1
            SystemFontType::Serif => "system:serif",
357
1
            SystemFontType::SerifBold => "system:serif:bold",
358
        }
359
11
    }
360
    
361
    /// Returns true if this system font type implies bold weight.
362
    /// Used when resolving system fonts to pass the correct weight to fontconfig.
363
6468
    pub fn is_bold(&self) -> bool {
364
6468
        matches!(
365
6468
            self,
366
            SystemFontType::UiBold
367
                | SystemFontType::MonospaceBold
368
                | SystemFontType::TitleBold
369
                | SystemFontType::SerifBold
370
        )
371
6468
    }
372
    
373
    /// Returns true if this system font type implies italic style.
374
6468
    pub fn is_italic(&self) -> bool {
375
6468
        matches!(self, SystemFontType::MonospaceItalic)
376
6468
    }
377
}
378

            
379
/// Accessibility settings detected from the operating system.
380
/// 
381
/// These settings allow apps to adapt their UI for users with accessibility needs.
382
/// Detection methods:
383
/// - macOS: UIAccessibility APIs (isBoldTextEnabled, isReduceMotionEnabled, etc.)
384
/// - Windows: SystemParametersInfo (SPI_GETHIGHCONTRAST, SPI_GETCLIENTAREAANIMATION)
385
/// - Linux: gsettings (org.gnome.desktop.interface, org.gnome.desktop.a11y)
386
#[derive(Debug, Default, Clone, PartialEq)]
387
#[repr(C)]
388
pub struct AccessibilitySettings {
389
    /// Text scaling factor (1.0 = normal, 1.5 = 150%, etc.)
390
    pub text_scale_factor: f32,
391
    /// User prefers bold text for better readability
392
    /// macOS: UIAccessibility.isBoldTextEnabled
393
    /// Windows: N/A (font scaling)
394
    /// Linux: org.gnome.desktop.interface text-scaling-factor
395
    pub prefers_bold_text: bool,
396
    /// User prefers larger text
397
    /// macOS: preferredContentSizeCategory
398
    /// Windows: SystemParametersInfo text scale factor
399
    /// Linux: org.gnome.desktop.interface text-scaling-factor
400
    pub prefers_larger_text: bool,
401
    /// User prefers high contrast colors
402
    /// macOS: UIAccessibility.isDarkerSystemColorsEnabled
403
    /// Windows: SPI_GETHIGHCONTRAST
404
    /// Linux: org.gnome.desktop.a11y.interface high-contrast
405
    pub prefers_high_contrast: bool,
406
    /// User prefers reduced motion/animations
407
    /// macOS: UIAccessibility.isReduceMotionEnabled
408
    /// Windows: SPI_GETCLIENTAREAANIMATION (inverted)
409
    /// Linux: org.gnome.desktop.interface enable-animations (inverted)
410
    pub prefers_reduced_motion: bool,
411
    /// User prefers reduced transparency
412
    /// macOS: UIAccessibility.isReduceTransparencyEnabled
413
    /// Windows: N/A
414
    /// Linux: N/A
415
    pub prefers_reduced_transparency: bool,
416
    /// Screen reader is active (VoiceOver, Narrator, Orca)
417
    pub screen_reader_active: bool,
418
    /// User prefers differentiate without color
419
    /// macOS: UIAccessibility.shouldDifferentiateWithoutColor
420
    pub differentiate_without_color: bool,
421
}
422

            
423
/// Common system colors used for UI elements.
424
/// 
425
/// These colors are queried from the operating system and automatically adapt
426
/// to the current theme (light/dark mode) and accent color settings.
427
/// 
428
/// On macOS, these correspond to NSColor semantic colors.
429
/// On Windows, these come from UISettings.
430
/// On Linux/GTK, these come from the GTK theme.
431
#[derive(Debug, Default, Clone, PartialEq)]
432
#[repr(C)]
433
pub struct SystemColors {
434
    // === Primary semantic colors ===
435
    /// Primary text color (NSColor.textColor on macOS)
436
    pub text: OptionColorU,
437
    /// Secondary text color for less prominent text (NSColor.secondaryLabelColor)
438
    pub secondary_text: OptionColorU,
439
    /// Tertiary text color for disabled/placeholder text (NSColor.tertiaryLabelColor)
440
    pub tertiary_text: OptionColorU,
441
    /// Background color for content areas (NSColor.textBackgroundColor)
442
    pub background: OptionColorU,
443
    
444
    // === Accent colors ===
445
    /// System accent color chosen by user (NSColor.controlAccentColor on macOS)
446
    pub accent: OptionColorU,
447
    /// Text color on accent backgrounds
448
    pub accent_text: OptionColorU,
449
    
450
    // === Control colors ===
451
    /// Button/control background (NSColor.controlColor)
452
    pub button_face: OptionColorU,
453
    /// Button/control text color (NSColor.controlTextColor)
454
    pub button_text: OptionColorU,
455
    /// Disabled control text color (NSColor.disabledControlTextColor)
456
    pub disabled_text: OptionColorU,
457
    
458
    // === Window colors ===
459
    /// Window background color (NSColor.windowBackgroundColor)
460
    pub window_background: OptionColorU,
461
    /// Under-page background color (NSColor.underPageBackgroundColor)
462
    pub under_page_background: OptionColorU,
463
    
464
    // === Selection colors ===
465
    /// Selection background when window is focused (NSColor.selectedContentBackgroundColor)
466
    pub selection_background: OptionColorU,
467
    /// Selection text color when window is focused
468
    pub selection_text: OptionColorU,
469
    /// Selection background when window is NOT focused (NSColor.unemphasizedSelectedContentBackgroundColor)
470
    /// This is used for :backdrop state styling
471
    pub selection_background_inactive: OptionColorU,
472
    /// Selection text color when window is NOT focused
473
    pub selection_text_inactive: OptionColorU,
474
    
475
    // === Additional semantic colors ===
476
    /// Link color (NSColor.linkColor)
477
    pub link: OptionColorU,
478
    /// Separator/divider color (NSColor.separatorColor)
479
    pub separator: OptionColorU,
480
    /// Grid/table line color (NSColor.gridColor)
481
    pub grid: OptionColorU,
482
    /// Find/search highlight color (NSColor.findHighlightColor)
483
    pub find_highlight: OptionColorU,
484
    
485
    // === Sidebar colors (macOS-specific) ===
486
    /// Sidebar background color
487
    pub sidebar_background: OptionColorU,
488
    /// Selected row in sidebar
489
    pub sidebar_selection: OptionColorU,
490
}
491

            
492
/// Common system font settings.
493
/// 
494
/// On macOS, these are queried from NSFont.
495
/// On Windows, these come from SystemParametersInfo.
496
/// On Linux, these come from GTK/gsettings.
497
#[derive(Debug, Default, Clone, PartialEq)]
498
#[repr(C)]
499
pub struct SystemFonts {
500
    /// The primary font used for UI elements like buttons and labels.
501
    /// On macOS: SF Pro (system font)
502
    /// On Windows: Segoe UI
503
    /// On Linux: Cantarell, Ubuntu, or system default
504
    pub ui_font: OptionString,
505
    /// The default font size for UI elements, in points.
506
    pub ui_font_size: OptionF32,
507
    /// The font used for code or other monospaced text.
508
    /// On macOS: SF Mono or Menlo
509
    /// On Windows: Cascadia Mono or Consolas
510
    /// On Linux: Ubuntu Mono or DejaVu Sans Mono
511
    pub monospace_font: OptionString,
512
    /// Monospace font size in points
513
    pub monospace_font_size: OptionF32,
514
    /// Bold variant of the UI font (if different)
515
    pub ui_font_bold: OptionString,
516
    /// Font for window titles
517
    pub title_font: OptionString,
518
    /// Title font size in points
519
    pub title_font_size: OptionF32,
520
    /// Font for menu items
521
    pub menu_font: OptionString,
522
    /// Menu font size in points
523
    pub menu_font_size: OptionF32,
524
    /// Small/caption font for less prominent text
525
    pub small_font: OptionString,
526
    /// Small font size in points
527
    pub small_font_size: OptionF32,
528
}
529

            
530
/// Common system metrics for UI element sizing and spacing.
531
#[derive(Debug, Default, Clone, PartialEq)]
532
#[repr(C)]
533
pub struct SystemMetrics {
534
    /// The corner radius for standard elements like buttons.
535
    pub corner_radius: OptionPixelValue,
536
    /// The width of standard borders.
537
    pub border_width: OptionPixelValue,
538
    /// The horizontal (left/right) padding for buttons and similar controls.
539
    pub button_padding_horizontal: OptionPixelValue,
540
    /// The vertical (top/bottom) padding for buttons and similar controls.
541
    pub button_padding_vertical: OptionPixelValue,
542
    /// Titlebar layout information (button positions, safe areas, etc.)
543
    pub titlebar: TitlebarMetrics,
544
}
545

            
546
/// Which side of the titlebar the window control buttons are on.
547
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
548
#[repr(C)]
549
pub enum TitlebarButtonSide {
550
    /// Buttons are on the left (macOS default)
551
    Left,
552
    /// Buttons are on the right (Windows, most Linux DEs)
553
    #[default]
554
    Right,
555
}
556

            
557
/// Which window control buttons are available in the titlebar.
558
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
559
#[repr(C)]
560
pub struct TitlebarButtons {
561
    /// Close button is available
562
    pub has_close: bool,
563
    /// Minimize button is available
564
    pub has_minimize: bool,
565
    /// Maximize/zoom button is available
566
    pub has_maximize: bool,
567
    /// Fullscreen button is available (macOS green button behavior)
568
    pub has_fullscreen: bool,
569
}
570

            
571
impl Default for TitlebarButtons {
572
51
    fn default() -> Self {
573
51
        Self {
574
51
            has_close: true,
575
51
            has_minimize: true,
576
51
            has_maximize: true,
577
51
            has_fullscreen: false,
578
51
        }
579
51
    }
580
}
581

            
582
/// Safe area insets for devices with notches, rounded corners, or sensor housings.
583
/// 
584
/// On devices like iPhones with notches or Dynamic Island, the safe area
585
/// indicates regions where content should not be placed to avoid being
586
/// obscured by hardware features.
587
#[derive(Debug, Default, Clone, Copy, PartialEq)]
588
#[repr(C)]
589
pub struct SafeAreaInsets {
590
    /// Inset from the top edge (notch, camera housing, etc.)
591
    pub top: OptionPixelValue,
592
    /// Inset from the bottom edge (home indicator on iPhone)
593
    pub bottom: OptionPixelValue,
594
    /// Inset from the left edge (rounded corners)
595
    pub left: OptionPixelValue,
596
    /// Inset from the right edge (rounded corners)
597
    pub right: OptionPixelValue,
598
}
599

            
600
/// Metrics for titlebar layout and window chrome.
601
/// 
602
/// This provides information needed to correctly position custom titlebar
603
/// content when using `WindowDecorations::NoTitle` (expanded title mode).
604
#[derive(Debug, Clone, PartialEq)]
605
#[repr(C)]
606
pub struct TitlebarMetrics {
607
    /// Which side the window control buttons are on
608
    pub button_side: TitlebarButtonSide,
609
    /// Which buttons are available
610
    pub buttons: TitlebarButtons,
611
    /// Height of the titlebar in pixels
612
    pub height: OptionPixelValue,
613
    /// Width reserved for window control buttons (close/min/max)
614
    /// This is the space to avoid when drawing custom title text
615
    pub button_area_width: OptionPixelValue,
616
    /// Horizontal padding inside the titlebar
617
    pub padding_horizontal: OptionPixelValue,
618
    /// Safe area insets for notched/rounded displays
619
    pub safe_area: SafeAreaInsets,
620
    /// Title text font (from SystemFonts::title_font)
621
    pub title_font: OptionString,
622
    /// Title text font size
623
    pub title_font_size: OptionF32,
624
    /// Title text font weight (400 = normal, 600 = semibold, 700 = bold)
625
    pub title_font_weight: OptionU16,
626
}
627

            
628
impl Default for TitlebarMetrics {
629
51
    fn default() -> Self {
630
51
        Self {
631
51
            button_side: TitlebarButtonSide::Right,
632
51
            buttons: TitlebarButtons::default(),
633
51
            height: OptionPixelValue::Some(PixelValue::px(32.0)),
634
51
            button_area_width: OptionPixelValue::Some(PixelValue::px(100.0)),
635
51
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(8.0)),
636
51
            safe_area: SafeAreaInsets::default(),
637
51
            title_font: OptionString::None,
638
51
            title_font_size: OptionF32::Some(13.0),
639
51
            title_font_weight: OptionU16::Some(600), // Semibold
640
51
        }
641
51
    }
642
}
643

            
644
impl TitlebarMetrics {
645
    /// Windows-style titlebar (buttons on right)
646
    pub fn windows() -> Self {
647
        Self {
648
            button_side: TitlebarButtonSide::Right,
649
            buttons: TitlebarButtons {
650
                has_close: true,
651
                has_minimize: true,
652
                has_maximize: true,
653
                has_fullscreen: false,
654
            },
655
            height: OptionPixelValue::Some(PixelValue::px(32.0)),
656
            button_area_width: OptionPixelValue::Some(PixelValue::px(138.0)), // 3 buttons * 46px
657
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(8.0)),
658
            safe_area: SafeAreaInsets::default(),
659
            title_font: OptionString::Some("Segoe UI Variable Text".into()),
660
            title_font_size: OptionF32::Some(12.0),
661
            title_font_weight: OptionU16::Some(400), // Normal
662
        }
663
    }
664
    
665
    /// macOS-style titlebar (buttons on left, "traffic lights")
666
    pub fn macos() -> Self {
667
        Self {
668
            button_side: TitlebarButtonSide::Left,
669
            buttons: TitlebarButtons {
670
                has_close: true,
671
                has_minimize: true,
672
                has_maximize: false, // macOS has fullscreen instead
673
                has_fullscreen: true,
674
            },
675
            height: OptionPixelValue::Some(PixelValue::px(28.0)),
676
            button_area_width: OptionPixelValue::Some(PixelValue::px(78.0)), // 3 buttons with gaps
677
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(8.0)),
678
            safe_area: SafeAreaInsets::default(),
679
            title_font: OptionString::Some(".SF NS".into()),
680
            title_font_size: OptionF32::Some(13.0),
681
            title_font_weight: OptionU16::Some(600), // Semibold
682
        }
683
    }
684
    
685
    /// Linux GNOME-style titlebar (buttons on right by default)
686
102
    pub fn linux_gnome() -> Self {
687
102
        Self {
688
102
            button_side: TitlebarButtonSide::Right, // Default, can be changed in settings
689
102
            buttons: TitlebarButtons {
690
102
                has_close: true,
691
102
                has_minimize: true,
692
102
                has_maximize: true,
693
102
                has_fullscreen: false,
694
102
            },
695
102
            height: OptionPixelValue::Some(PixelValue::px(35.0)),
696
102
            button_area_width: OptionPixelValue::Some(PixelValue::px(100.0)),
697
102
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(12.0)),
698
102
            safe_area: SafeAreaInsets::default(),
699
102
            title_font: OptionString::Some("Cantarell".into()),
700
102
            title_font_size: OptionF32::Some(11.0),
701
102
            title_font_weight: OptionU16::Some(700), // Bold
702
102
        }
703
102
    }
704
    
705
    /// iOS-style safe area (for notched devices)
706
    pub fn ios() -> Self {
707
        Self {
708
            button_side: TitlebarButtonSide::Left,
709
            buttons: TitlebarButtons {
710
                has_close: false, // iOS apps don't have close buttons
711
                has_minimize: false,
712
                has_maximize: false,
713
                has_fullscreen: false,
714
            },
715
            height: OptionPixelValue::Some(PixelValue::px(44.0)),
716
            button_area_width: OptionPixelValue::Some(PixelValue::px(0.0)),
717
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(16.0)),
718
            safe_area: SafeAreaInsets {
719
                // iPhone notch safe area
720
                top: OptionPixelValue::Some(PixelValue::px(47.0)),
721
                bottom: OptionPixelValue::Some(PixelValue::px(34.0)),
722
                left: OptionPixelValue::None,
723
                right: OptionPixelValue::None,
724
            },
725
            title_font: OptionString::Some(".SFUI-Semibold".into()),
726
            title_font_size: OptionF32::Some(17.0),
727
            title_font_weight: OptionU16::Some(600),
728
        }
729
    }
730
    
731
    /// Android-style titlebar (action bar)
732
    pub fn android() -> Self {
733
        Self {
734
            button_side: TitlebarButtonSide::Left, // Back button on left
735
            buttons: TitlebarButtons {
736
                has_close: false,
737
                has_minimize: false,
738
                has_maximize: false,
739
                has_fullscreen: false,
740
            },
741
            height: OptionPixelValue::Some(PixelValue::px(56.0)),
742
            button_area_width: OptionPixelValue::Some(PixelValue::px(48.0)), // Back button
743
            padding_horizontal: OptionPixelValue::Some(PixelValue::px(16.0)),
744
            safe_area: SafeAreaInsets::default(),
745
            title_font: OptionString::Some("Roboto Medium".into()),
746
            title_font_size: OptionF32::Some(20.0),
747
            title_font_weight: OptionU16::Some(500),
748
        }
749
    }
750
}
751

            
752
// ── Input interaction metrics ────────────────────────────────────────────
753

            
754
/// Input interaction timing and distance thresholds from the OS.
755
///
756
/// These values are queried from the operating system to match the user's
757
/// configured double-click speed, drag sensitivity, caret blink rate, etc.
758
///
759
/// # Platform APIs
760
/// - **macOS:** `NSEvent.doubleClickInterval`
761
/// - **Windows:** `GetDoubleClickTime()`, `GetSystemMetrics(SM_CXDOUBLECLK)`,
762
///   `GetCaretBlinkTime()`, `SystemParametersInfo(SPI_GETWHEELSCROLLLINES)`
763
/// - **Linux:** XDG Desktop Portal / gsettings
764
#[derive(Debug, Clone, Copy, PartialEq)]
765
#[repr(C)]
766
pub struct InputMetrics {
767
    /// Max milliseconds between clicks to register a double-click.
768
    pub double_click_time_ms: u32,
769
    /// Max pixels the mouse can move between clicks and still count.
770
    pub double_click_distance_px: f32,
771
    /// Pixels the mouse must move while held down before a drag starts.
772
    pub drag_threshold_px: f32,
773
    /// Caret blink rate in milliseconds (0 = no blink).
774
    pub caret_blink_rate_ms: u32,
775
    /// Width of the text caret/cursor in pixels (typically 1–2).
776
    pub caret_width_px: f32,
777
    /// Lines to scroll per mouse wheel notch.
778
    pub wheel_scroll_lines: u32,
779
    /// Milliseconds to wait before a hover triggers (e.g. tooltip delay).
780
    /// Windows: `SystemParametersInfo(SPI_GETMOUSEHOVERTIME)` — default 400.
781
    pub hover_time_ms: u32,
782
}
783

            
784
impl Default for InputMetrics {
785
153
    fn default() -> Self {
786
153
        Self {
787
153
            double_click_time_ms: 500,
788
153
            double_click_distance_px: 4.0,
789
153
            drag_threshold_px: 5.0,
790
153
            caret_blink_rate_ms: 530,
791
153
            caret_width_px: 1.0,
792
153
            wheel_scroll_lines: 3,
793
153
            hover_time_ms: 400,
794
153
        }
795
153
    }
796
}
797

            
798
// ── Text rendering hints ─────────────────────────────────────────────────
799

            
800
/// Subpixel rendering layout for font smoothing.
801
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
802
#[repr(C)]
803
pub enum SubpixelType {
804
    /// No subpixel rendering (grayscale anti-aliasing only).
805
    #[default]
806
    None,
807
    /// Horizontal RGB subpixel layout (most common for LCD monitors).
808
    Rgb,
809
    /// Horizontal BGR subpixel layout.
810
    Bgr,
811
    /// Vertical RGB subpixel layout.
812
    VRgb,
813
    /// Vertical BGR subpixel layout.
814
    VBgr,
815
}
816

            
817
/// Text rendering configuration from the OS.
818
///
819
/// These hints allow the framework to match the host's font smoothing
820
/// settings for crisp, consistent text rendering.
821
#[derive(Debug, Clone, Copy, PartialEq)]
822
#[repr(C)]
823
pub struct TextRenderingHints {
824
    /// Subpixel rendering type.
825
    pub subpixel_type: SubpixelType,
826
    /// Font smoothing gamma (1000 = default, higher = more contrast).
827
    pub font_smoothing_gamma: u32,
828
    /// Whether font smoothing (anti-aliasing) is enabled.
829
    pub font_smoothing_enabled: bool,
830
    /// User prefers increased text contrast.
831
    pub increased_contrast: bool,
832
}
833

            
834
impl Default for TextRenderingHints {
835
153
    fn default() -> Self {
836
153
        Self {
837
153
            subpixel_type: SubpixelType::None,
838
153
            font_smoothing_gamma: 1000,
839
153
            font_smoothing_enabled: true,
840
153
            increased_contrast: false,
841
153
        }
842
153
    }
843
}
844

            
845
// ── Focus ring visuals ───────────────────────────────────────────────────
846

            
847
/// Focus ring / indicator visual style.
848
///
849
/// When an element receives keyboard focus the OS typically draws a visible
850
/// ring or border.  These values come from the OS preferences.
851
#[derive(Debug, Default, Clone, Copy, PartialEq)]
852
#[repr(C)]
853
pub struct FocusVisuals {
854
    /// Focus ring / indicator colour.
855
    /// macOS: `NSColor.keyboardFocusIndicatorColor`
856
    pub focus_ring_color: OptionColorU,
857
    /// Width of focus border / ring.
858
    /// Windows: `SystemParametersInfo(SPI_GETFOCUSBORDERWIDTH)`
859
    pub focus_border_width: OptionPixelValue,
860
    /// Height of focus border / ring.
861
    pub focus_border_height: OptionPixelValue,
862
}
863

            
864
// ── Scrollbar preferences ────────────────────────────────────────────────
865

            
866
/// When scrollbars should be shown (OS-level preference).
867
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
868
#[repr(C)]
869
pub enum ScrollbarVisibility {
870
    /// Always show scrollbars.
871
    Always,
872
    /// Show only while scrolling, then fade out.
873
    #[default]
874
    WhenScrolling,
875
    /// Automatic: depends on input device (trackpad → overlay, mouse → always).
876
    Automatic,
877
}
878

            
879
/// What happens when clicking the scrollbar track area.
880
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
881
#[repr(C)]
882
pub enum ScrollbarTrackClick {
883
    /// Jump to the clicked position.
884
    JumpToPosition,
885
    /// Scroll by one page.
886
    #[default]
887
    PageUpDown,
888
}
889

            
890
/// OS-level scrollbar behaviour preferences.
891
///
892
/// These are separate from the CSS scrollbar *appearance* (`ComputedScrollbarStyle`).
893
/// They control *when* scrollbars appear and *how* clicking the track behaves.
894
#[derive(Debug, Clone, Copy, PartialEq)]
895
#[repr(C)]
896
pub struct ScrollbarPreferences {
897
    /// How scrollbars should be shown.
898
    /// macOS: `NSScroller.preferredScrollerStyle`
899
    pub visibility: ScrollbarVisibility,
900
    /// What happens when clicking the scrollbar track.
901
    pub track_click: ScrollbarTrackClick,
902
}
903

            
904
impl Default for ScrollbarPreferences {
905
153
    fn default() -> Self {
906
153
        Self {
907
153
            visibility: ScrollbarVisibility::WhenScrolling,
908
153
            track_click: ScrollbarTrackClick::PageUpDown,
909
153
        }
910
153
    }
911
}
912

            
913
// ── Linux-specific customisation ─────────────────────────────────────────
914

            
915
/// Linux-specific customisation settings.
916
///
917
/// Read from GTK / KDE / XDG settings on Linux; `Default` (all `None` / 0)
918
/// on other platforms.
919
#[derive(Debug, Default, Clone, PartialEq)]
920
#[repr(C)]
921
pub struct LinuxCustomization {
922
    /// GTK theme name (e.g. "Adwaita", "Breeze", "Numix").
923
    pub gtk_theme: OptionString,
924
    /// Icon theme name (e.g. "Papirus", "Numix", "Breeze").
925
    pub icon_theme: OptionString,
926
    /// Cursor theme name (e.g. "Breeze_Snow", "DMZ-Black").
927
    pub cursor_theme: OptionString,
928
    /// Cursor size in pixels (0 = unset / use OS default).
929
    pub cursor_size: u32,
930
    /// GTK button layout string (e.g. "close,minimize,maximize:menu").
931
    /// Determines button side and order for CSD titlebars on Linux.
932
    pub titlebar_button_layout: OptionString,
933
}
934

            
935
// ── Visual hints (icons in menus / buttons / toolbar style) ──────────────
936

            
937
/// Toolbar display style (icons, text, or both).
938
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
939
#[repr(C)]
940
pub enum ToolbarStyle {
941
    /// Show only icons in toolbars.
942
    #[default]
943
    IconsOnly,
944
    /// Show only text labels in toolbars.
945
    TextOnly,
946
    /// Show text beside the icon (horizontal).
947
    TextBesideIcon,
948
    /// Show text below the icon (vertical).
949
    TextBelowIcon,
950
}
951

            
952
/// Visual hints from the OS about how icons and decorations should be shown.
953
///
954
/// These preferences differ heavily between Linux desktops (KDE vs GNOME)
955
/// and are less configurable on macOS / Windows where HIG rules apply.
956
#[derive(Debug, Clone, Copy, PartialEq)]
957
#[repr(C)]
958
pub struct VisualHints {
959
    /// Toolbar display style.
960
    /// Linux: `org.gnome.desktop.interface toolbar-style`, KDE `ToolButtonStyle`.
961
    pub toolbar_style: ToolbarStyle,
962
    /// Show icons on push buttons?  (Common in KDE, rare in Win/Mac.)
963
    /// Linux: `org.gnome.desktop.interface buttons-have-icons`, KDE ShowIconsOnPushButtons.
964
    pub show_button_images: bool,
965
    /// Show icons in context menus?  (GNOME defaults off since 3.x; Win/Mac/KDE usually on.)
966
    /// Linux: `org.gnome.desktop.interface menus-have-icons`.
967
    pub show_menu_images: bool,
968
    /// Should tooltips be shown on hover?
969
    pub show_tooltips: bool,
970
    /// Flash the window taskbar entry on alert?
971
    pub flash_on_alert: bool,
972
}
973

            
974
impl Default for VisualHints {
975
153
    fn default() -> Self {
976
153
        Self {
977
153
            toolbar_style: ToolbarStyle::IconsOnly,
978
153
            show_button_images: false,
979
153
            show_menu_images: true,
980
153
            show_tooltips: true,
981
153
            flash_on_alert: true,
982
153
        }
983
153
    }
984
}
985

            
986
// ── Animation metrics ────────────────────────────────────────────────────
987

            
988
/// Focus indicator behaviour (always visible vs keyboard-only).
989
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
990
#[repr(C)]
991
pub enum FocusBehavior {
992
    /// Focus indicators are always visible when an element has focus.
993
    #[default]
994
    AlwaysVisible,
995
    /// Focus indicators are hidden until the user presses a keyboard key
996
    /// (Alt, Tab, arrow keys, etc.).  Windows: `SPI_GETKEYBOARDCUES`.
997
    KeyboardOnly,
998
}
999

            
/// Animation-related preferences from the OS.
///
/// These control whether UI animations (transitions, fades, slides) should
/// play and at what speed.
///
/// # Platform APIs
/// - **Windows:** `SystemParametersInfo(SPI_GETCLIENTAREAANIMATION)`,
///   `SPI_GETKEYBOARDCUES`
/// - **macOS:** `NSWorkspace.accessibilityDisplayShouldReduceMotion`
/// - **Linux:** `org.gnome.desktop.interface enable-animations`,
///   KDE `AnimationDurationFactor`
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct AnimationMetrics {
    /// Global enable/disable for UI animations.
    pub animations_enabled: bool,
    /// Animation speed factor (1.0 = normal, 0.5 = 2× faster, 2.0 = 2× slower).
    /// Primarily used in KDE.
    pub animation_duration_factor: f32,
    /// When to show focus rectangles / rings.
    pub focus_indicator_behavior: FocusBehavior,
}
impl Default for AnimationMetrics {
153
    fn default() -> Self {
153
        Self {
153
            animations_enabled: true,
153
            animation_duration_factor: 1.0,
153
            focus_indicator_behavior: FocusBehavior::AlwaysVisible,
153
        }
153
    }
}
// ── Audio metrics ────────────────────────────────────────────────────────
/// Audio-feedback preferences from the OS.
///
/// Controls whether the app should make sounds on events (error pings,
/// notifications) or on input (clicks, key presses).
///
/// # Platform APIs
/// - **Windows:** `SystemParametersInfo(SPI_GETBEEP)`
/// - **macOS:** `NSSound.soundEffectAudioVolume`
/// - **Linux:** `org.gnome.desktop.sound event-sounds`,
///   `org.gnome.desktop.sound input-feedback-sounds`
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct AudioMetrics {
    /// Should the app make sounds on events?  (Error ping, notification, etc.)
    pub event_sounds_enabled: bool,
    /// Should the app make sounds on input?  (Clicks, typing feedback.)
    pub input_feedback_sounds_enabled: bool,
}
impl Default for AudioMetrics {
153
    fn default() -> Self {
153
        Self {
153
            event_sounds_enabled: true,
153
            input_feedback_sounds_enabled: false,
153
        }
153
    }
}
/// 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.
7497
    pub fn get_fallback_chain(&self, platform: &Platform) -> Vec<&'static str> {
7497
        match platform {
            Platform::MacOs | Platform::Ios => self.macos_fallback_chain(),
            Platform::Windows => self.windows_fallback_chain(),
7497
            Platform::Linux(_) => self.linux_fallback_chain(),
            Platform::Android => self.android_fallback_chain(),
            Platform::Unknown => self.generic_fallback_chain(),
        }
7497
    }
    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",
            ],
        }
    }
7497
    fn linux_fallback_chain(&self) -> Vec<&'static str> {
7497
        match self {
7497
            SystemFontType::Ui | SystemFontType::UiBold => vec![
7497
                linux_fonts::CANTARELL,
7497
                linux_fonts::UBUNTU,
7497
                linux_fonts::NOTO_SANS,
7497
                linux_fonts::DEJAVU_SANS,
7497
                linux_fonts::LIBERATION_SANS,
7497
                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,
            ],
        }
7497
    }
    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.
102
    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")]
102
        { 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() }
102
    }
    /// 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`.
102
    fn scrollbar_info_to_computed(info: &ScrollbarInfo) -> ComputedScrollbarStyle {
        ComputedScrollbarStyle {
102
            width: Some(info.width.clone()),
102
            thumb_color: match info.thumb {
102
                StyleBackgroundContent::Color(c) => Some(c),
                _ => None,
            },
102
            track_color: match info.track {
102
                StyleBackgroundContent::Color(c) => Some(c),
                _ => None,
            },
        }
102
    }
    // --- 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,
            run_destructor: true,
            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(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: 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,
            run_destructor: true,
            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(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: 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,
            run_destructor: true,
            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(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: 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,
            run_destructor: true,
            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(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: 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,
            run_destructor: true,
            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(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: 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,
            run_destructor: true,
            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(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: 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,
            run_destructor: true,
            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(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: Default::default(),
        }
    }
    // --- Linux Styles ---
    /// GNOME Adwaita light theme defaults (Cantarell font).
102
    pub fn gnome_adwaita_light() -> SystemStyle {
102
        SystemStyle {
102
            platform: Platform::Linux(DesktopEnvironment::Gnome),
102
            theme: Theme::Light,
102
            colors: SystemColors {
102
                text: OptionColorU::Some(ColorU::new_rgb(46, 52, 54)),
102
                background: OptionColorU::Some(ColorU::new_rgb(249, 249, 249)),
102
                accent: OptionColorU::Some(ColorU::new_rgb(53, 132, 228)),
102
                window_background: OptionColorU::Some(ColorU::new_rgb(237, 237, 237)),
102
                ..Default::default()
102
            },
102
            fonts: SystemFonts {
102
                ui_font: OptionString::Some("Cantarell".into()),
102
                ui_font_size: OptionF32::Some(11.0),
102
                monospace_font: OptionString::Some("Monospace".into()),
102
                ..Default::default()
102
            },
102
            metrics: SystemMetrics {
102
                corner_radius: OptionPixelValue::Some(PixelValue::px(4.0)),
102
                border_width: OptionPixelValue::Some(PixelValue::px(1.0)),
102
                button_padding_horizontal: OptionPixelValue::Some(PixelValue::px(12.0)),
102
                button_padding_vertical: OptionPixelValue::Some(PixelValue::px(8.0)),
102
                titlebar: TitlebarMetrics::linux_gnome(),
102
            },
102
            scrollbar: Some(Box::new(scrollbar_info_to_computed(&SCROLLBAR_CLASSIC_LIGHT))),
102
            app_specific_stylesheet: None,
102
            run_destructor: true,
102
            icon_style: IconStyleOptions::default(),
102
            language: AzString::from_const_str("en-US"),
102
            os_version: OsVersion::LINUX_6_0,
102
            prefers_reduced_motion: BoolCondition::False,
102
            prefers_high_contrast: BoolCondition::False,
102
            scroll_physics: Default::default(),
102
            linux: Default::default(),
102
            focus_visuals: Default::default(),
102
            accessibility: Default::default(),
102
            input: Default::default(),
102
            text_rendering: Default::default(),
102
            scrollbar_preferences: Default::default(),
102
            visual_hints: Default::default(),
102
            animation: Default::default(),
102
            audio: Default::default(),
102
        }
102
    }
    /// 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,
            run_destructor: true,
            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,
            scroll_physics: Default::default(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: 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,
            run_destructor: true,
            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,
            scroll_physics: Default::default(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: 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,
            run_destructor: true,
            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,
            scroll_physics: Default::default(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: 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,
            run_destructor: true,
            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(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: 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,
            run_destructor: true,
            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(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: 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,
            run_destructor: true,
            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(),
            linux: Default::default(),
            focus_visuals: Default::default(),
            accessibility: Default::default(),
            input: Default::default(),
            text_rendering: Default::default(),
            scrollbar_preferences: Default::default(),
            visual_hints: Default::default(),
            animation: Default::default(),
            audio: Default::default(),
        }
    }
}