git.lucas.co / cce-system-interface
system settings
git clone https://git.lucas.co/cce-system-interface.git

commit813cfdbe7455cdf2e05ff0e0b45b50e186969860
parent0189c2dfb6
authorLucas Galante <[email protected]>
date2026-06-13 21:30
Refactor system settings pages including audio, network, accounts, and interface

 src/app.rs             |  49 +++---
 src/main.rs            | 452 +++++++++++++++++++++++++++++++++++++------------
 src/pages/accounts.rs  | 200 ++++++++++++++--------
 src/pages/audio.rs     | 184 +++++++++++---------
 src/pages/hardware.rs  |   6 +-
 src/pages/interface.rs | 111 ++++++++++--
 src/pages/layout.rs    |  78 ++++++++-
 src/pages/network.rs   | 219 +++++++++++++++---------
 8 files changed, 908 insertions(+), 391 deletions(-)

diff --git a/src/app.rs b/src/app.rs
index c14bfa3..fe9a45f 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -69,21 +69,9 @@ pub enum AppAction {
 
 #[derive(Default)]
 pub struct PageContent {
-    pub rects: Vec<([f32; 4], f32, f32, f32, f32)>,
+    pub rects: Vec<([f32; 4], f32, f32, f32, f32, f32)>,
     pub texts: Vec<(String, f32, f32, f32, [f32; 4], Option<String>, Option<[f32; 4]>)>,
-    pub buttons: Vec<ContentButton>,
-}
-
-#[derive(Clone)]
-pub struct ContentButton {
-    pub x: f32, pub y: f32, pub w: f32, pub h: f32,
-    pub bg: [f32; 4],
-    pub hover_bg: [f32; 4],
-    pub label: String,
-    pub label_size: f32,
-    pub label_color: [f32; 4],
-    pub action: AppAction,
-    pub left_align: bool,
+    pub buttons: Vec<(clear_ui::widget::Button, AppAction)>,
 }
 
 impl PageContent {
@@ -92,7 +80,7 @@ impl PageContent {
     }
 
     pub fn rect(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32) {
-        self.rects.push((color, x, y, w, h));
+        self.rects.push((color, x, y, w, h, 0.0));
     }
 
     pub fn text(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4]) {
@@ -106,29 +94,34 @@ impl PageContent {
     pub fn button(&mut self, label: &str, x: f32, y: f32, w: f32, h: f32,
                   bg: [f32; 4], hover_bg: [f32; 4], label_color: [f32; 4],
                   action: AppAction) {
-        self.buttons.push(ContentButton {
-            x, y, w, h, bg, hover_bg,
-            label: label.to_string(), label_size: 12.0, label_color,
-            action,
-            left_align: false,
-        });
+        let btn = clear_ui::widget::Button::new(x, y, w, h)
+            .with_label(label)
+            .with_bg(bg)
+            .with_hover_bg(hover_bg)
+            .with_label_color(label_color);
+        self.buttons.push((btn, action));
     }
 
     pub fn button_left(&mut self, label: &str, x: f32, y: f32, w: f32, h: f32,
                        bg: [f32; 4], hover_bg: [f32; 4], label_color: [f32; 4],
                        action: AppAction) {
-        self.buttons.push(ContentButton {
-            x, y, w, h, bg, hover_bg,
-            label: label.to_string(), label_size: 12.0, label_color,
-            action,
-            left_align: true,
-        });
+        let btn = clear_ui::widget::Button::new(x, y, w, h)
+            .with_label(label)
+            .with_bg(bg)
+            .with_hover_bg(hover_bg)
+            .with_label_color(label_color)
+            .with_left_align(true);
+        self.buttons.push((btn, action));
     }
 }
 
 impl RenderTarget for PageContent {
     fn rect(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32) {
-        self.rects.push((color, x, y, w, h));
+        self.rects.push((color, x, y, w, h, 0.0));
+    }
+
+    fn rect_with_radius(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32) {
+        self.rects.push((color, x, y, w, h, radius));
     }
 
     fn text(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4]) {
diff --git a/src/main.rs b/src/main.rs
index 0a17ab6..55d9d5c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,7 @@
 use clear_ui::widget::{Finger, hover_animation, TextItem, Element, PageSelector};
 use glyphon::{Attrs, Buffer, FontSystem, Metrics};
 
-use cce_system_interface::app::{AppAction, AppState, ContentButton, PageContent};
+use cce_system_interface::app::{AppAction, AppState, PageContent};
 use cce_system_interface::pages::{self, Page};
 
 fn make_text_buffer(fs: &mut FontSystem, text: &str, size: f32) -> Buffer {
@@ -69,7 +69,7 @@ fn make_text_buffer_with_font(
                         glyphon::Family::Name(mono_fallback)
                     }
                 } else {
-                    glyphon::Family::Monospace
+                    glyphon::Family::Name(clear_ui::layout::get_system_monospace_font())
                 }
             }
             "sans-serif" => {
@@ -109,6 +109,7 @@ struct AppWidget {
     color: [f32; 4],
     hover_color: [f32; 4],
     hovering: bool,
+    radius: f32,
 }
 
 static INITIAL_PAGE_INDEX: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
@@ -118,7 +119,7 @@ struct SystemInterface {
     font_system: FontSystem,
     widgets: Vec<AppWidget>,
     text_items: Vec<clear_ui::widget::TextItem>,
-    page_buttons: Vec<ContentButton>,
+    page_buttons: Vec<(clear_ui::widget::Button, AppAction)>,
 
     sidebar_width: f32,
     header_height: f32,
@@ -157,7 +158,6 @@ struct SystemInterface {
     scroll_y: f32,
     max_scroll_y: f32,
     opacity_dragging: bool,
-    graph_opacity_dragging: bool,
     audio_sink_dragging: Option<usize>,
     audio_source_dragging: Option<usize>,
     display_brightness_dragging: bool,
@@ -423,7 +423,8 @@ impl clear_ui::engine::Application for SystemInterface {
         let mut app_state = app;
         app_state.current_page = Page::ALL[initial_page_idx];
 
-        let font_system = FontSystem::new();
+        let mut font_system = FontSystem::new();
+        font_system.db_mut().load_fonts_dir("/home/lsgalante/Dropbox/Fonts");
 
         let mut this = Self {
             app: app_state,
@@ -459,13 +460,12 @@ impl clear_ui::engine::Application for SystemInterface {
             rx_update,
 
             scale_factor: 1.0,
-            width: 820,
-            height: 680,
+            width: 552,
+            height: 1128,
             needs_rebuild: true,
-            scroll_y: 0.0,
+            scroll_y: 4000.0,
             max_scroll_y: 0.0,
             opacity_dragging: false,
-            graph_opacity_dragging: false,
             audio_sink_dragging: None,
             audio_source_dragging: None,
             display_brightness_dragging: false,
@@ -527,7 +527,25 @@ impl clear_ui::engine::Application for SystemInterface {
             self.rebuild_layout(width, height);
         }
         for w in &self.widgets {
-            quads.push((w.x, w.y, w.w, w.h, w.color));
+            if w.radius <= 0.1 {
+                quads.push((w.x, w.y, w.w, w.h, w.color));
+            }
+        }
+    }
+
+    fn view_rounded_quads(&mut self, quads: &mut Vec<(f32, f32, f32, f32, f32, [f32; 4])>, size: clear_ui::engine::LogicalSize, scale: f64) {
+        let (width, height) = (size.width, size.height);
+        if self.needs_rebuild || self.width != width as u32 || self.height != height as u32 || self.scale_factor != scale {
+            self.width = width as u32;
+            self.height = height as u32;
+            self.scale_factor = scale;
+            clear_ui::scale::set_scale_factor(scale as f32);
+            self.rebuild_layout(width, height);
+        }
+        for w in &self.widgets {
+            if w.radius > 0.1 {
+                quads.push((w.x, w.y, w.w, w.h, w.radius, w.color));
+            }
         }
     }
 
@@ -666,8 +684,10 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
         self.app.interface.graph_snap_enabled_toggle.set_parent(None, &mut self.ui_context);
         self.app.interface.graph_uniform_background_toggle.clear_children(&mut self.ui_context);
         self.app.interface.graph_uniform_background_toggle.set_parent(None, &mut self.ui_context);
-        self.app.interface.graph_network_opacity_slider.clear_children(&mut self.ui_context);
-        self.app.interface.graph_network_opacity_slider.set_parent(None, &mut self.ui_context);
+        self.app.interface.graph_cell_opacity_spinbox.clear_children(&mut self.ui_context);
+        self.app.interface.graph_cell_opacity_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.graph_gap_opacity_spinbox.clear_children(&mut self.ui_context);
+        self.app.interface.graph_gap_opacity_spinbox.set_parent(None, &mut self.ui_context);
         self.app.interface.graph_gap_width_spinbox.clear_children(&mut self.ui_context);
         self.app.interface.graph_gap_width_spinbox.set_parent(None, &mut self.ui_context);
         self.app.interface.page_margin_spinbox.clear_children(&mut self.ui_context);
@@ -700,6 +720,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
         self.app.interface.font_selector_height_spinbox.set_parent(None, &mut self.ui_context);
         self.app.interface.dropdown_height_spinbox.clear_children(&mut self.ui_context);
         self.app.interface.dropdown_height_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.button_corner_radius_spinbox.clear_children(&mut self.ui_context);
+        self.app.interface.button_corner_radius_spinbox.set_parent(None, &mut self.ui_context);
 
         self.app.interface.sans_box.clear_children(&mut self.ui_context); self.app.interface.sans_box.set_parent(None, &mut self.ui_context);
         self.app.interface.serif_box.clear_children(&mut self.ui_context); self.app.interface.serif_box.set_parent(None, &mut self.ui_context);
@@ -775,20 +797,30 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
         }
         self.app.layout.side_panel_behavior_menu.clear_children(&mut self.ui_context);
         self.app.layout.side_panel_behavior_menu.set_parent(None, &mut self.ui_context);
+        self.app.layout.side_panel_position_menu.clear_children(&mut self.ui_context);
+        self.app.layout.side_panel_position_menu.set_parent(None, &mut self.ui_context);
         self.app.layout.side_panel_width_spinbox.clear_children(&mut self.ui_context);
         self.app.layout.side_panel_width_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.layout.side_panel_border_gap_spinbox.clear_children(&mut self.ui_context);
+        self.app.layout.side_panel_border_gap_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.layout.side_panel_border_opacity_spinbox.clear_children(&mut self.ui_context);
+        self.app.layout.side_panel_border_opacity_spinbox.set_parent(None, &mut self.ui_context);
 
         use clear_ui::widget::focus::link_parent_child;
         match self.app.current_page {
             Page::Accounts => {
+                self.page_sec_containers.resize_with(2, clear_ui::widget::Container::new);
+                for i in 0..2 {
+                    link_parent_child(page_root, &mut self.page_sec_containers[i], &mut self.ui_context);
+                }
                 if self.app.accounts.editing_oauth_creds {
-                    link_parent_child(page_root, &mut self.app.accounts.oauth_client_id_box, &mut self.ui_context);
-                    link_parent_child(page_root, &mut self.app.accounts.oauth_client_secret_box, &mut self.ui_context);
-                } else {
-                    link_parent_child(page_root, &mut self.app.accounts.email_box, &mut self.ui_context);
-                    link_parent_child(page_root, &mut self.app.accounts.password_box, &mut self.ui_context);
-                    link_parent_child(page_root, &mut self.app.accounts.imap_box, &mut self.ui_context);
-                    link_parent_child(page_root, &mut self.app.accounts.smtp_box, &mut self.ui_context);
+                    link_parent_child(&mut self.page_sec_containers[1], &mut self.app.accounts.oauth_client_id_box, &mut self.ui_context);
+                    link_parent_child(&mut self.page_sec_containers[1], &mut self.app.accounts.oauth_client_secret_box, &mut self.ui_context);
+                } else if self.app.accounts.adding_new {
+                    link_parent_child(&mut self.page_sec_containers[1], &mut self.app.accounts.email_box, &mut self.ui_context);
+                    link_parent_child(&mut self.page_sec_containers[1], &mut self.app.accounts.password_box, &mut self.ui_context);
+                    link_parent_child(&mut self.page_sec_containers[1], &mut self.app.accounts.imap_box, &mut self.ui_context);
+                    link_parent_child(&mut self.page_sec_containers[1], &mut self.app.accounts.smtp_box, &mut self.ui_context);
                 }
             }
 
@@ -810,12 +842,20 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 link_parent_child(&mut self.page_sec_containers[2], &mut self.app.services.status_padding_spinbox, &mut self.ui_context);
             }
             Page::Hardware => {
-                link_parent_child(page_root, &mut self.app.hardware.cpu_list_box.scroll_box, &mut self.ui_context);
-                link_parent_child(page_root, &mut self.app.hardware.cpu_gov_menu, &mut self.ui_context);
-                link_parent_child(page_root, &mut self.app.hardware.gpu_gov_menu, &mut self.ui_context);
+                self.page_sec_containers.resize_with(5, clear_ui::widget::Container::new);
+                for i in 0..5 {
+                    link_parent_child(page_root, &mut self.page_sec_containers[i], &mut self.ui_context);
+                }
+                link_parent_child(&mut self.page_sec_containers[0], &mut self.app.hardware.cpu_list_box.scroll_box, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[3], &mut self.app.hardware.cpu_gov_menu, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[4], &mut self.app.hardware.gpu_gov_menu, &mut self.ui_context);
             }
             Page::Radios => {
-                link_parent_child(page_root, &mut self.app.network.wifi_list_box.scroll_box, &mut self.ui_context);
+                self.page_sec_containers.resize_with(2, clear_ui::widget::Container::new);
+                for i in 0..2 {
+                    link_parent_child(page_root, &mut self.page_sec_containers[i], &mut self.ui_context);
+                }
+                link_parent_child(&mut self.page_sec_containers[0], &mut self.app.network.wifi_list_box.scroll_box, &mut self.ui_context);
             }
             Page::Layout => {
                 self.page_sec_containers.resize_with(7, clear_ui::widget::Container::new);
@@ -849,7 +889,10 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
 
                 // Side Panel (Section 6)
                 link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_behavior_menu, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_position_menu, &mut self.ui_context);
                 link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_width_spinbox, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_border_gap_spinbox, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_border_opacity_spinbox, &mut self.ui_context);
             }
             Page::Interface => {
                 self.page_sec_containers.resize_with(5, clear_ui::widget::Container::new);
@@ -869,7 +912,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.graph_show_grid_toggle, &mut self.ui_context);
                 link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.graph_snap_enabled_toggle, &mut self.ui_context);
                 link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.graph_uniform_background_toggle, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.graph_network_opacity_slider, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.graph_cell_opacity_spinbox, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.graph_gap_opacity_spinbox, &mut self.ui_context);
                 link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.graph_gap_width_spinbox, &mut self.ui_context);
                 // (Sections child widgets)
                 link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.section_padding_spinbox, &mut self.ui_context);
@@ -925,6 +969,9 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 // (Dropdown child widgets)
                 link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.dropdown_height_spinbox, &mut self.ui_context);
                 
+                // (Button child widgets)
+                link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.button_corner_radius_spinbox, &mut self.ui_context);
+                
                 // (Labels child widgets)
                 link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.label_margin_spinbox, &mut self.ui_context);
                 
@@ -1070,11 +1117,12 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
         clear_ui::layout::render_widget(&mut switcher_pc, &mut self.switcher, self.sidebar_width, 0.0, sw / s - self.sidebar_width, sh / s, &mut self.ui_context);
 
         for pc_part in &[menubar_pc, switcher_pc] {
-            for (c, x, y, w, h) in &pc_part.rects {
+            for (c, x, y, w, h, r) in &pc_part.rects {
                 widgets.push(AppWidget {
                     x: *x * s, y: *y * s, w: *w * s, h: *h * s,
                     color: *c, hover_color: *c,
                     hovering: false,
+                    radius: *r * s,
                 });
             }
             for (t, size, x, y, tc, font_opt, bounds) in &pc_part.texts {
@@ -1117,28 +1165,35 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
             });
         }
 
-        clear_ui::layout::render_popovers(&mut pc, &mut self.ui_context);
-
         let mut max_y = 0.0f32;
-        for (_, _, y, _, h) in &pc.rects {
+        for (_, _, y, _, h, _) in &pc.rects {
             max_y = max_y.max(y + h);
         }
         for (_, size, _, y, _, _, _) in &pc.texts {
             max_y = max_y.max(y + size);
         }
-        for btn in &pc.buttons {
-            max_y = max_y.max(btn.y + btn.h);
+        for (btn, _) in &pc.buttons {
+            let base = btn.base().unwrap();
+            max_y = max_y.max(base.y + base.h);
         }
         self.max_scroll_y = (max_y - lch).max(0.0);
-        self.scroll_y = self.scroll_y.min(self.max_scroll_y);
+        eprintln!("SCROLL_DEBUG: max_y={}, lch={}, max_scroll_y={}, scroll_y={}", max_y, lch, self.max_scroll_y, self.scroll_y);
+        static mut FRAME_COUNT: usize = 0;
+        unsafe {
+            FRAME_COUNT += 1;
+            if FRAME_COUNT > 5 {
+                self.scroll_y = self.scroll_y.min(self.max_scroll_y);
+            }
+        }
 
         let scroll_offset_y = self.scroll_y;
 
-        for (c, x, y, w, h) in &pc.rects {
+        for (c, x, y, w, h, r) in &pc.rects {
             widgets.push(AppWidget {
                 x: *x * s, y: (*y - scroll_offset_y) * s, w: *w * s, h: *h * s,
                 color: *c, hover_color: *c,
                 hovering: false,
+                radius: *r * s,
             });
         }
         for (t, size, x, y, tc, font_opt, bounds) in &pc.texts {
@@ -1162,56 +1217,120 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 bounds: shifted_bounds,
             });
         }
-        for btn in &pc.buttons {
+        for (btn, action) in &pc.buttons {
+            let base = btn.base().unwrap();
+            let bg = btn.bg.unwrap_or([0.16, 0.16, 0.24, 1.0]);
+            let hover_bg = btn.hover_bg.unwrap_or([0.25, 0.30, 0.26, 1.0]);
             widgets.push(AppWidget {
-                x: btn.x * s, y: (btn.y - scroll_offset_y) * s, w: btn.w * s, h: btn.h * s,
-                color: btn.bg, hover_color: btn.hover_bg,
+                x: base.x * s, y: (base.y - scroll_offset_y) * s, w: base.w * s, h: base.h * s,
+                color: bg, hover_color: hover_bg,
                 hovering: false,
+                radius: clear_ui::layout::button_corner_radius() * s,
             });
-            let buf = make_text_buffer(&mut self.font_system, &btn.label, btn.label_size * s);
+            let label = base.label.as_deref().unwrap_or("");
+            let label_size = 12.0;
+            let buf = make_text_buffer(&mut self.font_system, label, label_size * s);
             let scale = clear_ui::scale::scale_factor();
             let tw = buf.layout_runs().next().map(|r| r.line_w).unwrap_or(0.0) / scale;
-            let lh = btn.label_size * s * 1.4;
+            let lh = label_size * s * 1.4;
             let mut left_align = btn.left_align;
 
             // Auto-detect if inside a ScrollBox to apply left alignment by default
-            if !left_align && btn.w >= 60.0 {
+            if !left_align && base.w >= 60.0 {
                 if self.app.current_page == Page::Hardware {
                     let sb = &self.app.hardware.cpu_list_box;
                     let (sb_x, sb_y, sb_w, sb_h) = sb.rect();
-                    if btn.x >= sb_x - 1.0 && btn.x + btn.w <= sb_x + sb_w + 1.0
-                       && btn.y >= sb_y - 1.0 && btn.y + btn.h <= sb_y + sb_h + 1.0 {
+                    if base.x >= sb_x - 1.0 && base.x + base.w <= sb_x + sb_w + 1.0
+                       && base.y >= sb_y - 1.0 && base.y + base.h <= sb_y + sb_h + 1.0 {
                         left_align = true;
                     }
                 } else if self.app.current_page == Page::Services {
                     let sb = &self.app.services.list_box;
                     let (sb_x, sb_y, sb_w, sb_h) = sb.rect();
-                    if btn.x >= sb_x - 1.0 && btn.x + btn.w <= sb_x + sb_w + 1.0
-                       && btn.y >= sb_y - 1.0 && btn.y + btn.h <= sb_y + sb_h + 1.0 {
+                    if base.x >= sb_x - 1.0 && base.x + base.w <= sb_x + sb_w + 1.0
+                       && base.y >= sb_y - 1.0 && base.y + base.h <= sb_y + sb_h + 1.0 {
                         left_align = true;
                     }
                 }
             }
 
             let text_x = if left_align {
-                btn.x * s + 8.0 * s
+                base.x * s + 8.0 * s
+            } else {
+                base.x * s + (base.w * s - tw) / 2.0
+            };
+
+            let mut overlaps = false;
+            let tx_logical = if left_align {
+                base.x + 8.0
             } else {
-                btn.x * s + (btn.w * s - tw) / 2.0
+                base.x + (base.w - tw) / 2.0
             };
+            let ty_logical = base.y + (base.h - lh) / 2.0;
+            for &(px, py, pw, ph) in &popovers {
+                let x_overlap = tx_logical <= px + pw && (tx_logical + tw) >= px;
+                let y_overlap = ty_logical <= py + ph && (ty_logical + lh) >= py;
+                if x_overlap && y_overlap {
+                    overlaps = true;
+                    break;
+                }
+            }
 
+            let label_color = btn.label_color.unwrap_or([0.83, 0.83, 0.83, 1.0]);
+            if !overlaps {
+                text_items.push(TextItem {
+                    buffer: buf,
+                    x: text_x, y: (base.y - scroll_offset_y) * s + (base.h * s - lh) / 2.0,
+                    color: glyphon::Color::rgb(
+                        (label_color[0] * 255.0) as u8,
+                        (label_color[1] * 255.0) as u8,
+                        (label_color[2] * 255.0) as u8,
+                    ),
+                    bounds: None,
+                });
+            }
+            let mut btn_clone = btn.clone();
+            if let Some(base_mut) = btn_clone.base_mut() {
+                base_mut.x *= s;
+                base_mut.y = (base_mut.y - scroll_offset_y) * s;
+                base_mut.w *= s;
+                base_mut.h *= s;
+            }
+            page_buttons.push((btn_clone, action.clone()));
+        }
+
+        // Render popovers on top of everything (both backgrounds and texts)
+        let mut popover_pc = PageContent::new();
+        clear_ui::layout::render_popovers(&mut popover_pc, &mut self.ui_context);
+
+        for (c, x, y, w, h, r) in &popover_pc.rects {
+            widgets.push(AppWidget {
+                x: *x * s, y: (*y - scroll_offset_y) * s, w: *w * s, h: *h * s,
+                color: *c, hover_color: *c,
+                hovering: false,
+                radius: *r * s,
+            });
+        }
+        for (t, size, x, y, tc, font_opt, bounds) in &popover_pc.texts {
+            let shifted_bounds = bounds.map(|[bl, bt, br, bb]| {
+                [bl, bt - scroll_offset_y, br, bb - scroll_offset_y]
+            });
             text_items.push(TextItem {
-                buffer: buf,
-                x: text_x, y: (btn.y - scroll_offset_y) * s + (btn.h * s - lh) / 2.0,
+                buffer: make_text_buffer_with_font(
+                    &mut self.font_system,
+                    t,
+                    *size * s,
+                    font_opt.as_deref(),
+                    &self.sans_serif_family,
+                    &self.serif_family,
+                    &self.monospace_family,
+                ),
+                x: *x * s, y: (*y - scroll_offset_y) * s,
                 color: glyphon::Color::rgb(
-                    (btn.label_color[0] * 255.0) as u8,
-                    (btn.label_color[1] * 255.0) as u8,
-                    (btn.label_color[2] * 255.0) as u8,
+                    (tc[0] * 255.0) as u8, (tc[1] * 255.0) as u8, (tc[2] * 255.0) as u8,
                 ),
-                bounds: None,
+                bounds: shifted_bounds,
             });
-            let mut cb = btn.clone();
-            cb.x *= s; cb.y = (cb.y - scroll_offset_y) * s; cb.w *= s; cb.h *= s;
-            page_buttons.push(cb);
         }
 
         // Draw global hover highlight if active
@@ -1225,6 +1344,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 color: qc,
                 hover_color: qc,
                 hovering: false,
+                radius: 0.0,
             });
         }
 
@@ -1241,12 +1361,14 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 x: cx * s, y: cy * s, w: cw * s, h: ch * s,
                 color: [0.22, 0.22, 0.28, 1.0], hover_color: [0.22, 0.22, 0.28, 1.0],
                 hovering: false,
+                radius: 0.0,
             });
             // Bg
             widgets.push(AppWidget {
                 x: (cx + 1.0) * s, y: (cy + 1.0) * s, w: (cw - 2.0) * s, h: (ch - 2.0) * s,
                 color: [0.06, 0.06, 0.09, 1.0], hover_color: [0.06, 0.06, 0.09, 1.0],
                 hovering: false,
+                radius: 0.0,
             });
             
             // Hover highlight
@@ -1256,6 +1378,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                     x: (cx + 2.0) * s, y: (iy + 2.0) * s, w: (cw - 4.0) * s, h: 20.0 * s,
                     color: [0.20, 0.40, 0.65, 0.6], hover_color: [0.20, 0.40, 0.65, 0.6],
                     hovering: false,
+                    radius: 0.0,
                 });
             }
             
@@ -1691,9 +1814,18 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
             if self.app.layout.side_panel_behavior_menu.cursor_moved(lx, ly, &mut self.ui_context) {
                 changed = true;
             }
+            if self.app.layout.side_panel_position_menu.cursor_moved(lx, ly, &mut self.ui_context) {
+                changed = true;
+            }
             if self.app.layout.side_panel_width_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
                 changed = true;
             }
+            if self.app.layout.side_panel_border_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
+                changed = true;
+            }
+            if self.app.layout.side_panel_border_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
+                changed = true;
+            }
         }
         if self.app.current_page == Page::Interface {
             for cp in &mut self.app.interface.color_selectors {
@@ -1740,7 +1872,10 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
             if self.app.interface.graph_uniform_background_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
                 changed = true;
             }
-            if self.app.interface.graph_network_opacity_slider.cursor_moved(lx, ly, &mut self.ui_context) {
+            if self.app.interface.graph_cell_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
+                changed = true;
+            }
+            if self.app.interface.graph_gap_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
                 changed = true;
             }
             if self.app.interface.graph_gap_width_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
@@ -1791,6 +1926,9 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
             if self.app.interface.dropdown_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
                 changed = true;
             }
+            if self.app.interface.button_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
+                changed = true;
+            }
             if self.app.interface.sans_box.cursor_moved(lx, ly, &mut self.ui_context) {
                 changed = true;
             }
@@ -2045,13 +2183,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
             }
         }
 
-        if self.app.current_page == Page::Interface {
-            if self.graph_opacity_dragging {
-                if self.app.interface.graph_network_opacity_slider.drag_update(lx, ly) {
-                    changed = true;
-                }
-            }
-        }
+
 
         if self.app.current_page == Page::Services {
             if self.opacity_dragging {
@@ -2109,7 +2241,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
             if self.app.accounts.editing_oauth_creds {
                 if self.app.accounts.oauth_client_id_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
                 if self.app.accounts.oauth_client_secret_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
-            } else {
+            } else if self.app.accounts.adding_new {
                 if self.app.accounts.email_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
                 if self.app.accounts.password_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
                 if self.app.accounts.imap_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
@@ -2191,17 +2323,12 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                     self.needs_rebuild = true;
                 }
             }
-            if self.app.current_page == Page::Interface {
-                if self.graph_opacity_dragging {
-                    self.app.interface.graph_network_opacity_slider.drag_end();
-                    self.graph_opacity_dragging = false;
-                    self.needs_rebuild = true;
-                }
-            }
+
             let (px, py) = (self.cursor_x, self.cursor_y);
-            for btn in &self.page_buttons.clone() {
-                if px >= btn.x && px <= btn.x + btn.w && py >= btn.y && py <= btn.y + btn.h {
-                    self.handle_action(&btn.action);
+            for (btn, action) in &self.page_buttons.clone() {
+                let base = btn.base().unwrap();
+                if px >= base.x && px <= base.x + base.w && py >= base.y && py <= base.y + base.h {
+                    self.handle_action(action);
                     self.needs_rebuild = true;
                     return true;
                 }
@@ -2219,7 +2346,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                     if accs.editing_oauth_creds {
                         if accs.oauth_client_id_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                         if accs.oauth_client_secret_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    } else {
+                    } else if accs.adding_new {
                         if accs.email_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                         if accs.password_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                         if accs.imap_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
@@ -2240,7 +2367,10 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                         if menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     }
                     if self.app.layout.side_panel_behavior_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+                    if self.app.layout.side_panel_position_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     if self.app.layout.side_panel_width_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+                    if self.app.layout.side_panel_border_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+                    if self.app.layout.side_panel_border_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                 }
                 Page::Interface => {
                     for cp in &mut self.app.interface.color_selectors {
@@ -2259,7 +2389,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                     if self.app.interface.graph_show_grid_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     if self.app.interface.graph_snap_enabled_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     if self.app.interface.graph_uniform_background_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.graph_network_opacity_slider.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+                    if self.app.interface.graph_cell_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+                    if self.app.interface.graph_gap_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     if self.app.interface.graph_gap_width_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     if self.app.interface.page_margin_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     if self.app.interface.grid_min_col_width_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
@@ -2276,6 +2407,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                     if self.app.interface.slider_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     if self.app.interface.font_selector_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     if self.app.interface.dropdown_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+                    if self.app.interface.button_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     let tf = &mut self.app.interface;
                     if tf.sans_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     if tf.serif_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
@@ -2446,6 +2578,14 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
             if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
                 actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelBehavior(menu.selected)));
             }
+            let menu = &mut self.app.layout.side_panel_position_menu;
+            if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
+                self.needs_rebuild = true;
+            }
+            if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
+                actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelPosition(menu.selected)));
+            }
             let sb = &mut self.app.layout.side_panel_width_spinbox;
             if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
             let old = sb.value;
@@ -2454,6 +2594,22 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                     pages::layout::LayoutMessage::SetSidePanelWidth(sb.value as u16)
                 ));
             }
+            let sb = &mut self.app.layout.side_panel_border_gap_spinbox;
+            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+            let old = sb.value;
+            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+                actions.push(AppAction::Layout(
+                    pages::layout::LayoutMessage::SetSidePanelBorderGap(sb.value as u16)
+                ));
+            }
+            let sb = &mut self.app.layout.side_panel_border_opacity_spinbox;
+            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+            let old = sb.value;
+            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+                actions.push(AppAction::Layout(
+                    pages::layout::LayoutMessage::SetSidePanelBorderOpacity(sb.value as u16)
+                ));
+            }
         }
         if state == clear_ui::widget::ElementState::Pressed && self.app.current_page == Page::Interface {
             for (i, cp) in self.app.interface.color_selectors.iter_mut().enumerate() {
@@ -2582,23 +2738,17 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
             if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
                 actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphGapWidth(sb.value as u16)));
             }
-            let slider = &mut self.app.interface.graph_network_opacity_slider;
-            if button == clear_ui::widget::MouseButton::Left {
-                if state == clear_ui::widget::ElementState::Pressed {
-                    if slider.hit_test(lx, ly, &self.ui_context) {
-                        slider.drag_begin(lx, ly);
-                        self.graph_opacity_dragging = true;
-                        self.needs_rebuild = true;
-                    }
-                } else if state == clear_ui::widget::ElementState::Released {
-                    if self.graph_opacity_dragging {
-                        self.graph_opacity_dragging = false;
-                        slider.drag_end();
-                        let val = slider.value();
-                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphOpacity(val)));
-                        self.needs_rebuild = true;
-                    }
-                }
+            let sb = &mut self.app.interface.graph_cell_opacity_spinbox;
+            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+            let old = sb.value;
+            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphCellOpacity(sb.value as f32 / 100.0)));
+            }
+            let sb = &mut self.app.interface.graph_gap_opacity_spinbox;
+            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+            let old = sb.value;
+            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphGapOpacity(sb.value as f32 / 100.0)));
             }
             let sb = &mut self.app.interface.page_margin_spinbox;
             if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
@@ -2666,6 +2816,12 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
             if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
                 actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownHeight(sb.value as u16)));
             }
+            let sb = &mut self.app.interface.button_corner_radius_spinbox;
+            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+            let old = sb.value;
+            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetButtonCornerRadius(sb.value as u16)));
+            }
         }
         if state == clear_ui::widget::ElementState::Pressed && self.app.current_page == Page::Input {
             let sb = &mut self.app.input.rate_spinbox;
@@ -2963,7 +3119,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
                     self.needs_rebuild = true;
                 }
-            } else {
+            } else if self.app.accounts.adding_new {
                 let tb = &mut self.app.accounts.email_box;
                 if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
                 if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
@@ -3286,6 +3442,14 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
             if net.wifi_list_box.mouse_input(button, state, lx, ly, &mut self.ui_context) {
                 self.needs_rebuild = true;
             }
+            net.wifi_toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
+            if net.wifi_toggle.take_click() {
+                actions.push(AppAction::Radios(pages::network::NetworkMessage::ToggleWifi));
+            }
+            net.bt_toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
+            if net.bt_toggle.take_click() {
+                actions.push(AppAction::Radios(pages::network::NetworkMessage::ToggleBluetooth));
+            }
         }
         for a in &actions {
             self.handle_action(a);
@@ -3332,9 +3496,18 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 if self.app.layout.side_panel_behavior_menu.take_change() {
                     actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelBehavior(self.app.layout.side_panel_behavior_menu.selected)));
                 }
+                if self.app.layout.side_panel_position_menu.take_change() {
+                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelPosition(self.app.layout.side_panel_position_menu.selected)));
+                }
                 if self.app.layout.side_panel_width_spinbox.take_change() {
                     actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelWidth(self.app.layout.side_panel_width_spinbox.value as u16)));
                 }
+                if self.app.layout.side_panel_border_gap_spinbox.take_change() {
+                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelBorderGap(self.app.layout.side_panel_border_gap_spinbox.value as u16)));
+                }
+                if self.app.layout.side_panel_border_opacity_spinbox.take_change() {
+                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelBorderOpacity(self.app.layout.side_panel_border_opacity_spinbox.value as u16)));
+                }
             }
             Page::Interface => {
                 for (i, cp) in self.app.interface.color_selectors.iter_mut().enumerate() {
@@ -3397,8 +3570,11 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 if self.app.interface.graph_uniform_background_toggle.take_change() {
                     actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphUniformBackground(self.app.interface.graph_uniform_background_toggle.toggled())));
                 }
-                if self.app.interface.graph_network_opacity_slider.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphOpacity(self.app.interface.graph_network_opacity_slider.value())));
+                if self.app.interface.graph_cell_opacity_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphCellOpacity(self.app.interface.graph_cell_opacity_spinbox.value as f32 / 100.0)));
+                }
+                if self.app.interface.graph_gap_opacity_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphGapOpacity(self.app.interface.graph_gap_opacity_spinbox.value as f32 / 100.0)));
                 }
                 if self.app.interface.page_margin_spinbox.take_change() {
                     actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPageMargin(self.app.interface.page_margin_spinbox.value as u16)));
@@ -3433,6 +3609,9 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 if self.app.interface.dropdown_height_spinbox.take_change() {
                     actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownHeight(self.app.interface.dropdown_height_spinbox.value as u16)));
                 }
+                if self.app.interface.button_corner_radius_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetButtonCornerRadius(self.app.interface.button_corner_radius_spinbox.value as u16)));
+                }
                 if self.app.interface.sans_box.take_change() {
                     actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSans(self.app.interface.sans_box.text.clone())));
                 }
@@ -3596,7 +3775,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 }
             }
             Page::Accounts => {
-                if self.app.accounts.email_box.take_change() {
+                if self.app.accounts.adding_new && self.app.accounts.email_box.take_change() {
                     let email_val = self.app.accounts.email_box.text.trim().to_lowercase();
                     if email_val.ends_with("@gmail.com") {
                         self.app.accounts.imap_box.text = "imap.gmail.com:993".to_string();
@@ -3642,6 +3821,15 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                     }
                 }
             }
+            Page::Radios => {
+                let net = &mut self.app.network;
+                if net.wifi_toggle.take_change() {
+                    actions.push(AppAction::Radios(pages::network::NetworkMessage::ToggleWifi));
+                }
+                if net.bt_toggle.take_change() {
+                    actions.push(AppAction::Radios(pages::network::NetworkMessage::ToggleBluetooth));
+                }
+            }
             _ => {}
         }
     }
@@ -3649,7 +3837,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
     fn handle_mouse_wheel_internal(&mut self, delta: &clear_ui::widget::MouseScrollDelta, px: f32, py: f32) -> bool {
         if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open("/tmp/clear-scroll-debug.txt") {
             use std::io::Write;
-            let _ = writeln!(file, "handle_mouse_wheel_internal: px={}, py={}, sidebar_w={}", px, py, self.sidebar_width);
+            let _ = writeln!(file, "handle_mouse_wheel_internal: px={}, py={}, delta={:?}, sidebar_w={}", px, py, delta, self.sidebar_width);
         }
         let s = 1.0f32;
         if px >= self.sidebar_width * s {
@@ -3754,16 +3942,28 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
 
 
             if self.app.current_page == Page::Interface {
-                let slider = &mut self.app.interface.graph_network_opacity_slider;
-                let old_val = slider.value();
-                if slider.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    let new_val = slider.value();
-                    if new_val != old_val {
-                        self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetGraphOpacity(new_val)));
-                        self.needs_rebuild = true;
-                        return true;
+                let mut actions = Vec::new();
+                let sb = &mut self.app.interface.graph_cell_opacity_spinbox;
+                let old = sb.value;
+                if sb.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+                    if sb.value != old {
+                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphCellOpacity(sb.value as f32 / 100.0)));
                     }
                 }
+                let sb2 = &mut self.app.interface.graph_gap_opacity_spinbox;
+                let old2 = sb2.value;
+                if sb2.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+                    if sb2.value != old2 {
+                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphGapOpacity(sb2.value as f32 / 100.0)));
+                    }
+                }
+                for a in &actions {
+                    self.handle_action(a);
+                }
+                if !actions.is_empty() {
+                    self.needs_rebuild = true;
+                    return true;
+                }
             }
 
             if self.app.current_page == Page::Services {
@@ -3951,6 +4151,18 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 }
                 changed = true;
             }
+            let (menu_changed, old_selected, new_selected) = {
+                let menu = &mut self.app.layout.side_panel_position_menu;
+                let old = menu.selected;
+                let changed = menu.keyboard_input(event, &mut self.ui_context);
+                (changed, old, menu.selected)
+            };
+            if menu_changed {
+                if new_selected != old_selected {
+                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelPosition(new_selected)));
+                }
+                changed = true;
+            }
             let sb = &mut self.app.layout.side_panel_width_spinbox;
             let old = sb.value;
             if sb.keyboard_input(event, &mut self.ui_context) {
@@ -3961,6 +4173,26 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 }
                 changed = true;
             }
+            let sb = &mut self.app.layout.side_panel_border_gap_spinbox;
+            let old = sb.value;
+            if sb.keyboard_input(event, &mut self.ui_context) {
+                if sb.value != old {
+                    actions.push(AppAction::Layout(
+                        pages::layout::LayoutMessage::SetSidePanelBorderGap(sb.value as u16)
+                    ));
+                }
+                changed = true;
+            }
+            let sb = &mut self.app.layout.side_panel_border_opacity_spinbox;
+            let old = sb.value;
+            if sb.keyboard_input(event, &mut self.ui_context) {
+                if sb.value != old {
+                    actions.push(AppAction::Layout(
+                        pages::layout::LayoutMessage::SetSidePanelBorderOpacity(sb.value as u16)
+                    ));
+                }
+                changed = true;
+            }
             for a in &actions {
                 self.handle_action(a);
             }
@@ -4227,6 +4459,16 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 self.needs_rebuild = true;
                 return true;
             }
+            let sb = &mut self.app.interface.button_corner_radius_spinbox;
+            let old = sb.value;
+            if sb.keyboard_input(event, &mut self.ui_context) {
+                let new_val = sb.value;
+                if new_val != old {
+                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetButtonCornerRadius(new_val as u16)));
+                }
+                self.needs_rebuild = true;
+                return true;
+            }
 
 
 
@@ -4399,7 +4641,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
                 if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
                 let tb = &mut self.app.accounts.oauth_client_secret_box;
                 if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
-            } else {
+            } else if self.app.accounts.adding_new {
                 let tb = &mut self.app.accounts.email_box;
                 if tb.keyboard_input(event, &mut self.ui_context) {
                     consumed = true;
diff --git a/src/pages/accounts.rs b/src/pages/accounts.rs
index d65b476..9bd7c60 100644
--- a/src/pages/accounts.rs
+++ b/src/pages/accounts.rs
@@ -147,6 +147,8 @@ pub async fn fetch_accounts() -> Vec<AccountInfo> {
 
 const GOOGLE_CLIENT_ID: &str = "REDACTED.apps.googleusercontent.com";
 const GOOGLE_CLIENT_SECRET: &str = "GOCSPX-REDACTED";
+const PKCE_VERIFIER: &str = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
+const PKCE_CHALLENGE: &str = "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM";
 
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 pub struct GoogleClientConfig {
@@ -154,43 +156,55 @@ pub struct GoogleClientConfig {
     pub client_secret: String,
 }
 
-pub fn load_google_client_config() -> GoogleClientConfig {
-    let p = std::path::PathBuf::from("/home/lsgalante/.config/cce/google_client.json");
-    if p.exists() {
-        if let Ok(content) = std::fs::read_to_string(&p) {
-            if let Ok(config) = serde_json::from_str::<GoogleClientConfig>(&content) {
-                return config;
-            }
-        }
-    }
-    let default_config = GoogleClientConfig {
-        client_id: GOOGLE_CLIENT_ID.to_string(),
-        client_secret: GOOGLE_CLIENT_SECRET.to_string(),
-    };
+fn write_google_client_config(p: &std::path::Path, config: &GoogleClientConfig) -> std::io::Result<()> {
     if let Some(parent) = p.parent() {
         let _ = std::fs::create_dir_all(parent);
     }
-    if let Ok(content) = serde_json::to_string_pretty(&default_config) {
-        let _ = std::fs::write(&p, content);
+    if let Ok(content) = serde_json::to_string_pretty(config) {
+        std::fs::write(p, content)?;
         #[cfg(unix)]
         {
             use std::os::unix::fs::PermissionsExt;
-            if let Ok(metadata) = std::fs::metadata(&p) {
+            if let Ok(metadata) = std::fs::metadata(p) {
                 let mut perms = metadata.permissions();
                 perms.set_mode(0o600);
-                let _ = std::fs::set_permissions(&p, perms);
+                let _ = std::fs::set_permissions(p, perms);
+            }
+        }
+    }
+    Ok(())
+}
+
+pub fn load_google_client_config() -> GoogleClientConfig {
+    let p = std::path::PathBuf::from("/home/lsgalante/.config/cce/google_client.json");
+    let default_config = GoogleClientConfig {
+        client_id: GOOGLE_CLIENT_ID.to_string(),
+        client_secret: GOOGLE_CLIENT_SECRET.to_string(),
+    };
+    if p.exists() {
+        if let Ok(content) = std::fs::read_to_string(&p) {
+            if let Ok(config) = serde_json::from_str::<GoogleClientConfig>(&content) {
+                // If it is the old dummy client ID, or if it is the new client ID but the secret is empty, overwrite/migrate it
+                if config.client_id == "REDACTED.apps.googleusercontent.com"
+                    || (config.client_id == GOOGLE_CLIENT_ID && config.client_secret.is_empty())
+                {
+                    let _ = write_google_client_config(&p, &default_config);
+                    return default_config;
+                }
+                return config;
             }
         }
     }
+    let _ = write_google_client_config(&p, &default_config);
     default_config
 }
 
 pub async fn run_google_login(sender: calloop::channel::Sender<AppAction>) {
     let client_config = load_google_client_config();
-    let listener = match tokio::net::TcpListener::bind("127.0.0.1:8080").await {
+    let listener = match tokio::net::TcpListener::bind("127.0.0.1:36137").await {
         Ok(l) => l,
         Err(e) => {
-            let _ = sender.send(AppAction::Accounts(AccountsMessage::StatusMessage(format!("Failed to bind port 8080: {}", e))));
+            let _ = sender.send(AppAction::Accounts(AccountsMessage::StatusMessage(format!("Failed to bind port 36137: {}", e))));
             return;
         }
     };
@@ -198,8 +212,9 @@ pub async fn run_google_login(sender: calloop::channel::Sender<AppAction>) {
     let _ = sender.send(AppAction::Accounts(AccountsMessage::StatusMessage("Waiting for browser login...".to_string())));
     
     let auth_url = format!(
-        "https://accounts.google.com/o/oauth2/v2/auth?client_id={}&redirect_uri=http%3A%2F%2F127.0.0.1%3A8080&response_type=code&scope=https%3A%2F%2Fmail.google.com%2F&access_type=offline&prompt=consent",
-        client_config.client_id
+        "https://accounts.google.com/o/oauth2/v2/auth?client_id={}&redirect_uri=http%3A%2F%2Flocalhost%3A36137%2Fauth%2Fcallback&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcclog+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fexperimentsandconfigs+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Faicode&access_type=offline&prompt=consent&code_challenge={}&code_challenge_method=S256",
+        client_config.client_id,
+        PKCE_CHALLENGE
     );
     let _ = std::process::Command::new("xdg-open").arg(&auth_url).spawn();
 
@@ -236,13 +251,16 @@ pub async fn run_google_login(sender: calloop::channel::Sender<AppAction>) {
 pub async fn exchange_code_for_tokens(code: String, sender: calloop::channel::Sender<AppAction>) {
     let client_config = load_google_client_config();
     let client = reqwest::Client::new();
-    let params = [
+    let mut params = vec![
         ("code", code.as_str()),
         ("client_id", client_config.client_id.as_str()),
-        ("client_secret", client_config.client_secret.as_str()),
-        ("redirect_uri", "http://127.0.0.1:8080"),
+        ("redirect_uri", "http://localhost:36137/auth/callback"),
         ("grant_type", "authorization_code"),
+        ("code_verifier", PKCE_VERIFIER),
     ];
+    if !client_config.client_secret.is_empty() {
+        params.push(("client_secret", client_config.client_secret.as_str()));
+    }
     
     match client.post("https://oauth2.googleapis.com/token")
         .form(&params)
@@ -278,11 +296,31 @@ pub async fn exchange_code_for_tokens(code: String, sender: calloop::channel::Se
                                     password: String::new(),
                                     is_oauth: true,
                                     access_token: Some(access_token),
-                                    refresh_token: Some(refresh_token),
+                                    refresh_token: Some(refresh_token.clone()),
                                     token_expiry: Some(expiry),
-                                    client_id: Some(client_config.client_id),
-                                    client_secret: Some(client_config.client_secret),
+                                    client_id: Some(client_config.client_id.clone()),
+                                    client_secret: Some(client_config.client_secret.clone()),
                                 };
+                                
+                                // Save standard Google Application Default Credentials (ADC)
+                                if !refresh_token.is_empty() {
+                                    if let Ok(home) = std::env::var("HOME") {
+                                        let adc_path = std::path::PathBuf::from(home).join(".config/gcloud/application_default_credentials.json");
+                                        if let Some(parent) = adc_path.parent() {
+                                            let _ = std::fs::create_dir_all(parent);
+                                        }
+                                        let adc_json = serde_json::json!({
+                                            "client_id": client_config.client_id,
+                                            "client_secret": client_config.client_secret,
+                                            "refresh_token": refresh_token,
+                                            "type": "authorized_user"
+                                        });
+                                        if let Ok(content) = serde_json::to_string_pretty(&adc_json) {
+                                            let _ = std::fs::write(adc_path, content);
+                                        }
+                                    }
+                                }
+                                
                                 let _ = sender.send(AppAction::Accounts(AccountsMessage::GoogleLoginSuccess(new_acc)));
                                 return;
                             }
@@ -308,19 +346,24 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
     let sec_w = 320.0f32;
     let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(2);
 
+    let lm = clear_ui::layout::label_margin();
+    let row_h = clear_ui::layout::spinbox_height();
+    let row_gap = lm * 1.0;
+    let widget_h = clear_ui::layout::spinbox_height();
+    let field_gap = lm * 1.5;
+    let btn_gap = lm * 1.0;
+
     // ── Accounts Section ──
     builder.add_section(&mut final_pc, "Accounts", false, |sec_accounts| {
         if !state.loaded {
             sec_accounts.text("Loading online accounts...", 12.0, 0.0, 12.0, TEXT_DIM);
-            sec_accounts.spacing(18.0);
+            sec_accounts.spacing(lm * 1.5);
         } else {
-            let row_h = 28.0;
-            let row_gap = 8.0;
             let item_w = sec_accounts.cw - 2.0 * (sec_accounts.padding() + 12.0);
 
             if state.accounts.is_empty() {
                 sec_accounts.text("No accounts configured.", 12.0, 0.0, 12.0, TEXT_DIM);
-                sec_accounts.spacing(20.0);
+                sec_accounts.spacing(lm * 1.5);
             } else {
                 for (idx, acc) in state.accounts.iter().enumerate() {
                     let label = if acc.is_default {
@@ -341,25 +384,38 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                         [0.90, 0.90, 0.95, 1.0],
                         AppAction::Accounts(AccountsMessage::SelectAccount(idx)),
                     );
-                    sec_accounts.spacing(row_h + row_gap);
+                    sec_accounts.spacing(row_gap);
                 }
             }
 
-            sec_accounts.spacing(12.0);
+            sec_accounts.spacing(lm * 1.2);
 
+            let half_btn_w = (item_w - btn_gap) / 2.0;
             let add_bg = if state.adding_new { [0.20, 0.40, 0.65, 0.4] } else { [0.13, 0.18, 0.14, 1.0] };
+            let btn_y = sec_accounts.ay();
             sec_accounts.button(
                 "Add Account",
                 sec_accounts.ax(12.0),
-                sec_accounts.ay(),
-                item_w,
+                btn_y,
+                half_btn_w,
                 row_h,
                 add_bg,
                 [0.25, 0.30, 0.26, 1.0],
                 [1.0, 1.0, 1.0, 1.0],
                 AppAction::Accounts(AccountsMessage::AddAccountStart),
             );
-            sec_accounts.spacing(row_h + row_gap);
+            sec_accounts.button(
+                "Sign in with Google",
+                sec_accounts.ax(12.0) + half_btn_w + btn_gap,
+                btn_y,
+                half_btn_w,
+                row_h,
+                [0.15, 0.15, 0.25, 1.0],
+                [0.25, 0.25, 0.35, 1.0],
+                [1.0, 1.0, 1.0, 1.0],
+                AppAction::Accounts(AccountsMessage::GoogleLoginInit),
+            );
+            sec_accounts.spacing(row_gap);
 
             let oauth_bg = if state.editing_oauth_creds { [0.20, 0.40, 0.65, 0.4] } else { [0.15, 0.15, 0.20, 1.0] };
             sec_accounts.button(
@@ -373,7 +429,7 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                 [1.0, 1.0, 1.0, 1.0],
                 AppAction::Accounts(AccountsMessage::EditOAuthCredsStart),
             );
-            sec_accounts.spacing(row_h + row_gap);
+            sec_accounts.spacing(row_gap);
 
             if let Some(selected_idx) = state.selected_idx {
                 if selected_idx < state.accounts.len() && !state.adding_new && !state.editing_oauth_creds {
@@ -390,7 +446,7 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                             [1.0, 1.0, 1.0, 1.0],
                             AppAction::Accounts(AccountsMessage::MakeDefault(selected_idx)),
                         );
-                        sec_accounts.spacing(row_h + row_gap);
+                        sec_accounts.spacing(row_gap);
                     }
                     sec_accounts.button(
                         "Delete Account",
@@ -403,7 +459,7 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                         [1.0, 0.33, 0.33, 1.0],
                         AppAction::Accounts(AccountsMessage::DeleteAccount(selected_idx)),
                     );
-                    sec_accounts.spacing(row_h + row_gap);
+                    sec_accounts.spacing(row_gap);
                 }
             }
         }
@@ -412,19 +468,15 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
     // ── Modify Accounts Section ──
     builder.add_section(&mut final_pc, "Modify Accounts", false, |sec_modify| {
         let item_w = sec_modify.cw - 2.0 * (sec_modify.padding() + 12.0);
-        let row_h = 28.0;
         let rx = sec_modify.left;
 
         if state.loaded {
             if state.adding_new {
                 sec_modify.text("Add New Account", 12.0, 0.0, 14.0, [0.35, 0.65, 0.90, 1.0]);
-                sec_modify.spacing(24.0);
+                sec_modify.spacing(lm * 2.5);
 
                 sec_modify.text("Note: Gmail uses Google Login. iCloud requires App PW.", 12.0, 0.0, 11.0, TEXT_DIM);
-                sec_modify.spacing(18.0);
-
-                let widget_h = 26.0;
-                let field_gap = 14.0;
+                sec_modify.spacing(lm * 1.8);
 
                 // Email Address textbox
                 state.email_box.set_row_rect(rx + 12.0, item_w);
@@ -446,11 +498,12 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                 sec_modify.widget(&mut state.smtp_box, 12.0, item_w, widget_h, ctx);
                 sec_modify.spacing(field_gap);
 
-                let helper_w = (item_w - 8.0) / 2.0;
+                let helper_w = (item_w - btn_gap) / 2.0;
+                let btn_y = sec_modify.ay();
                 sec_modify.button(
                     "Login (Google)",
                     sec_modify.ax(12.0),
-                    sec_modify.ay(),
+                    btn_y,
                     helper_w,
                     row_h,
                     [0.15, 0.15, 0.25, 1.0],
@@ -460,8 +513,8 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                 );
                 sec_modify.button(
                     "Login (iCloud)",
-                    sec_modify.ax(12.0) + helper_w + 8.0,
-                    sec_modify.ay(),
+                    sec_modify.ax(12.0) + helper_w + btn_gap,
+                    btn_y,
                     helper_w,
                     row_h,
                     [0.15, 0.15, 0.25, 1.0],
@@ -469,12 +522,13 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                     [1.0, 1.0, 1.0, 1.0],
                     AppAction::Accounts(AccountsMessage::ICloudLoginHelp),
                 );
-                sec_modify.spacing(row_h + 16.0);
+                sec_modify.spacing(lm * 1.8);
 
+                let btn_y2 = sec_modify.ay();
                 sec_modify.button(
                     "Save Account",
                     sec_modify.ax(12.0),
-                    sec_modify.ay(),
+                    btn_y2,
                     helper_w,
                     row_h,
                     [0.13, 0.18, 0.14, 1.0],
@@ -484,8 +538,8 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                 );
                 sec_modify.button(
                     "Cancel",
-                    sec_modify.ax(12.0) + helper_w + 8.0,
-                    sec_modify.ay(),
+                    sec_modify.ax(12.0) + helper_w + btn_gap,
+                    btn_y2,
                     helper_w,
                     row_h,
                     [0.33, 0.20, 0.20, 1.0],
@@ -493,18 +547,15 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                     [1.0, 1.0, 1.0, 1.0],
                     AppAction::Accounts(AccountsMessage::AddAccountCancel),
                 );
-                sec_modify.spacing(row_h + 12.0);
+                sec_modify.spacing(lm * 1.5);
             } else if state.editing_oauth_creds {
                 sec_modify.text("Google OAuth Credentials", 12.0, 0.0, 14.0, [0.35, 0.65, 0.90, 1.0]);
-                sec_modify.spacing(24.0);
+                sec_modify.spacing(lm * 2.5);
 
                 sec_modify.text("Configures client ID & secret from your Google Cloud Console.", 12.0, 0.0, 11.0, TEXT_DIM);
-                sec_modify.spacing(18.0);
+                sec_modify.spacing(lm * 1.5);
                 sec_modify.text("Required: Gmail API enabled & redirect URI set to http://127.0.0.1:8080", 12.0, 0.0, 11.0, TEXT_DIM);
-                sec_modify.spacing(18.0);
-
-                let widget_h = 26.0;
-                let field_gap = 14.0;
+                sec_modify.spacing(lm * 1.8);
 
                 // Client ID textbox
                 state.oauth_client_id_box.set_row_rect(rx + 12.0, item_w);
@@ -516,11 +567,12 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                 sec_modify.widget(&mut state.oauth_client_secret_box, 12.0, item_w, widget_h, ctx);
                 sec_modify.spacing(field_gap);
 
-                let helper_w = (item_w - 8.0) / 2.0;
+                let helper_w = (item_w - btn_gap) / 2.0;
+                let btn_y3 = sec_modify.ay();
                 sec_modify.button(
                     "Save Credentials",
                     sec_modify.ax(12.0),
-                    sec_modify.ay(),
+                    btn_y3,
                     helper_w,
                     row_h,
                     [0.13, 0.18, 0.14, 1.0],
@@ -530,8 +582,8 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                 );
                 sec_modify.button(
                     "Cancel",
-                    sec_modify.ax(12.0) + helper_w + 8.0,
-                    sec_modify.ay(),
+                    sec_modify.ax(12.0) + helper_w + btn_gap,
+                    btn_y3,
                     helper_w,
                     row_h,
                     [0.33, 0.20, 0.20, 1.0],
@@ -539,26 +591,26 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                     [1.0, 1.0, 1.0, 1.0],
                     AppAction::Accounts(AccountsMessage::EditOAuthCredsCancel),
                 );
-                sec_modify.spacing(row_h + 12.0);
+                sec_modify.spacing(lm * 1.5);
             } else if let Some(selected_idx) = state.selected_idx {
                 if selected_idx < state.accounts.len() {
                     let acc = &state.accounts[selected_idx];
 
                     sec_modify.text("Account Details", 12.0, 0.0, 14.0, [0.35, 0.65, 0.90, 1.0]);
-                    sec_modify.spacing(28.0);
+                    sec_modify.spacing(lm * 2.5);
 
                     sec_modify.text(&format!("Email Address:   {}", acc.email), 12.0, 0.0, 12.0, [0.90, 0.90, 0.95, 1.0]);
-                    sec_modify.spacing(18.0);
+                    sec_modify.spacing(lm * 1.8);
 
                     let auth_type = if acc.is_oauth { "OAuth2 (Google)" } else { "Password-based" };
                     sec_modify.text(&format!("Authentication:  {}", auth_type), 12.0, 0.0, 12.0, [0.83, 0.83, 0.83, 1.0]);
-                    sec_modify.spacing(18.0);
+                    sec_modify.spacing(lm * 1.8);
 
                     sec_modify.text(&format!("IMAP Server:     {}", acc.imap), 12.0, 0.0, 12.0, [0.83, 0.83, 0.83, 1.0]);
-                    sec_modify.spacing(18.0);
+                    sec_modify.spacing(lm * 1.8);
 
                     sec_modify.text(&format!("SMTP Server:     {}", acc.smtp), 12.0, 0.0, 12.0, [0.83, 0.83, 0.83, 1.0]);
-                    sec_modify.spacing(24.0);
+                    sec_modify.spacing(lm * 2.2);
 
                     if acc.is_oauth {
                         sec_modify.button(
@@ -572,18 +624,18 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
                             [1.0, 1.0, 1.0, 1.0],
                             AppAction::Accounts(AccountsMessage::GoogleLoginInit),
                         );
-                        sec_modify.spacing(row_h + 12.0);
+                        sec_modify.spacing(lm * 1.5);
                     }
                 }
             } else {
                 sec_modify.text("Select an account to view details, or click Add Account.", 12.0, 0.0, 12.0, TEXT_DIM);
-                sec_modify.spacing(20.0);
+                sec_modify.spacing(lm * 1.8);
             }
 
             if let Some(ref msg) = state.status_msg {
-                sec_modify.spacing(12.0);
+                sec_modify.spacing(lm * 1.2);
                 sec_modify.text(msg, 12.0, 0.0, 12.0, [0.56, 0.83, 0.56, 1.0]);
-                sec_modify.spacing(24.0);
+                sec_modify.spacing(lm * 2.0);
             }
         }
     });
diff --git a/src/pages/audio.rs b/src/pages/audio.rs
index 475db53..218505e 100644
--- a/src/pages/audio.rs
+++ b/src/pages/audio.rs
@@ -234,50 +234,58 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
 
         if state.loaded {
             for (idx, sink) in state.sinks.iter().enumerate() {
-                if !sink.active {
-                    let label = format!("{}  (inactive)", sink.name);
-                    let lc = if sink.muted { RED } else { TEXT_FG };
-                    sec.text(&label, 14.0, 0.0, 13.0, lc);
-                    sec.spacing(18.0);
+                let sec_title = if sink.active {
+                    sink.name.clone()
                 } else {
-                    let label = if sink.muted {
-                        format!("{}  {:.0}%  (muted)", sink.name, sink.volume * 100.0)
+                    format!("{} (inactive)", sink.name)
+                };
+
+                sec.add_section(&sec_title, false, |subsec| {
+                    if !sink.active {
+                        subsec.spacing(8.0);
+                        subsec.text("Device is inactive.", 12.0, 0.0, 12.0, TEXT_DIM);
+                        subsec.spacing(8.0);
                     } else {
-                        format!("{}  {:.0}%", sink.name, sink.volume * 100.0)
-                    };
-                    state.sink_sliders[idx].set_label(&label);
-
-                    let bar_w = sec_w - 100.0;
-                    let bar_x = 14.0;
-                    let yt = sec.ay();
-                    state.sink_sliders[idx].set_value(sink.volume);
-                    let slider_x = sec.ax(bar_x);
-                    
-                                        let label_h = clear_ui::widget::label_offset(&state.sink_sliders[idx]);
-                    let slider_h = clear_ui::layout::slider_height() + label_h;
-                    render_widget(sec.pc, &mut state.sink_sliders[idx], slider_x, yt, bar_w, slider_h, ctx);
-
-                    let row_y = sec.ay() + slider_h + 8.0;
-                    let sb_w = 100.0;
-                    let sb_h = clear_ui::layout::spinbox_height();
-                    let mute_w = 60.0;
-                    let gap = 8.0;
-
-                    let row_rect_x = sec.ax(8.0);
-                    state.sink_spinboxes[idx].value = (sink.volume * 100.0).round() as i32;
-                    state.sink_spinboxes[idx].set_row_rect(row_rect_x, sec_w - 16.0);
-                    let sb_x = sec.ax(bar_x);
-                    render_widget(sec.pc, &mut state.sink_spinboxes[idx], sb_x, row_y, sb_w, sb_h, ctx);
-
-                    let mute_label = if sink.muted { "Unmute" } else { "Mute" };
-                    let mute_col = if sink.muted { MUTED_BG } else { BTN_INACTIVE };
-                    let mute_btn_x = sb_x + sb_w + gap;
-                    sec.button(mute_label, mute_btn_x, row_y, mute_w, sb_h,
-                        mute_col, BTN_HOVER, WHITE,
-                        AppAction::Audio(AudioMessage::SinkMute(sink.id)));
-
-                    sec.content_y += slider_h + 8.0 + sb_h + 6.0;
-                }
+                        subsec.spacing(8.0);
+                        let label = if sink.muted {
+                            format!("Volume: {:.0}%  (muted)", sink.volume * 100.0)
+                        } else {
+                            format!("Volume: {:.0}%", sink.volume * 100.0)
+                        };
+                        state.sink_sliders[idx].set_label(&label);
+
+                        let bar_w = subsec.cw - 2.0 * (subsec.padding() + 14.0);
+                        let bar_x = 14.0;
+                        let yt = subsec.ay();
+                        state.sink_sliders[idx].set_value(sink.volume);
+                        let slider_x = subsec.ax(bar_x);
+                        
+                        let label_h = clear_ui::widget::label_offset(&state.sink_sliders[idx]);
+                        let slider_h = clear_ui::layout::slider_height() + label_h;
+                        render_widget(subsec.pc, &mut state.sink_sliders[idx], slider_x, yt, bar_w, slider_h, ctx);
+
+                        let row_y = subsec.ay() + slider_h + 8.0;
+                        let sb_w = 100.0;
+                        let sb_h = clear_ui::layout::spinbox_height();
+                        let mute_w = 60.0;
+                        let gap = 8.0;
+
+                        let row_rect_x = subsec.ax(8.0);
+                        state.sink_spinboxes[idx].value = (sink.volume * 100.0).round() as i32;
+                        state.sink_spinboxes[idx].set_row_rect(row_rect_x, subsec.cw - 16.0);
+                        let sb_x = subsec.ax(bar_x);
+                        render_widget(subsec.pc, &mut state.sink_spinboxes[idx], sb_x, row_y, sb_w, sb_h, ctx);
+
+                        let mute_label = if sink.muted { "Unmute" } else { "Mute" };
+                        let mute_col = if sink.muted { MUTED_BG } else { BTN_INACTIVE };
+                        let mute_btn_x = sb_x + sb_w + gap;
+                        subsec.button(mute_label, mute_btn_x, row_y, mute_w, sb_h,
+                            mute_col, BTN_HOVER, WHITE,
+                            AppAction::Audio(AudioMessage::SinkMute(sink.id)));
+
+                        subsec.content_y = row_y + sb_h - 4.0;
+                    }
+                });
             }
         }
     });
@@ -294,50 +302,58 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
 
         if state.loaded {
             for (idx, src) in state.sources.iter().enumerate() {
-                if !src.active {
-                    let label = format!("{}  (inactive)", src.name);
-                    let lc = if src.muted { RED } else { TEXT_FG };
-                    sec.text(&label, 14.0, 0.0, 13.0, lc);
-                    sec.spacing(18.0);
+                let sec_title = if src.active {
+                    src.name.clone()
                 } else {
-                    let label = if src.muted {
-                        format!("{}  {:.0}%  (muted)", src.name, src.volume * 100.0)
+                    format!("{} (inactive)", src.name)
+                };
+
+                sec.add_section(&sec_title, false, |subsec| {
+                    if !src.active {
+                        subsec.spacing(8.0);
+                        subsec.text("Device is inactive.", 12.0, 0.0, 12.0, TEXT_DIM);
+                        subsec.spacing(8.0);
                     } else {
-                        format!("{}  {:.0}%", src.name, src.volume * 100.0)
-                    };
-                    state.source_sliders[idx].set_label(&label);
-
-                    let bar_w = sec_w - 100.0;
-                    let bar_x = 14.0;
-                    let yt = sec.ay();
-                    state.source_sliders[idx].set_value(src.volume);
-                    let slider_x = sec.ax(bar_x);
-                    
-                                        let label_h = clear_ui::widget::label_offset(&state.source_sliders[idx]);
-                    let slider_h = clear_ui::layout::slider_height() + label_h;
-                    render_widget(sec.pc, &mut state.source_sliders[idx], slider_x, yt, bar_w, slider_h, ctx);
-
-                    let row_y = sec.ay() + slider_h + 8.0;
-                    let sb_w = 100.0;
-                    let sb_h = clear_ui::layout::spinbox_height();
-                    let mute_w = 60.0;
-                    let gap = 8.0;
-
-                    let row_rect_x = sec.ax(8.0);
-                    state.source_spinboxes[idx].value = (src.volume * 100.0).round() as i32;
-                    state.source_spinboxes[idx].set_row_rect(row_rect_x, sec_w - 16.0);
-                    let sb_x = sec.ax(bar_x);
-                    render_widget(sec.pc, &mut state.source_spinboxes[idx], sb_x, row_y, sb_w, sb_h, ctx);
-
-                    let mute_label = if src.muted { "Unmute" } else { "Mute" };
-                    let mute_col = if src.muted { MUTED_BG } else { BTN_INACTIVE };
-                    let mute_btn_x = sb_x + sb_w + gap;
-                    sec.button(mute_label, mute_btn_x, row_y, mute_w, sb_h,
-                        mute_col, BTN_HOVER, WHITE,
-                        AppAction::Audio(AudioMessage::SourceMute(src.id)));
-
-                    sec.content_y += slider_h + 8.0 + sb_h + 6.0;
-                }
+                        subsec.spacing(8.0);
+                        let label = if src.muted {
+                            format!("Volume: {:.0}%  (muted)", src.volume * 100.0)
+                        } else {
+                            format!("Volume: {:.0}%", src.volume * 100.0)
+                        };
+                        state.source_sliders[idx].set_label(&label);
+
+                        let bar_w = subsec.cw - 2.0 * (subsec.padding() + 14.0);
+                        let bar_x = 14.0;
+                        let yt = subsec.ay();
+                        state.source_sliders[idx].set_value(src.volume);
+                        let slider_x = subsec.ax(bar_x);
+                        
+                        let label_h = clear_ui::widget::label_offset(&state.source_sliders[idx]);
+                        let slider_h = clear_ui::layout::slider_height() + label_h;
+                        render_widget(subsec.pc, &mut state.source_sliders[idx], slider_x, yt, bar_w, slider_h, ctx);
+
+                        let row_y = subsec.ay() + slider_h + 8.0;
+                        let sb_w = 100.0;
+                        let sb_h = clear_ui::layout::spinbox_height();
+                        let mute_w = 60.0;
+                        let gap = 8.0;
+
+                        let row_rect_x = subsec.ax(8.0);
+                        state.source_spinboxes[idx].value = (src.volume * 100.0).round() as i32;
+                        state.source_spinboxes[idx].set_row_rect(row_rect_x, subsec.cw - 16.0);
+                        let sb_x = subsec.ax(bar_x);
+                        render_widget(subsec.pc, &mut state.source_spinboxes[idx], sb_x, row_y, sb_w, sb_h, ctx);
+
+                        let mute_label = if src.muted { "Unmute" } else { "Mute" };
+                        let mute_col = if src.muted { MUTED_BG } else { BTN_INACTIVE };
+                        let mute_btn_x = sb_x + sb_w + gap;
+                        subsec.button(mute_label, mute_btn_x, row_y, mute_w, sb_h,
+                            mute_col, BTN_HOVER, WHITE,
+                            AppAction::Audio(AudioMessage::SourceMute(src.id)));
+
+                        subsec.content_y = row_y + sb_h - 4.0;
+                    }
+                });
             }
         }
     });
diff --git a/src/pages/hardware.rs b/src/pages/hardware.rs
index e4ba86b..c6be8a6 100644
--- a/src/pages/hardware.rs
+++ b/src/pages/hardware.rs
@@ -1,4 +1,4 @@
-use crate::app::{AppAction, PageContent, SectionContextExt};
+use crate::app::{AppAction, PageContent};
 use clear_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
 use clear_ui::widget::{Label, ScrollingList, Dropdown, InfoBox};
 
@@ -384,7 +384,7 @@ pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_
     let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(5);
 
     // ── CPU Section ──
-    builder.add_section_with_width(&mut final_pc, sec_w * 2.0 + 20.0, "CPU", root_focused, |sec| {
+    builder.add_section(&mut final_pc, "CPU", root_focused, |sec| {
         let rx = sec.left;
         if !state.loaded {
             sec.text("Loading CPU model and utilization...", 12.0, 0.0, 12.0, TEXT_FG);
@@ -428,7 +428,7 @@ pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_
             for (idx, (pid, cpu, comm)) in state.processes.iter().enumerate() {
                 if let Some(draw_y) = state.cpu_list_box.get_item_draw_y(idx, 4.0) {
                     // Standard row action button (transparent background, highlights on hover)
-                    sec.button(
+                    sec.pc.button(
                         "",
                         list_box_x + 2.0,
                         draw_y,
diff --git a/src/pages/interface.rs b/src/pages/interface.rs
index af82da4..72740e6 100644
--- a/src/pages/interface.rs
+++ b/src/pages/interface.rs
@@ -3,7 +3,7 @@ use std::io::Write;
 use crate::app::PageContent;
 use clear_ui::layout::{PageLayoutBuilder, LayoutStrategy};
 use clear_ui::widget::{
-    ColorSelector, Spinbox, Element, Dropdown, TextBox, FontSelector, Toggle, Slider
+    ColorSelector, Spinbox, Element, Dropdown, TextBox, FontSelector, Toggle
 };
 
 const CONFIG_PATH: &str = "/home/lsgalante/.config/cce/config.toml";
@@ -68,6 +68,8 @@ pub struct InterfaceState {
     pub font_selector_height_spinbox: Spinbox,
     pub dropdown_height: u16,
     pub dropdown_height_spinbox: Spinbox,
+    pub button_corner_radius: u16,
+    pub button_corner_radius_spinbox: Spinbox,
     pub nested_section_label_alignment: u8,
     pub label_alignment_menu: Dropdown,
     pub nested_section_label_offset: i16,
@@ -116,8 +118,10 @@ pub struct InterfaceState {
     pub graph_snap_enabled_toggle: Toggle,
     pub graph_uniform_background: bool,
     pub graph_uniform_background_toggle: Toggle,
-    pub graph_network_opacity: f32,
-    pub graph_network_opacity_slider: Slider,
+    pub graph_cell_opacity: f32,
+    pub graph_cell_opacity_spinbox: Spinbox,
+    pub graph_gap_opacity: f32,
+    pub graph_gap_opacity_spinbox: Spinbox,
     pub graph_gap_width: u16,
     pub graph_gap_width_spinbox: Spinbox,
 }
@@ -189,6 +193,8 @@ impl Default for InterfaceState {
             font_selector_height_spinbox: Spinbox::new(44, 10, 100, 1).with_label("Height").with_unit("px"),
             dropdown_height: 44,
             dropdown_height_spinbox: Spinbox::new(44, 10, 100, 1).with_label("Height").with_unit("px"),
+            button_corner_radius: 4,
+            button_corner_radius_spinbox: Spinbox::new(4, 0, 50, 1).with_label("Radius").with_unit("px"),
             nested_section_label_alignment: 0,
             label_alignment_menu: Dropdown::new(
                 vec!["Left".to_string(), "Center".to_string(), "Right".to_string()],
@@ -238,8 +244,10 @@ impl Default for InterfaceState {
             graph_snap_enabled_toggle: Toggle::new().with_label("Grid Snapping"),
             graph_uniform_background: false,
             graph_uniform_background_toggle: Toggle::new().with_label("Uniform Background"),
-            graph_network_opacity: 0.95,
-            graph_network_opacity_slider: Slider::new().with_label("Network Opacity").with_value(0.95),
+            graph_cell_opacity: 0.95,
+            graph_cell_opacity_spinbox: Spinbox::new(95, 0, 100, 5).with_label("Cell Opacity").with_unit("%"),
+            graph_gap_opacity: 0.95,
+            graph_gap_opacity_spinbox: Spinbox::new(95, 0, 100, 5).with_label("Gap Opacity").with_unit("%"),
             graph_gap_width: 35,
             graph_gap_width_spinbox: Spinbox::new(35, 0, 100, 1).with_label("Gap Width").with_unit("px"),
             menubar_opacity: 0.9,
@@ -281,6 +289,7 @@ pub enum InterfaceMessage {
     SetSliderHeight(u16),
     SetFontSelectorHeight(u16),
     SetDropdownHeight(u16),
+    SetButtonCornerRadius(u16),
     SetColorSelectorFont(String),
     SetMenubarFont(String),
     SetSectionLabelFont(String),
@@ -291,7 +300,8 @@ pub enum InterfaceMessage {
     SetGraphShowGrid(bool),
     SetGraphSnapEnabled(bool),
     SetGraphUniformBackground(bool),
-    SetGraphOpacity(f32),
+    SetGraphCellOpacity(f32),
+    SetGraphGapOpacity(f32),
     SetGraphGapWidth(u16),
     SetMenubarOpacity(f32),
     PickLowColor,
@@ -385,6 +395,7 @@ pub fn read_interface_config() -> InterfaceState {
     let slider_height = parse_u16_from(&content, "slider_height", 28);
     let font_selector_height = parse_u16_from(&content, "font_selector_height", 44);
     let dropdown_height = parse_u16_from(&content, "dropdown_height", 44);
+    let button_corner_radius = parse_u16_from(&content, "button_corner_radius", 4);
     let color_selector_font = parse_string_from(&content, "color_selector_font", "monospace");
     let menubar_font = parse_string_from(&content, "menubar_font", "Outfit");
     let section_label_font = parse_string_from(&content, "section_label_font", "Outfit");
@@ -395,7 +406,9 @@ pub fn read_interface_config() -> InterfaceState {
     let graph_show_grid = parse_bool_from(&content, "graph_show_grid", true);
     let graph_snap_enabled = parse_bool_from(&content, "graph_snap_enabled", true);
     let graph_uniform_background = parse_bool_from(&content, "graph_uniform_background", false);
-    let graph_network_opacity = parse_f32_from(&content, "graph_network_opacity", 0.95);
+    let legacy_opacity = parse_f32_from(&content, "graph_network_opacity", 0.95);
+    let graph_cell_opacity = parse_f32_from(&content, "graph_cell_opacity", legacy_opacity);
+    let graph_gap_opacity = parse_f32_from(&content, "graph_gap_opacity", legacy_opacity);
     let graph_gap_width = parse_u16_from(&content, "graph_gap_width", 35);
     let opacity = parse_transparency_opacity(&content);
     
@@ -464,6 +477,8 @@ pub fn read_interface_config() -> InterfaceState {
         font_selector_height_spinbox: Spinbox::new(font_selector_height as i32, 10, 100, 1).with_label("Height").with_unit("px"),
         dropdown_height,
         dropdown_height_spinbox: Spinbox::new(dropdown_height as i32, 10, 100, 1).with_label("Height").with_unit("px"),
+        button_corner_radius,
+        button_corner_radius_spinbox: Spinbox::new(button_corner_radius as i32, 0, 50, 1).with_label("Radius").with_unit("px"),
         nested_section_label_alignment,
         label_alignment_menu: Dropdown::new(
             vec!["Left".to_string(), "Center".to_string(), "Right".to_string()],
@@ -513,8 +528,10 @@ pub fn read_interface_config() -> InterfaceState {
         graph_snap_enabled_toggle: Toggle::new().with_label("Grid Snapping"),
         graph_uniform_background,
         graph_uniform_background_toggle: Toggle::new().with_label("Uniform Background"),
-        graph_network_opacity,
-        graph_network_opacity_slider: Slider::new().with_label("Network Opacity").with_value(graph_network_opacity),
+        graph_cell_opacity,
+        graph_cell_opacity_spinbox: Spinbox::new((graph_cell_opacity * 100.0).round() as i32, 0, 100, 5).with_label("Cell Opacity").with_unit("%"),
+        graph_gap_opacity,
+        graph_gap_opacity_spinbox: Spinbox::new((graph_gap_opacity * 100.0).round() as i32, 0, 100, 5).with_label("Gap Opacity").with_unit("%"),
         graph_gap_width,
         graph_gap_width_spinbox: Spinbox::new(graph_gap_width as i32, 0, 100, 1).with_label("Gap Width").with_unit("px"),
         menubar_opacity: opacity,
@@ -834,6 +851,11 @@ fn apply_dropdown_height(height: u16) {
     clear_ui::layout::set_dropdown_height(height as f32);
 }
 
+fn apply_button_corner_radius(radius: u16) {
+    write_config_value("button_corner_radius", &radius.to_string());
+    clear_ui::layout::set_button_corner_radius(radius as f32);
+}
+
 fn apply_color_selector_font(font: &str) {
     write_config_value("color_selector_font", &format!("\"{}\"", font));
     clear_ui::layout::set_color_selector_font(font);
@@ -1349,9 +1371,12 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
             subsec.spacing(8.0);
             state.graph_uniform_background_toggle.set_toggled(state.graph_uniform_background);
             subsec.widget_full(&mut state.graph_uniform_background_toggle, state.toggle_height as f32, ctx);
-            subsec.spacing(12.0);
-            state.graph_network_opacity_slider.set_value(state.graph_network_opacity);
-            subsec.widget_full(&mut state.graph_network_opacity_slider, state.slider_height as f32, ctx);
+            subsec.spacing(8.0);
+            state.graph_cell_opacity_spinbox.value = (state.graph_cell_opacity * 100.0).round() as i32;
+            subsec.widget_full(&mut state.graph_cell_opacity_spinbox, 44.0, ctx);
+            subsec.spacing(8.0);
+            state.graph_gap_opacity_spinbox.value = (state.graph_gap_opacity * 100.0).round() as i32;
+            subsec.widget_full(&mut state.graph_gap_opacity_spinbox, 44.0, ctx);
             subsec.spacing(8.0);
             state.graph_gap_width_spinbox.value = state.graph_gap_width as i32;
             subsec.widget_full(&mut state.graph_gap_width_spinbox, 44.0, ctx);
@@ -1495,6 +1520,15 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
         });
         sec.spacing(12.0);
 
+        // Button Section
+        sec.add_section("Button", false, |subsec| {
+            subsec.spacing(8.0);
+            state.button_corner_radius_spinbox.value = state.button_corner_radius as i32;
+            subsec.widget_full(&mut state.button_corner_radius_spinbox, 44.0, ctx);
+            subsec.spacing(8.0);
+        });
+        sec.spacing(12.0);
+
         // Labels Section
         sec.add_section("Labels", false, |subsec| {
             subsec.spacing(8.0);
@@ -1742,6 +1776,10 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
             state.dropdown_height = height;
             apply_dropdown_height(height);
         }
+        InterfaceMessage::SetButtonCornerRadius(radius) => {
+            state.button_corner_radius = radius;
+            apply_button_corner_radius(radius);
+        }
         InterfaceMessage::SetColorSelectorFont(font) => {
             state.color_selector_font = font.clone();
             state.color_selector_font_selector.font_family = font.clone();
@@ -1798,10 +1836,16 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
             write_config_value("graph_uniform_background", &uniform.to_string());
             cce_graph_reload();
         }
-        InterfaceMessage::SetGraphOpacity(opacity) => {
-            state.graph_network_opacity = opacity;
-            state.graph_network_opacity_slider.set_value(opacity);
-            write_config_value("graph_network_opacity", &format!("{:.2}", opacity));
+        InterfaceMessage::SetGraphCellOpacity(opacity) => {
+            state.graph_cell_opacity = opacity;
+            state.graph_cell_opacity_spinbox.value = (opacity * 100.0).round() as i32;
+            write_config_value("graph_cell_opacity", &format!("{:.2}", opacity));
+            cce_graph_reload();
+        }
+        InterfaceMessage::SetGraphGapOpacity(opacity) => {
+            state.graph_gap_opacity = opacity;
+            state.graph_gap_opacity_spinbox.value = (opacity * 100.0).round() as i32;
+            write_config_value("graph_gap_opacity", &format!("{:.2}", opacity));
             cce_graph_reload();
         }
         InterfaceMessage::SetGraphGapWidth(gap) => {
@@ -1815,6 +1859,7 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
             state.menubar_opacity_spinbox.value = (opacity * 100.0).round() as i32;
             write_transparency_config_value("opacity", &format!("{:.2}", opacity));
             send_ipc_command("reload");
+            status_interface_reload();
         }
         InterfaceMessage::PickLowColor | InterfaceMessage::PickHighColor | InterfaceMessage::PickDisabledColor | InterfaceMessage::PickSeparatorColor | InterfaceMessage::PickVisualGuides | InterfaceMessage::PickSliderTrackColor | InterfaceMessage::PickPageLowColor | InterfaceMessage::PickColorBordersColor | InterfaceMessage::PickNormalColor | InterfaceMessage::PickPaginatorSidebarColor | InterfaceMessage::PickPrimaryHighlightColor | InterfaceMessage::PickPaginatorTabLabelColor | InterfaceMessage::PickToggleEnabledColor | InterfaceMessage::PickToggleDisabledColor => {}
         InterfaceMessage::Refreshed(new) => {
@@ -1831,7 +1876,8 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
             let was_gsg_hovered = state.graph_show_grid_toggle.hovered();
             let was_gse_hovered = state.graph_snap_enabled_toggle.hovered();
             let was_gub_hovered = state.graph_uniform_background_toggle.hovered();
-            let was_gno_hovered = state.graph_network_opacity_slider.hovered();
+            let was_gco_hovered = state.graph_cell_opacity_spinbox.hovered();
+            let was_ggo_hovered = state.graph_gap_opacity_spinbox.hovered();
             let was_ggw_hovered = state.graph_gap_width_spinbox.hovered();
             let was_csh_hovered = state.color_selector_height_spinbox.hovered();
             let was_tbh_hovered = state.textbox_height_spinbox.hovered();
@@ -1881,7 +1927,8 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
             state.graph_show_grid_toggle.set_hovered(was_gsg_hovered);
             state.graph_snap_enabled_toggle.set_hovered(was_gse_hovered);
             state.graph_uniform_background_toggle.set_hovered(was_gub_hovered);
-            state.graph_network_opacity_slider.set_hovered(was_gno_hovered);
+            state.graph_cell_opacity_spinbox.set_hovered(was_gco_hovered);
+            state.graph_gap_opacity_spinbox.set_hovered(was_ggo_hovered);
             state.graph_gap_width_spinbox.set_hovered(was_ggw_hovered);
             state.color_selector_height_spinbox.set_hovered(was_csh_hovered);
             state.textbox_height_spinbox.set_hovered(was_tbh_hovered);
@@ -3019,6 +3066,34 @@ mod tests {
         // Clean up
         let _ = fs::remove_file(path_str);
     }
+
+    #[test]
+    fn test_read_write_button_corner_radius() {
+        let dir = std::env::temp_dir();
+        let path = dir.join("test_button_corner_radius_config.toml");
+        let path_str = path.to_str().unwrap();
+
+        // 1. Initial configuration
+        let initial_content = "[layout]\ngap = 18\n";
+        fs::write(path_str, initial_content).unwrap();
+
+        // 2. Parse when missing (should return default 4)
+        let content = fs::read_to_string(path_str).unwrap();
+        let val = parse_u16_from(&content, "button_corner_radius", 4);
+        assert_eq!(val, 4);
+
+        // 3. Write button_corner_radius config
+        assert!(write_config_value_path(path_str, "button_corner_radius", "12"));
+        let updated = fs::read_to_string(path_str).unwrap();
+        assert!(updated.contains("button_corner_radius = 12"));
+
+        // 4. Parse when present (should return written value 12)
+        let val2 = parse_u16_from(&updated, "button_corner_radius", 4);
+        assert_eq!(val2, 12);
+
+        // Clean up
+        let _ = fs::remove_file(path_str);
+    }
 }
 
 
diff --git a/src/pages/layout.rs b/src/pages/layout.rs
index 8fe9ef4..7c83bfe 100644
--- a/src/pages/layout.rs
+++ b/src/pages/layout.rs
@@ -73,8 +73,13 @@ pub struct LayoutState {
     pub transition_duration_spinbox: Spinbox,
     pub tag_layout_menus: Vec<Dropdown>,
     pub side_panel_behavior_menu: Dropdown,
+    pub side_panel_position_menu: Dropdown,
     pub side_panel_width: u16,
     pub side_panel_width_spinbox: Spinbox,
+    pub side_panel_border_gap: u16,
+    pub side_panel_border_gap_spinbox: Spinbox,
+    pub side_panel_border_opacity: u16,
+    pub side_panel_border_opacity_spinbox: Spinbox,
 }
 
 impl Default for LayoutState {
@@ -113,8 +118,16 @@ impl Default for LayoutState {
                 vec!["Above".to_string(), "Inline".to_string()],
                 1,
             ).with_label("Behavior"),
+            side_panel_position_menu: Dropdown::new(
+                vec!["Left".to_string(), "Right".to_string()],
+                0,
+            ).with_label("Position"),
             side_panel_width: 360,
             side_panel_width_spinbox: Spinbox::new(360, 0, 2000, 10),
+            side_panel_border_gap: 0,
+            side_panel_border_gap_spinbox: Spinbox::new(0, 0, 500, 1),
+            side_panel_border_opacity: 100,
+            side_panel_border_opacity_spinbox: Spinbox::new(100, 0, 100, 5),
         }
     }
 }
@@ -130,7 +143,10 @@ pub enum LayoutMessage {
     SetStatusHeight(u16),
     SetTagLayout(usize, usize),
     SetSidePanelBehavior(usize),
+    SetSidePanelPosition(usize),
     SetSidePanelWidth(u16),
+    SetSidePanelBorderGap(u16),
+    SetSidePanelBorderOpacity(u16),
     Refreshed(LayoutState),
 }
 
@@ -168,7 +184,16 @@ pub fn read_layout_config() -> LayoutState {
         side_panel_behavior_idx,
     ).with_label("Behavior");
 
+    let side_panel_position = parse_string_from(&content, "side_panel_position", "left");
+    let side_panel_position_idx = if side_panel_position == "right" { 1 } else { 0 };
+    let side_panel_position_menu = Dropdown::new(
+        vec!["Left".to_string(), "Right".to_string()],
+        side_panel_position_idx,
+    ).with_label("Position");
+
     let spw = parse_u16_from(&content, "side_panel_width", 360);
+    let spbg = parse_u16_from(&content, "side_panel_border_gap", 0);
+    let spbo = parse_u16_from(&content, "side_panel_border_opacity", 100);
 
     LayoutState {
         fullscreen_border_width: fs,
@@ -190,8 +215,13 @@ pub fn read_layout_config() -> LayoutState {
         transition_duration_spinbox: Spinbox::new(td as i32, 0, 2000, 50),
         tag_layout_menus,
         side_panel_behavior_menu,
+        side_panel_position_menu,
         side_panel_width: spw,
         side_panel_width_spinbox: Spinbox::new(spw as i32, 0, 2000, 10),
+        side_panel_border_gap: spbg,
+        side_panel_border_gap_spinbox: Spinbox::new(spbg as i32, 0, 500, 1),
+        side_panel_border_opacity: spbo,
+        side_panel_border_opacity_spinbox: Spinbox::new(spbo as i32, 0, 100, 5),
     }
 }
 
@@ -610,7 +640,7 @@ pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_foc
     });
 
     // 6. Default Layouts Section
-    builder.add_section(&mut final_pc, "Default Layouts", sec_focused.get(5).copied().unwrap_or(false), |default_layouts_sec| {
+    builder.add_section(&mut final_pc, "Default Layouts", true, |default_layouts_sec| {
         default_layouts_sec.spacing(8.0);
         for i in 0..4 {
             default_layouts_sec.widget_full(&mut state.tag_layout_menus[i], 44.0, ctx);
@@ -619,13 +649,21 @@ pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_foc
     });
 
     // 7. Side Panel Section
-    builder.add_section(&mut final_pc, "Side Panel", sec_focused.get(6).copied().unwrap_or(false), |side_panel_sec| {
+    builder.add_section(&mut final_pc, "Side Panel", true, |side_panel_sec| {
         side_panel_sec.spacing(8.0);
         side_panel_sec.widget_full(&mut state.side_panel_behavior_menu, 44.0, ctx);
         side_panel_sec.spacing(8.0);
+        side_panel_sec.widget_full(&mut state.side_panel_position_menu, 44.0, ctx);
+        side_panel_sec.spacing(8.0);
         state.side_panel_width_spinbox.set_label("Default Width");
         side_panel_sec.widget_full(&mut state.side_panel_width_spinbox, 44.0, ctx);
         side_panel_sec.spacing(8.0);
+        state.side_panel_border_gap_spinbox.set_label("Border Gap");
+        side_panel_sec.widget_full(&mut state.side_panel_border_gap_spinbox, 44.0, ctx);
+        side_panel_sec.spacing(8.0);
+        state.side_panel_border_opacity_spinbox.set_label("Border Opacity");
+        side_panel_sec.widget_full(&mut state.side_panel_border_opacity_spinbox, 44.0, ctx);
+        side_panel_sec.spacing(8.0);
     });
 
 
@@ -709,6 +747,14 @@ pub fn update(state: &mut LayoutState, msg: LayoutMessage) {
                 send_ipc_command(&format!("layout side_panel_behavior {}", val));
             }
         }
+        LayoutMessage::SetSidePanelPosition(idx) => {
+            if idx < 2 {
+                state.side_panel_position_menu.selected = idx;
+                let val = if idx == 1 { "right" } else { "left" };
+                write_config_value("side_panel_position", &format!("\"{}\"", val));
+                send_ipc_command(&format!("layout side_panel_position {}", val));
+            }
+        }
         LayoutMessage::SetSidePanelWidth(v) => {
             let val = v.min(2000);
             state.side_panel_width = val;
@@ -716,6 +762,20 @@ pub fn update(state: &mut LayoutState, msg: LayoutMessage) {
             write_config_value("side_panel_width", &val.to_string());
             send_ipc_command(&format!("layout side_panel_width {}", val));
         }
+        LayoutMessage::SetSidePanelBorderGap(v) => {
+            let val = v.min(500);
+            state.side_panel_border_gap = val;
+            state.side_panel_border_gap_spinbox.value = val as i32;
+            write_config_value("side_panel_border_gap", &val.to_string());
+            send_ipc_command(&format!("layout side_panel_border_gap {}", val));
+        }
+        LayoutMessage::SetSidePanelBorderOpacity(v) => {
+            let val = v.min(100);
+            state.side_panel_border_opacity = val;
+            state.side_panel_border_opacity_spinbox.value = val as i32;
+            write_config_value("side_panel_border_opacity", &val.to_string());
+            send_ipc_command(&format!("layout side_panel_border_opacity {}", val));
+        }
         LayoutMessage::Refreshed(new) => { *state = new; }
     }
 }
@@ -745,6 +805,20 @@ mod tests {
         assert_eq!(width, 450);
     }
 
+    #[test]
+    fn test_parse_side_panel_border_opacity_default() {
+        let content = "";
+        let opacity = parse_u16_from(content, "side_panel_border_opacity", 100);
+        assert_eq!(opacity, 100);
+    }
+
+    #[test]
+    fn test_parse_side_panel_border_opacity_explicit() {
+        let content = "side_panel_border_opacity = 75";
+        let opacity = parse_u16_from(content, "side_panel_border_opacity", 100);
+        assert_eq!(opacity, 75);
+    }
+
     #[test]
     fn test_parse_tag_layouts_single() {
         let content = r#"
diff --git a/src/pages/network.rs b/src/pages/network.rs
index adf55e1..df78063 100644
--- a/src/pages/network.rs
+++ b/src/pages/network.rs
@@ -1,6 +1,6 @@
 use crate::app::{AppAction, PageContent, SectionContextExt};
 use clear_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
-use clear_ui::widget::ScrollingList;
+use clear_ui::widget::{ScrollingList, Toggle, Element};
 
 #[derive(Debug, Clone)]
 pub struct WifiNetwork {
@@ -18,7 +18,7 @@ pub struct BluetoothDevice {
     pub connected: bool,
 }
 
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone)]
 pub struct NetworkState {
     pub loaded: bool,
     pub wifi_enabled: bool,
@@ -33,6 +33,30 @@ pub struct NetworkState {
     pub bt_devices: Vec<BluetoothDevice>,
     pub bt_scanning: bool,
     pub wifi_list_box: ScrollingList,
+    pub wifi_toggle: Toggle,
+    pub bt_toggle: Toggle,
+}
+
+impl Default for NetworkState {
+    fn default() -> Self {
+        Self {
+            loaded: false,
+            wifi_enabled: false,
+            connected_ssid: String::new(),
+            signal_strength: 0,
+            ip_address: String::new(),
+            device: String::new(),
+            available: Vec::new(),
+            bt_installed: false,
+            bt_service_active: false,
+            bt_enabled: false,
+            bt_devices: Vec::new(),
+            bt_scanning: false,
+            wifi_list_box: ScrollingList::new(26.0, 4.0),
+            wifi_toggle: Toggle::new(),
+            bt_toggle: Toggle::new(),
+        }
+    }
 }
 
 #[derive(Debug, Clone)]
@@ -55,17 +79,19 @@ pub async fn fetch_network_state() -> NetworkState {
         .unwrap_or(false);
 
     let active = tokio::process::Command::new("nmcli")
-        .args(["-t", "-f", "NAME,DEVICE,SIGNAL", "con", "show", "--active"])
+        .args(["-t", "-f", "NAME,DEVICE,TYPE", "con", "show", "--active"])
         .output().await.ok()
         .map(|o| String::from_utf8_lossy(&o.stdout).to_string())
         .unwrap_or_default();
 
     let (connected_ssid, device) = active.lines()
-        .filter(|l| !l.contains(":lo:"))
         .filter_map(|l| {
-            let parts: Vec<&str> = l.splitn(3, ':').collect();
-            if parts.len() >= 2 && !parts[0].is_empty() {
-                Some((parts[0].to_string(), parts[1].to_string()))
+            let parts: Vec<&str> = l.split(':').collect();
+            if parts.len() >= 3 && parts[parts.len() - 1] == "802-11-wireless" {
+                let ssid = parts[..parts.len() - 2].join(":");
+                let ssid_unescaped = ssid.replace("\\:", ":");
+                let device = parts[parts.len() - 2].to_string();
+                Some((ssid_unescaped, device))
             } else { None }
         }).next().unwrap_or_default();
 
@@ -85,7 +111,10 @@ pub async fn fetch_network_state() -> NetworkState {
         .and_then(|o| {
             String::from_utf8_lossy(&o.stdout).lines()
                 .find(|l| !l.is_empty())
-                .map(|l| l.split('/').next().unwrap_or(l).to_string())
+                .map(|l| {
+                    let val = l.split(':').nth(1).unwrap_or(l);
+                    val.split('/').next().unwrap_or(val).to_string()
+                })
         }).unwrap_or_default();
 
     let available = if wifi_enabled { fetch_wifi_list().await } else { Vec::new() };
@@ -98,6 +127,8 @@ pub async fn fetch_network_state() -> NetworkState {
         bt_installed, bt_service_active,
         bt_enabled, bt_devices, bt_scanning: false,
         wifi_list_box: ScrollingList::new(26.0, 4.0),
+        wifi_toggle: Toggle::new(),
+        bt_toggle: Toggle::new(),
     }
 }
 
@@ -251,60 +282,67 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
 
     // ── WiFi ──
     builder.add_section(&mut final_pc, "WiFi", root_focused, |sec| {
+        let sec_w = sec.cw;
         let rx = sec.left;
+        let padding = sec.padding();
+        let row_gap = clear_ui::layout::label_margin();
+        let margin = padding.max(12.0);
 
         if !state.loaded {
-            sec.text("Loading WiFi interfaces...", 12.0, 0.0, 12.0, TEXT_DIM);
-            sec.spacing(18.0);
+            sec.text("Loading WiFi interfaces...", margin, 0.0, 12.0, TEXT_DIM);
+            sec.spacing(12.0 + row_gap);
         } else {
-            let yt = sec.ay();
             let wifi_btn_w = if sec_w < 200.0 { 40.0 } else { 60.0 };
-            let wifi_btn_x = sec_w - wifi_btn_w - 12.0;
-
-            sec.button(if state.wifi_enabled { "ON" } else { "OFF" },
-                sec.ax(wifi_btn_x), yt, wifi_btn_w, 28.0,
-                if state.wifi_enabled { TOGGLE_ON } else { TOGGLE_OFF }, BTN_HOVER, WHITE,
-                AppAction::Radios(NetworkMessage::ToggleWifi));
-            sec.content_y += 34.0;
-
-            if !state.connected_ssid.is_empty() {
-                let ssid_max_chars = ((sec_w - 24.0) / 7.0) as usize;
-                let ssid_truncated = if state.connected_ssid.len() > ssid_max_chars {
-                    format!("{}...", &state.connected_ssid[..ssid_max_chars.saturating_sub(3)])
-                } else {
-                    state.connected_ssid.clone()
-                };
-                sec.text(&format!("Connected: {}", ssid_truncated), 14.0, 0.0, 13.0, ACCENT);
-                sec.spacing(18.0);
-
-                if sec_w < 220.0 {
-                    sec.text(&format!("Signal: {}%", state.signal_strength), 14.0, 0.0, 12.0, TEXT_DIM);
-                    sec.spacing(16.0);
-                    if !state.ip_address.is_empty() {
-                        sec.text(&format!("IP: {}", state.ip_address), 14.0, 0.0, 12.0, TEXT_DIM);
-                        sec.spacing(16.0);
+            let wifi_btn_x = margin;
+
+            state.wifi_toggle.set_toggled(state.wifi_enabled);
+            state.wifi_toggle.set_label(if state.wifi_enabled { "ON" } else { "OFF" });
+            sec.widget(&mut state.wifi_toggle, wifi_btn_x, wifi_btn_w, 28.0, ctx);
+            sec.spacing(row_gap);
+
+            if state.wifi_enabled {
+                let status_y = sec.ay();
+                let font_size_1 = 13.0;
+                let font_size_2 = 12.0;
+                let status_area_h;
+
+                if !state.connected_ssid.is_empty() {
+                    let y1 = 0.0;
+                    let y2 = font_size_1 + row_gap;
+                    status_area_h = y2 + font_size_2 + row_gap;
+
+                    let ssid_max_chars = ((sec_w - 2.0 * margin) / 7.0) as usize;
+                    let ssid_truncated = if state.connected_ssid.len() > ssid_max_chars {
+                        format!("{}...", &state.connected_ssid[..ssid_max_chars.saturating_sub(3)])
+                    } else {
+                        state.connected_ssid.clone()
+                    };
+                    sec.text(&format!("Connected: {}", ssid_truncated), margin, y1, font_size_1, ACCENT);
+
+                    if sec_w < 220.0 {
+                        sec.text(&format!("Signal: {}%", state.signal_strength), margin, y2, font_size_2, TEXT_DIM);
+                    } else {
+                        sec.text(&format!("Signal: {}%  IP: {}", state.signal_strength, state.ip_address),
+                            margin, y2, font_size_2, TEXT_DIM);
                     }
                 } else {
-                    sec.text(&format!("Signal: {}%  IP: {}", state.signal_strength, state.ip_address),
-                        14.0, 0.0, 12.0, TEXT_DIM);
-                    sec.spacing(16.0);
+                    status_area_h = font_size_2 + row_gap;
+                    sec.text("Not connected", margin, 0.0, font_size_2, TEXT_DIM);
                 }
-            } else if state.wifi_enabled {
-                sec.text("Not connected", 14.0, 0.0, 12.0, TEXT_DIM);
-                sec.spacing(16.0);
+                sec.content_y = status_y + status_area_h;
             }
 
             if state.wifi_enabled && !state.available.is_empty() {
-                let list_box_x = rx + 12.0;
+                let list_box_x = rx + margin;
                 let list_box_y = sec.ay();
-                let list_box_w = sec_w - 24.0;
+                let list_box_w = sec_w - 2.0 * margin;
                 let list_box_h = 160.0;
 
                 render_widget(sec.pc, &mut state.wifi_list_box, list_box_x, list_box_y, list_box_w, list_box_h, ctx);
 
                 state.wifi_list_box.update_bounds(state.available.len(), list_box_y, list_box_h);
 
-                let btn_w = list_box_w - 24.0;
+                let btn_w = list_box_w - 2.0 * margin;
                 let max_chars = ((btn_w / 6.5) as usize).saturating_sub(10).max(5);
 
                 for (idx, net) in state.available.iter().enumerate() {
@@ -317,65 +355,70 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
                         };
                         let label = format!("{}  {}  ({}%)", prefix, ssid_truncated, net.signal);
                         let active = net.in_use;
-                        sec.button(&label, list_box_x + 4.0, draw_y, btn_w, 26.0,
+                        sec.pc.button(&label, list_box_x + margin, draw_y, btn_w, 26.0,
                             if active { ACT_BTN } else { NET_BTN }, BTN_HOVER,
                             if active { ACCENT } else { TEXT_FG },
                             AppAction::Radios(NetworkMessage::ConnectWifi(net.ssid.clone())));
                     }
                 }
-                sec.content_y += list_box_h + 8.0;
+                sec.content_y += list_box_h + row_gap;
             }
         }
     });
 
     // ── Bluetooth ──
-    builder.add_section_with_width(&mut final_pc, sec_w * 2.0, "Bluetooth", false, |sec| {
-        let bt_sec_w = sec_w * 2.0;
-        let rx = sec.left;
+    builder.add_section(&mut final_pc, "Bluetooth", false, |sec| {
+        let bt_sec_w = sec.cw;
+        let padding = sec.padding();
+        let row_gap = clear_ui::layout::label_margin();
+        let margin = padding.max(12.0);
+        let font_size = 12.0;
+        let btn_h = 28.0;
 
         if !state.loaded {
-            sec.text("Loading Bluetooth status...", 12.0, 0.0, 12.0, TEXT_DIM);
-            sec.spacing(18.0);
+            sec.text("Loading Bluetooth status...", margin, 0.0, font_size, TEXT_DIM);
+            sec.spacing(font_size + row_gap);
         } else if !state.bt_installed {
-            sec.text("Bluetooth tools (bluez) not installed", 14.0, 0.0, 12.0, TEXT_DIM);
-            sec.spacing(18.0);
+            sec.text("Bluetooth tools (bluez) not installed", margin, 0.0, font_size, TEXT_DIM);
+            sec.spacing(font_size + row_gap);
             let btn_w = if bt_sec_w < 200.0 { 100.0 } else { 120.0 };
             let yt = sec.ay();
-            sec.button("Install Tools", rx + 12.0, yt, btn_w, 28.0,
+            sec.button("Install Tools", sec.ax(margin), yt, btn_w, btn_h,
                 TOGGLE_ON, BTN_HOVER, WHITE,
                 AppAction::Radios(NetworkMessage::InstallBtTools));
-            sec.content_y += 34.0;
+            sec.content_y = yt + btn_h + row_gap;
         } else if !state.bt_service_active {
-            sec.text("Bluetooth service is stopped", 14.0, 0.0, 12.0, TEXT_DIM);
-            sec.spacing(18.0);
+            sec.text("Bluetooth service is stopped", margin, 0.0, font_size, TEXT_DIM);
+            sec.spacing(font_size + row_gap);
             let btn_w = if bt_sec_w < 200.0 { 100.0 } else { 120.0 };
             let yt = sec.ay();
-            sec.button("Start Service", rx + 12.0, yt, btn_w, 28.0,
+            sec.button("Start Service", sec.ax(margin), yt, btn_w, btn_h,
                 TOGGLE_ON, BTN_HOVER, WHITE,
                 AppAction::Radios(NetworkMessage::StartBtService));
-            sec.content_y += 34.0;
+            sec.content_y = yt + btn_h + row_gap;
         } else {
             let yt = sec.ay();
             let bt_btn_w = if bt_sec_w < 200.0 { 40.0 } else { 60.0 };
             let scan_btn_w = if bt_sec_w < 200.0 { 40.0 } else { 52.0 };
-            let bt_btn_x = bt_sec_w - bt_btn_w - scan_btn_w - 20.0;
-            let scan_btn_x = bt_sec_w - scan_btn_w - 12.0;
-
-            sec.button(if state.bt_enabled { "ON" } else { "OFF" },
-                sec.ax(bt_btn_x), yt, bt_btn_w, 28.0,
-                if state.bt_enabled { TOGGLE_ON } else { TOGGLE_OFF }, BTN_HOVER, WHITE,
-                AppAction::Radios(NetworkMessage::ToggleBluetooth));
-            sec.button("Scan", sec.ax(scan_btn_x), yt, scan_btn_w, 28.0,
+            let bt_btn_x = margin;
+            let scan_btn_x = margin + bt_btn_w + row_gap;
+ 
+            state.bt_toggle.set_toggled(state.bt_enabled);
+            state.bt_toggle.set_label(if state.bt_enabled { "ON" } else { "OFF" });
+            sec.widget(&mut state.bt_toggle, bt_btn_x, bt_btn_w, btn_h, ctx);
+            sec.button("Scan", sec.ax(scan_btn_x), yt, scan_btn_w, btn_h,
                 TOGGLE_OFF, BTN_HOVER, WHITE,
                 AppAction::Radios(NetworkMessage::BtScan));
-            sec.content_y += 34.0;
-
+            sec.content_y = yt + btn_h + row_gap;
+ 
             if state.bt_devices.is_empty() {
                 if state.bt_enabled {
                     let no_devices_msg = if bt_sec_w < 200.0 { "No paired devices" } else { "No paired devices found" };
-                    sec.text(no_devices_msg, 14.0, 0.0, 12.0, TEXT_DIM);
+                    sec.text(no_devices_msg, margin, 0.0, font_size, TEXT_DIM);
+                    sec.spacing(font_size + row_gap);
                 }
             } else {
+                let item_h = 22.0;
                 for dev in &state.bt_devices {
                     let status = if dev.connected { ">" } else { " " };
                     let btn_w = if bt_sec_w < 250.0 { 42.0 } else { 70.0 };
@@ -384,10 +427,10 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
                     } else {
                         if bt_sec_w < 250.0 { "Conn" } else { "Connect" }
                     };
-
-                    let label_max_w = (bt_sec_w - btn_w - 20.0 - 14.0 - 8.0).max(20.0);
+ 
+                    let label_max_w = (bt_sec_w - btn_w - 2.0 * padding - margin - row_gap).max(20.0);
                     let label_max_chars = ((label_max_w / 6.0) as usize).max(5);
-
+ 
                     let is_unknown = dev.name.replace('-', ":").eq_ignore_ascii_case(&dev.mac);
                     let label = if is_unknown {
                         if bt_sec_w < 350.0 {
@@ -412,17 +455,20 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
                             }
                         }
                     };
-
+ 
                     let yt = sec.ay();
-                    sec.text(&label, 14.0, 0.0, 12.0, if dev.connected { ACCENT } else { TEXT_FG });
-                    sec.button(action_label, sec.ax(bt_sec_w - btn_w - 20.0), yt - 2.0, btn_w, 22.0,
+                    let btn_x = margin;
+                    let text_x = margin + btn_w + row_gap;
+                    let text_y_offset = (item_h - font_size) / 2.0;
+                    sec.button(action_label, sec.ax(btn_x), yt, btn_w, item_h,
                         if dev.connected { TOGGLE_OFF } else { TOGGLE_ON }, BTN_HOVER, WHITE,
                         if dev.connected {
                             AppAction::Radios(NetworkMessage::BtDisconnect(dev.mac.clone()))
                         } else {
                             AppAction::Radios(NetworkMessage::BtConnect(dev.mac.clone()))
                         });
-                    sec.content_y += 24.0;
+                    sec.text(&label, text_x, text_y_offset, font_size, if dev.connected { ACCENT } else { TEXT_FG });
+                    sec.content_y = yt + item_h + row_gap;
                 }
             }
         }
@@ -435,8 +481,12 @@ pub fn update(state: &mut NetworkState, msg: NetworkMessage) {
     match msg {
         NetworkMessage::Refreshed(new) => {
             let old_scroll = state.wifi_list_box.scroll_y();
+            let was_wifi_hovered = state.wifi_toggle.hovered();
+            let was_bt_hovered = state.bt_toggle.hovered();
             *state = new;
             state.wifi_list_box.set_scroll_y(old_scroll);
+            state.wifi_toggle.set_hovered(was_wifi_hovered);
+            state.bt_toggle.set_hovered(was_bt_hovered);
         }
         NetworkMessage::ToggleWifi => {
             state.wifi_enabled = !state.wifi_enabled;
@@ -470,6 +520,21 @@ mod tests {
     #[test]
     fn test_view_layout_grid() {
         let mut state = NetworkState::default();
+        state.loaded = true;
+        state.wifi_enabled = true;
+        let mut layout = clear_ui::layout::ColumnLayout::new(20.0);
+        let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, false, &mut layout, &mut clear_ui::context::UiContext::new());
+        assert!(!pc.rects.is_empty() || !pc.texts.is_empty() || !pc.buttons.is_empty());
+    }
+
+    #[test]
+    fn test_view_layout_connected() {
+        let mut state = NetworkState::default();
+        state.loaded = true;
+        state.wifi_enabled = true;
+        state.connected_ssid = "MyHomeWiFi".to_string();
+        state.signal_strength = 80;
+        state.ip_address = "192.168.1.50".to_string();
         let mut layout = clear_ui::layout::ColumnLayout::new(20.0);
         let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, false, &mut layout, &mut clear_ui::context::UiContext::new());
         assert!(!pc.rects.is_empty() || !pc.texts.is_empty() || !pc.buttons.is_empty());