git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commit26aee85e4e9edbecb4b5c5feeaedf63c706d3f9c
parent774784f34f
authorLucas Galante <[email protected]>
date2026-07-12 19:33
refactor(widget)!: Element is DELETED — the trait is WidgetHost (6bd flip)

The rename that ends the god-trait: after the census-driven shrink batches
(125 -> ~65 methods) and the base() guarantee, `Element` matched the measured
host blueprint and became `WidgetHost` — the single surface the machinery
(context routing, paint walk, render loop, app dyn broadcasts) sees.
`Adapted<W>` remains the one production implementor; concrete behavior lives
on the narrow Layout/Paint/Input traits. `ElementState` (the input enum) is
unrelated and keeps its name; cce-layout-interface's local `Element` document
enum is untouched (it aliased the trait as UiElement).

634 occurrences across 18 crates, word-boundary exact; the workspace compiled
on the first pass. CLAUDE.md updated.

Verified: 163 tests; settings audio render stream byte-identical to the
pre-flip baseline.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018u7qTwzX95dd5ysAkaSCLk

 CLAUDE.md                                |  23 ++--
 src/backend/window_runner.rs             |  18 +--
 src/context.rs                           |  44 +++----
 src/layout.rs                            |  56 ++++-----
 src/main.rs                              |   4 +-
 src/scene/arena.rs                       |  14 +--
 src/scene/painter.rs                     |  36 +++---
 src/scene/tree.rs                        |  36 +++---
 src/widget/container/breadcrumb.rs       |   2 +-
 src/widget/container/container_layout.rs |  32 ++---
 src/widget/container/menu.rs             |  22 ++--
 src/widget/container/paginator.rs        |  16 +--
 src/widget/container/parameters_bg.rs    |  18 +--
 src/widget/container/scroll_box.rs       |  18 +--
 src/widget/container/spreadsheet.rs      |  32 ++---
 src/widget/container/treelist.rs         |   4 +-
 src/widget/core.rs                       |  28 ++---
 src/widget/display/float3.rs             |  16 +--
 src/widget/display/graph.rs              |  20 ++--
 src/widget/display/label.rs              |  12 +-
 src/widget/display/node.rs               |  14 +--
 src/widget/display/panel.rs              |   4 +-
 src/widget/display/progress_bar.rs       |  26 ++---
 src/widget/display/separator.rs          |  18 +--
 src/widget/display/serialize.rs          |   6 +-
 src/widget/display/sidebar.rs            |   4 +-
 src/widget/display/splitter.rs           |   4 +-
 src/widget/display/status_bar.rs         |  20 ++--
 src/widget/display/status_dot.rs         |  10 +-
 src/widget/display/usage_bar.rs          |   8 +-
 src/widget/input/button.rs               |  16 +--
 src/widget/input/checkbox.rs             |  48 ++++----
 src/widget/input/dropdown.rs             |  20 ++--
 src/widget/input/slider.rs               |  54 ++++-----
 src/widget/input/spinbox.rs              |  16 +--
 src/widget/input/text_box.rs             |   8 +-
 src/widget/layout_helper.rs              |   8 +-
 src/widget/mod.rs                        |  28 +++--
 src/widget/model.rs                      | 194 +++++++++++++++----------------
 39 files changed, 482 insertions(+), 475 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index b8a4943..b87c45f 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -87,7 +87,7 @@ appended as a final unclipped batch drawn on top.
 ## The `scene/` core rebuild (read `docs/rfc-core-rebuild.md` before touching it)
 
 `src/scene/` is a **retained scene graph being grown additively** to replace three overlaid legacy
-subsystems (tripled tree ownership via raw `*mut dyn Element`; three uncoordinated render paths;
+subsystems (tripled tree ownership via raw widget pointers; three uncoordinated render paths;
 layout smeared across five mechanisms). The RFC (`docs/rfc-core-rebuild.md`) is the authoritative
 design and phase tracker — its inline "DONE" notes are the source of truth for what has landed.
 Modules:
@@ -99,20 +99,21 @@ Modules:
 - `layout.rs` — the hand-rolled measure→arrange solver (`Style`/`Size`/`Rect`/`LayoutBox`).
   Deliberately **not** taffy: a compact row/column + flex + align + gap/padding box model.
 - `paint.rs` / `painter.rs` — `DisplayList` + `PaintCtx` (clip/transform stack) and the single
-  paint walk. Each widget emits its own geometry via `Element::paint_self`; the walk owns recursion
-  and clipping (`Element::clips_children`), instead of every container re-deriving intersections.
-  `renders_own_subtree` is an escape hatch for legacy subtree painters.
+  paint walk. Each widget emits its own geometry via `WidgetHost::paint_self`; the walk owns
+  recursion and clipping (`WidgetHost::clips_children`), instead of every container re-deriving
+  intersections. `renders_own_subtree` is an escape hatch for legacy subtree painters.
 - `anim.rs` — `Animated<T>` (tween + spring + easing), the Phase 4 animation primitive replacing
   ad-hoc bool flips.
 
-### `Element` scene hooks (migration surface)
+### `WidgetHost` (formerly the `Element` god-trait)
 
-The legacy `Element` trait (`src/widget/mod.rs`, ~125 methods — the god-trait the RFC is
-dismantling) carries the opt-in hooks that move a widget onto the new core, all defaulting to the
-legacy path: `layout_style()` / `intrinsic_size()` (→ layout engine), `paint_self()` /
-`clips_children()` / `renders_own_subtree()` (→ single paint path), `children()`. Migrate a widget
-by implementing these; leave them defaulted to keep it on the legacy path. This is what lets a
-single container be moved and verified in a running app without disturbing the rest.
+`WidgetHost` (`src/widget/mod.rs`) is the single ~65-method host surface the machinery
+(context routing, paint walk, render loop, app dyn broadcasts) sees, produced by the RFC's 6bd
+shrink-then-rename of the old ~125-method `Element` god-trait. Its ONE production implementor
+is `Adapted<W>`; concrete widget behavior lives on the narrow `Layout`/`Paint`/`Input` traits
+(`src/widget/model.rs`). `base()` is guaranteed (`&Widget`, no Option). The direct-dispatch
+block (mouse/key/drag) and value block shrink further as apps adopt routed events and
+concrete slots — see the RFC's blueprint notes before adding anything to this trait.
 
 **Runtime verification matters here.** Several scene changes are "compiles + tests pass; runtime
 verification pending" per the RFC — the headless tests can't catch paint/event regressions. When
diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index 4dbd156..2d768b3 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -37,7 +37,7 @@ use glyphon::{
     FontSystem, Resolution, TextArea,
     TextBounds, Buffer, Attrs, Metrics,
 };
-use crate::widget::{Element, TextItem, MouseButton, ElementState, MouseScrollDelta, KeyEvent, Key, NamedKey, Position};
+use crate::widget::{WidgetHost, TextItem, MouseButton, ElementState, MouseScrollDelta, KeyEvent, Key, NamedKey, Position};
 use crate::wayland::detect_scale_factor;
 use crate::backend::WgpuAdapter;
 
@@ -986,13 +986,13 @@ pub fn push_plate_solid_border_vertices_legacy(
     push_plate_solid_border_vertices(x, y, ww, h, radii, t, sw, sh, color, clip_circle, out);
 }
 
-pub fn widget_vertices(w: &dyn crate::widget::Element, sw: f32, sh: f32, clip_circle: [f32; 3]) -> Vec<Vertex> {
+pub fn widget_vertices(w: &dyn crate::widget::WidgetHost, sw: f32, sh: f32, clip_circle: [f32; 3]) -> Vec<Vertex> {
     let mut verts = Vec::new();
     push_widget_vertices(w, sw, sh, clip_circle, &mut verts);
     verts
 }
 
-pub fn push_widget_vertices(w: &dyn crate::widget::Element, sw: f32, sh: f32, clip_circle: [f32; 3], out: &mut Vec<Vertex>) {
+pub fn push_widget_vertices(w: &dyn crate::widget::WidgetHost, sw: f32, sh: f32, clip_circle: [f32; 3], out: &mut Vec<Vertex>) {
     let (x, y, ww, h) = w.rect();
     let radii = w.corner_radii();
     if let Some(thickness) = w.plate_bevel() {
@@ -1106,7 +1106,7 @@ pub fn tessellate_display_list(
 }
 
 pub fn extra_quad_vertices(
-    w: &dyn crate::widget::Element,
+    w: &dyn crate::widget::WidgetHost,
     qx: f32, qy: f32, qw: f32, qh: f32,
     sw: f32, sh: f32,
     qc: [f32; 4],
@@ -1118,9 +1118,9 @@ pub fn extra_quad_vertices(
 }
 
 fn get_child_widget_for_quad<'a>(
-    w: &'a dyn crate::widget::Element,
+    w: &'a dyn crate::widget::WidgetHost,
     qx: f32, qy: f32, qw: f32, qh: f32,
-) -> &'a dyn crate::widget::Element {
+) -> &'a dyn crate::widget::WidgetHost {
     if let Some(pbg) = w.as_any().downcast_ref::<crate::widget::ParametersBg>() {
         for s_opt in &pbg.sliders {
             if let Some(s) = s_opt {
@@ -1191,7 +1191,7 @@ fn get_child_widget_for_quad<'a>(
 }
 
 pub fn push_extra_quad_vertices(
-    w: &dyn crate::widget::Element,
+    w: &dyn crate::widget::WidgetHost,
     qx: f32, qy: f32, qw: f32, qh: f32,
     sw: f32, sh: f32,
     qc: [f32; 4],
@@ -1245,7 +1245,7 @@ pub fn push_extra_quad_vertices(
 }
 
 pub fn extra_quad_vertices_clipped(
-    w: &dyn crate::widget::Element,
+    w: &dyn crate::widget::WidgetHost,
     qx: f32, qy: f32, qw: f32, qh: f32,
     sw: f32, sh: f32,
     qc: [f32; 4],
@@ -1258,7 +1258,7 @@ pub fn extra_quad_vertices_clipped(
 }
 
 pub fn push_extra_quad_vertices_clipped(
-    w: &dyn crate::widget::Element,
+    w: &dyn crate::widget::WidgetHost,
     qx: f32, qy: f32, qw: f32, qh: f32,
     sw: f32, sh: f32,
     qc: [f32; 4],
diff --git a/src/context.rs b/src/context.rs
index f05994f..d19a078 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -1,5 +1,5 @@
 use std::collections::HashMap;
-use crate::widget::{Element, WidgetId, Key, NamedKey, MouseButton, ElementState, Event};
+use crate::widget::{WidgetHost, WidgetId, Key, NamedKey, MouseButton, ElementState, Event};
 use crate::widget::core::hover_animation::HoverState;
 use crate::widget::core::context_menu::ContextMenuState;
 
@@ -104,15 +104,15 @@ impl UiContext {
         }
     }
 
-    pub fn get_widget(&self, id: WidgetId) -> Option<&(dyn Element + 'static)> {
+    pub fn get_widget(&self, id: WidgetId) -> Option<&(dyn WidgetHost + 'static)> {
         self.tree.get_ptr(id).map(|ptr| unsafe { &*ptr })
     }
 
-    pub fn get_widget_mut(&mut self, id: WidgetId) -> Option<&mut (dyn Element + 'static)> {
+    pub fn get_widget_mut(&mut self, id: WidgetId) -> Option<&mut (dyn WidgetHost + 'static)> {
         self.tree.get_ptr(id).map(|ptr| unsafe { &mut *ptr })
     }
 
-    pub fn propagate_event(&mut self, event: &Event, root: *mut (dyn Element + 'static)) -> bool {
+    pub fn propagate_event(&mut self, event: &Event, root: *mut (dyn WidgetHost + 'static)) -> bool {
         if let Event::MouseWheel { .. } = event {
             let now = std::time::Instant::now();
             let elapsed_ms = match self.last_scroll_time {
@@ -167,7 +167,7 @@ impl UiContext {
         self.propagate_event_impl(event, root)
     }
 
-    fn propagate_event_impl(&mut self, event: &Event, root: *mut (dyn Element + 'static)) -> bool {
+    fn propagate_event_impl(&mut self, event: &Event, root: *mut (dyn WidgetHost + 'static)) -> bool {
         if root.is_null() {
             return false;
         }
@@ -332,7 +332,7 @@ impl UiContext {
 
     pub fn clear_dirty(&mut self) {
         self.any_dirty = false;
-        let ptrs: Vec<*mut (dyn Element + 'static)> =
+        let ptrs: Vec<*mut (dyn WidgetHost + 'static)> =
             self.tree.iter_registered().map(|(_, ptr)| ptr).collect();
         for ptr in ptrs {
             unsafe {
@@ -344,7 +344,7 @@ impl UiContext {
 
     pub fn rebuild_spatial_grid(&mut self) {
         self.spatial_grid.clear();
-        let entries: Vec<(WidgetId, *mut (dyn Element + 'static))> =
+        let entries: Vec<(WidgetId, *mut (dyn WidgetHost + 'static))> =
             self.tree.iter_registered().collect();
         for (id, ptr) in entries {
             unsafe {
@@ -411,13 +411,13 @@ impl UiContext {
     }
 
     // --- Focus management (id-keyed; Phase 6bc) ---
-    pub fn set_focused(&mut self, w: &mut dyn Element) {
+    pub fn set_focused(&mut self, w: &mut dyn WidgetHost) {
         let id = w.base().id();
         // Refresh the registry with the pointer we were just handed, so focus on a
         // not-yet-registered widget keeps working (the legacy code stored this pointer
         // directly; the id must resolve for FocusOut/KeyInput dispatch to reach it).
         let new_ptr = unsafe {
-            std::mem::transmute::<*mut dyn Element, *mut (dyn Element + 'static)>(w as *mut dyn Element)
+            std::mem::transmute::<*mut dyn WidgetHost, *mut (dyn WidgetHost + 'static)>(w as *mut dyn WidgetHost)
         };
         self.tree.register(id, new_ptr);
         self.set_focused_id(id);
@@ -426,7 +426,7 @@ impl UiContext {
     /// Transitional pointer form (TreeList focuses its adapter via `EventCtx::host_ptr`). The
     /// pointer must be live at the call — it is only used to derive the id and refresh the
     /// registry, never stored.
-    pub fn set_focused_ptr(&mut self, new_ptr: *mut (dyn Element + 'static)) {
+    pub fn set_focused_ptr(&mut self, new_ptr: *mut (dyn WidgetHost + 'static)) {
         if new_ptr.is_null() {
             return;
         }
@@ -461,7 +461,7 @@ impl UiContext {
         }
     }
 
-    pub fn is_focused(&self, w: &dyn Element) -> bool {
+    pub fn is_focused(&self, w: &dyn WidgetHost) -> bool {
         self.is_focused_id(w.base().id())
     }
 
@@ -480,7 +480,7 @@ impl UiContext {
         }
     }
 
-    pub fn clear_if_matches(&mut self, w: &dyn Element) {
+    pub fn clear_if_matches(&mut self, w: &dyn WidgetHost) {
         if self.focused_widget == Some(w.base().id()) {
             self.focused_widget = None;
         }
@@ -556,7 +556,7 @@ impl UiContext {
     }
 
     // --- Registry (backed by the generational WidgetTree; see scene/tree.rs) ---
-    pub fn register_widget(&mut self, id: WidgetId, ptr: *mut (dyn Element + 'static)) {
+    pub fn register_widget(&mut self, id: WidgetId, ptr: *mut (dyn WidgetHost + 'static)) {
         self.tree.register(id, ptr);
         unsafe {
             if !ptr.is_null() && (*ptr).wants_tick() {
@@ -588,15 +588,15 @@ impl UiContext {
 
     /// Register an open popover. Takes `&mut` so the registry can be refreshed with the
     /// pointer we are handed (the occlusion walks resolve the stored id through the tree).
-    pub fn register_popover(&mut self, w: &mut (dyn Element + 'static)) {
+    pub fn register_popover(&mut self, w: &mut (dyn WidgetHost + 'static)) {
         let id = w.base().id();
-        self.tree.register(id, w as *mut (dyn Element + 'static));
+        self.tree.register(id, w as *mut (dyn WidgetHost + 'static));
         if !self.active_popovers.contains(&id) {
             self.active_popovers.push(id);
         }
     }
 
-    pub fn register_popover_ptr(&mut self, ptr: *mut (dyn Element + 'static)) {
+    pub fn register_popover_ptr(&mut self, ptr: *mut (dyn WidgetHost + 'static)) {
         if ptr.is_null() {
             return;
         }
@@ -692,7 +692,7 @@ impl UiContext {
         crate::widget::context_menu::is_visible()
     }
 
-    pub fn show_context_menu(&mut self, x: f32, y: f32, options: Vec<String>, header_count: usize, target: *mut (dyn Element + 'static)) {
+    pub fn show_context_menu(&mut self, x: f32, y: f32, options: Vec<String>, header_count: usize, target: *mut (dyn WidgetHost + 'static)) {
         if target.is_null() {
             return;
         }
@@ -701,7 +701,7 @@ impl UiContext {
         crate::widget::context_menu::show(x, y, options, header_count, id);
     }
 
-    pub fn handle_right_click(&mut self, target: *mut (dyn Element + 'static), px: f32, py: f32) {
+    pub fn handle_right_click(&mut self, target: *mut (dyn WidgetHost + 'static), px: f32, py: f32) {
         if target.is_null() {
             return;
         }
@@ -863,7 +863,7 @@ impl UiContext {
         false
     }
 
-    fn find_hovered_scrollable(&self, root: *mut (dyn Element + 'static), cx: f32, cy: f32) -> Option<*mut (dyn Element + 'static)> {
+    fn find_hovered_scrollable(&self, root: *mut (dyn WidgetHost + 'static), cx: f32, cy: f32) -> Option<*mut (dyn WidgetHost + 'static)> {
         unsafe {
             if root.is_null() {
                 return None;
@@ -890,13 +890,13 @@ impl UiContext {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::widget::{Element, Widget};
+    use crate::widget::{WidgetHost, Widget};
 
-    /// A plain drag-blocking widget (the `Element` default) at a fixed rect.
+    /// A plain drag-blocking widget (the `WidgetHost` default) at a fixed rect.
     struct Block {
         base: Widget,
     }
-    impl Element for Block {
+    impl WidgetHost for Block {
         crate::impl_widget_base!(Block);
         fn color(&self) -> [f32; 4] {
             [0.0, 0.0, 0.0, 1.0]
diff --git a/src/layout.rs b/src/layout.rs
index 7a8d500..931ec54 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -1,4 +1,4 @@
-use crate::widget::Element;
+use crate::widget::WidgetHost;
 use crate::context::UiContext;
 use std::sync::RwLock;
 use std::collections::HashMap;
@@ -3141,7 +3141,7 @@ impl RenderTarget for PopoverCollector {
 }
 
 
-pub fn render_widget<T: Element + 'static>(pc: &mut dyn RenderTarget, w: &mut T, x: f32, y: f32, ww: f32, wh: f32, ctx: &mut UiContext) {
+pub fn render_widget<T: WidgetHost + 'static>(pc: &mut dyn RenderTarget, w: &mut T, x: f32, y: f32, ww: f32, wh: f32, ctx: &mut UiContext) {
     let id = Some(w.base().id());
     if let Some(w_id) = id {
         ctx.register_widget(w_id, w.as_ptr_mut());
@@ -3373,7 +3373,7 @@ impl Column {
         pc.text(text, x, y, font_size, color);
     }
 
-    pub fn widget<T: Element + 'static>(&mut self, pc: &mut dyn RenderTarget, w: &mut T, x_off: f32, ww: f32, mut wh: f32, ctx: &mut UiContext) {
+    pub fn widget<T: WidgetHost + 'static>(&mut self, pc: &mut dyn RenderTarget, w: &mut T, x_off: f32, ww: f32, mut wh: f32, ctx: &mut UiContext) {
         if let Some(pref) = w.preferred_height() {
             wh = pref;
         }
@@ -3424,7 +3424,7 @@ impl<'a> Row<'a> {
         self.cursor_x += width + self.spacing;
     }
 
-    pub fn widget<T: Element + 'static>(&mut self, w: &mut T, ww: f32, mut wh: f32, ctx: &mut UiContext) {
+    pub fn widget<T: WidgetHost + 'static>(&mut self, w: &mut T, ww: f32, mut wh: f32, ctx: &mut UiContext) {
         if let Some(pref) = w.preferred_height() {
             wh = pref;
         }
@@ -3553,7 +3553,7 @@ impl Section {
         pc.text(text, self.ax(x_off), self.ay() + y_off, font_size, color);
     }
 
-    pub fn widget<T: Element + 'static>(&mut self, pc: &mut dyn RenderTarget, w: &mut T, _x_off: f32, _ww: f32, mut wh: f32, ctx: &mut UiContext) {
+    pub fn widget<T: WidgetHost + 'static>(&mut self, pc: &mut dyn RenderTarget, w: &mut T, _x_off: f32, _ww: f32, mut wh: f32, ctx: &mut UiContext) {
         if let Some(pref) = w.preferred_height() {
             wh = pref;
         }
@@ -3605,7 +3605,7 @@ impl Section {
         }
     }
 
-    pub fn widget_full<T: Element + 'static>(&mut self, pc: &mut dyn RenderTarget, w: &mut T, wh: f32, ctx: &mut UiContext) {
+    pub fn widget_full<T: WidgetHost + 'static>(&mut self, pc: &mut dyn RenderTarget, w: &mut T, wh: f32, ctx: &mut UiContext) {
         let x_off = 12.0;
         let ww = self.cw - 2.0 * (self.padding() + x_off);
         self.widget(pc, w, x_off, ww, wh, ctx);
@@ -3744,7 +3744,7 @@ pub struct SectionVStack<'a> {
 }
 
 impl<'a> SectionVStack<'a> {
-    pub fn add_widget<T: Element + 'static>(&mut self, w: &mut T, ww: f32, wh: f32, ctx: &mut UiContext) {
+    pub fn add_widget<T: WidgetHost + 'static>(&mut self, w: &mut T, ww: f32, wh: f32, ctx: &mut UiContext) {
         self.section.widget(self.pc, w, Section::DEFAULT_MARGIN_X, ww, wh, ctx);
         self.section.spacing(self.spacing);
     }
@@ -3967,8 +3967,8 @@ pub trait LayoutStrategy: std::fmt::Debug {
     fn get_column_width(&self) -> Option<f32> { None }
     fn get_gap(&self) -> f32 { 20.0 }
 
-    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn crate::widget::Element + 'static)], ctx: &mut crate::context::UiContext) -> f32;
-    fn measure(&self, constraints: crate::widget::LayoutConstraints, children: &[*mut (dyn crate::widget::Element + 'static)], ctx: &crate::context::UiContext) -> crate::widget::Size;
+    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn crate::widget::WidgetHost + 'static)], ctx: &mut crate::context::UiContext) -> f32;
+    fn measure(&self, constraints: crate::widget::LayoutConstraints, children: &[*mut (dyn crate::widget::WidgetHost + 'static)], ctx: &crate::context::UiContext) -> crate::widget::Size;
     fn box_clone(&self) -> Box<dyn LayoutStrategy>;
 }
 
@@ -4042,7 +4042,7 @@ impl LayoutStrategy for FlexLayout {
         self.spacing
     }
 
-    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn crate::widget::Element + 'static)], _ctx: &mut crate::context::UiContext) -> f32 {
+    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn crate::widget::WidgetHost + 'static)], _ctx: &mut crate::context::UiContext) -> f32 {
         let mut cur_x = x;
         let mut cur_y = y;
         match self.direction {
@@ -4074,7 +4074,7 @@ impl LayoutStrategy for FlexLayout {
         }
     }
 
-    fn measure(&self, constraints: crate::widget::LayoutConstraints, children: &[*mut (dyn crate::widget::Element + 'static)], ctx: &crate::context::UiContext) -> crate::widget::Size {
+    fn measure(&self, constraints: crate::widget::LayoutConstraints, children: &[*mut (dyn crate::widget::WidgetHost + 'static)], ctx: &crate::context::UiContext) -> crate::widget::Size {
         match self.direction {
             FlexDirection::Row => {
                 let mut total_w = 0.0f32;
@@ -4164,7 +4164,7 @@ impl LayoutStrategy for ColumnLayout {
         self.gap
     }
 
-    fn layout(&self, x: f32, y: f32, w: f32, _h: f32, children: &[*mut (dyn crate::widget::Element + 'static)], _ctx: &mut crate::context::UiContext) -> f32 {
+    fn layout(&self, x: f32, y: f32, w: f32, _h: f32, children: &[*mut (dyn crate::widget::WidgetHost + 'static)], _ctx: &mut crate::context::UiContext) -> f32 {
         let mut cur_y = y;
         for &child_ptr in children {
             unsafe {
@@ -4178,7 +4178,7 @@ impl LayoutStrategy for ColumnLayout {
         (cur_y - y).max(0.0)
     }
 
-    fn measure(&self, constraints: crate::widget::LayoutConstraints, children: &[*mut (dyn crate::widget::Element + 'static)], ctx: &crate::context::UiContext) -> crate::widget::Size {
+    fn measure(&self, constraints: crate::widget::LayoutConstraints, children: &[*mut (dyn crate::widget::WidgetHost + 'static)], ctx: &crate::context::UiContext) -> crate::widget::Size {
         let mut total_h = 0.0f32;
         let mut max_w = 0.0f32;
         for (i, &child_ptr) in children.iter().enumerate() {
@@ -4298,7 +4298,7 @@ impl LayoutStrategy for AdaptiveGrid {
         crate::layout::grid_gap()
     }
 
-    fn layout(&self, x: f32, y: f32, w: f32, _h: f32, children: &[*mut (dyn crate::widget::Element + 'static)], _ctx: &mut crate::context::UiContext) -> f32 {
+    fn layout(&self, x: f32, y: f32, w: f32, _h: f32, children: &[*mut (dyn crate::widget::WidgetHost + 'static)], _ctx: &mut crate::context::UiContext) -> f32 {
         let usable_w = w.max(1.0);
         let min_col_width = crate::layout::grid_min_col_width();
         let gap = crate::layout::grid_gap();
@@ -4341,7 +4341,7 @@ impl LayoutStrategy for AdaptiveGrid {
         (max_h - y).max(0.0)
     }
 
-    fn measure(&self, constraints: crate::widget::LayoutConstraints, children: &[*mut (dyn crate::widget::Element + 'static)], ctx: &crate::context::UiContext) -> crate::widget::Size {
+    fn measure(&self, constraints: crate::widget::LayoutConstraints, children: &[*mut (dyn crate::widget::WidgetHost + 'static)], ctx: &crate::context::UiContext) -> crate::widget::Size {
         let usable_w = constraints.max_width.max(1.0);
         let min_col_width = crate::layout::grid_min_col_width();
         let gap = crate::layout::grid_gap();
@@ -4429,7 +4429,7 @@ impl LayoutStrategy for RadialLayout {
         }
     }
 
-    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn crate::widget::Element + 'static)], _ctx: &mut crate::context::UiContext) -> f32 {
+    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn crate::widget::WidgetHost + 'static)], _ctx: &mut crate::context::UiContext) -> f32 {
         let cx = x + w / 2.0;
         let cy = y + h / 2.0;
         let aspect = if self.aspect_ratio > 0.0 {
@@ -4452,7 +4452,7 @@ impl LayoutStrategy for RadialLayout {
         h
     }
 
-    fn measure(&self, constraints: crate::widget::LayoutConstraints, children: &[*mut (dyn crate::widget::Element + 'static)], ctx: &crate::context::UiContext) -> crate::widget::Size {
+    fn measure(&self, constraints: crate::widget::LayoutConstraints, children: &[*mut (dyn crate::widget::WidgetHost + 'static)], ctx: &crate::context::UiContext) -> crate::widget::Size {
         let cx = constraints.max_width / 2.0;
         let cy = constraints.max_height / 2.0;
         let aspect = if self.aspect_ratio > 0.0 {
@@ -4692,7 +4692,7 @@ impl<'a, P: RenderTarget> SectionContext<'a, P> {
         }
     }
 
-    pub fn widget<T: Element + 'static>(&mut self, w: &mut T, _x_off: f32, _ww: f32, mut wh: f32, ctx: &mut UiContext) {
+    pub fn widget<T: WidgetHost + 'static>(&mut self, w: &mut T, _x_off: f32, _ww: f32, mut wh: f32, ctx: &mut UiContext) {
         if let Some(pref) = w.preferred_height() {
             wh = pref;
         }
@@ -4753,7 +4753,7 @@ impl<'a, P: RenderTarget> SectionContext<'a, P> {
         }
     }
 
-    pub fn widget_full<T: Element + 'static>(&mut self, w: &mut T, wh: f32, ctx: &mut UiContext) {
+    pub fn widget_full<T: WidgetHost + 'static>(&mut self, w: &mut T, wh: f32, ctx: &mut UiContext) {
         let x_off = 12.0;
         let ww = self.cw - 2.0 * (self.padding() + x_off); // cw - 40.0
         self.widget(w, x_off, ww, wh, ctx);
@@ -4928,7 +4928,7 @@ pub struct VStack<'b, 'a, P> {
 }
 
 impl<'b, 'a, P: RenderTarget> VStack<'b, 'a, P> {
-    pub fn add_widget<T: Element + 'static>(&mut self, w: &mut T, _ww: f32, wh: f32, ctx: &mut UiContext) {
+    pub fn add_widget<T: WidgetHost + 'static>(&mut self, w: &mut T, _ww: f32, wh: f32, ctx: &mut UiContext) {
         let pad = self.context.padding();
         let margin_x = 2.0 * pad + 12.0;
         let x = self.context.left + margin_x;
@@ -5103,7 +5103,7 @@ mod tests {
         h: f32,
     }
 
-    impl Element for MockWidget {
+    impl WidgetHost for MockWidget {
         crate::impl_widget_base!(MockWidget);
         fn rect(&self) -> (f32, f32, f32, f32) {
             (self.x, self.y, self.w, self.h)
@@ -5123,7 +5123,7 @@ mod tests {
         base: crate::widget::Widget,
     }
 
-    impl Element for MockWidgetWithLabel {
+    impl WidgetHost for MockWidgetWithLabel {
         crate::impl_widget_base!(MockWidgetWithLabel);
         fn rect(&self) -> (f32, f32, f32, f32) {
             let offset = crate::widget::label_offset(self);
@@ -5462,9 +5462,9 @@ mod tests {
         let mut w3 = MockWidget { base: crate::widget::Widget::new(), x: 0.0, y: 0.0, w: 80.0, h: 40.0 };
         
         let children = vec![
-            &mut w1 as *mut MockWidget as *mut (dyn Element + 'static),
-            &mut w2 as *mut MockWidget as *mut (dyn Element + 'static),
-            &mut w3 as *mut MockWidget as *mut (dyn Element + 'static),
+            &mut w1 as *mut MockWidget as *mut (dyn WidgetHost + 'static),
+            &mut w2 as *mut MockWidget as *mut (dyn WidgetHost + 'static),
+            &mut w3 as *mut MockWidget as *mut (dyn WidgetHost + 'static),
         ];
 
         let _ = layout.layout(10.0, 20.0, 250.0, 500.0, &children, &mut dummy);
@@ -5494,9 +5494,9 @@ mod tests {
         let mut w3 = MockWidget { base: crate::widget::Widget::new(), x: 0.0, y: 0.0, w: 80.0, h: 40.0 };
         
         let children = vec![
-            &mut w1 as *mut MockWidget as *mut (dyn Element + 'static),
-            &mut w2 as *mut MockWidget as *mut (dyn Element + 'static),
-            &mut w3 as *mut MockWidget as *mut (dyn Element + 'static),
+            &mut w1 as *mut MockWidget as *mut (dyn WidgetHost + 'static),
+            &mut w2 as *mut MockWidget as *mut (dyn WidgetHost + 'static),
+            &mut w3 as *mut MockWidget as *mut (dyn WidgetHost + 'static),
         ];
 
         let _ = layout.layout(10.0, 20.0, 250.0, 300.0, &children, &mut dummy);
diff --git a/src/main.rs b/src/main.rs
index 84bd5e4..b9a5691 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -26,7 +26,7 @@ use cce_ui::scene::layout::{
 };
 use cce_ui::scene::paint::{DisplayList, PaintCtx};
 use cce_ui::widget::{
-    Adapted, Button, Dropdown, Element, ElementState, Event, KeyEvent, MouseButton,
+    Adapted, Button, Dropdown, WidgetHost, ElementState, Event, KeyEvent, MouseButton,
     MouseScrollDelta, Slider, TextBox, Toggle,
 };
 use wayland_client::QueueHandle;
@@ -64,7 +64,7 @@ struct DemoApp {
 
 impl DemoApp {
     /// The widget roots, in paint order (events route over the same list).
-    fn roots(&mut self) -> [*mut (dyn Element + 'static); 5] {
+    fn roots(&mut self) -> [*mut (dyn WidgetHost + 'static); 5] {
         [
             self.button.as_ptr_mut(),
             self.toggle.as_ptr_mut(),
diff --git a/src/scene/arena.rs b/src/scene/arena.rs
index c44fa40..76eef38 100644
--- a/src/scene/arena.rs
+++ b/src/scene/arena.rs
@@ -2,8 +2,8 @@
 //!
 //! This is Phase 1 of the core rebuild (see `docs/rfc-core-rebuild.md`). It replaces the old
 //! model where the widget tree was smeared across three parallel stores kept in sync by hand
-//! (`Backplate.children: Vec<*mut dyn Element>`, `UiContext.layout_tree`, and
-//! `UiContext.widget_registry`) and traversed through raw `*mut dyn Element` pointers that
+//! (`Backplate.children: Vec<*mut dyn WidgetHost>`, `UiContext.layout_tree`, and
+//! `UiContext.widget_registry`) and traversed through raw `*mut dyn WidgetHost` pointers that
 //! `Drop` did not fully clear.
 //!
 //! Here there is exactly **one** store. Every node lives in the [`Arena`], addressed by a
@@ -562,12 +562,12 @@ mod tests {
     }
 
     // Validation against a real trait object: the arena must be able to *own* and tree actual
-    // `dyn Element` widgets (the payload type Phase 3 will use), not just Copy scalars.
+    // `dyn WidgetHost` widgets (the payload type Phase 3 will use), not just Copy scalars.
     #[test]
     fn holds_and_trees_real_dyn_element_payloads() {
-        use crate::widget::Element;
+        use crate::widget::WidgetHost;
 
-        // A minimal real `Element` — `color` is the trait's only required method, everything
+        // A minimal real `WidgetHost` — `color` is the trait's only required method, everything
         // else is defaulted, so this exercises the actual trait object without dragging in a
         // heavyweight widget constructor.
         struct Marker {
@@ -575,7 +575,7 @@ mod tests {
             tint: [f32; 4],
             painted: std::cell::Cell<bool>,
         }
-        impl Element for Marker {
+        impl WidgetHost for Marker {
             crate::impl_widget_base!(Marker);
             fn color(&self) -> [f32; 4] {
                 self.painted.set(true);
@@ -583,7 +583,7 @@ mod tests {
             }
         }
 
-        let mut arena: Arena<Box<dyn Element>> = Arena::new();
+        let mut arena: Arena<Box<dyn WidgetHost>> = Arena::new();
         let root = arena.insert(Box::new(Marker { base: crate::widget::Widget::new(), tint: [1.0, 0.0, 0.0, 1.0], painted: false.into() }));
         let child = arena.insert(Box::new(Marker { base: crate::widget::Widget::new(), tint: [0.0, 1.0, 0.0, 1.0], painted: false.into() }));
         arena.append_child(root, child);
diff --git a/src/scene/painter.rs b/src/scene/painter.rs
index 34f3415..d399954 100644
--- a/src/scene/painter.rs
+++ b/src/scene/painter.rs
@@ -3,8 +3,8 @@
 //! One traversal of the widget tree that emits every widget's own primitives into a single
 //! [`DisplayList`], in draw order, through a [`PaintCtx`]. Recursion and clipping live *here*
 //! (not smeared across each container's `all_*` methods): a widget contributes its own geometry
-//! via [`Element::paint_self`], then the walk descends into its children — pushing the widget's
-//! rect as a clip first when [`Element::clips_children`] is set, so the clip stack composes
+//! via [`WidgetHost::paint_self`], then the walk descends into its children — pushing the widget's
+//! rect as a clip first when [`WidgetHost::clips_children`] is set, so the clip stack composes
 //! automatically instead of every container re-deriving intersections by hand.
 //!
 //! This replaces, once wired into the backend, the three uncoordinated render paths (top-level
@@ -14,15 +14,15 @@
 
 use crate::scene::layout::Rect;
 use crate::scene::paint::{DisplayList, PaintCtx, Prim};
-use crate::widget::{Element, TextLabel, UiContext};
+use crate::widget::{WidgetHost, TextLabel, UiContext};
 
-type ElemPtr = *mut (dyn Element + 'static);
+type ElemPtr = *mut (dyn WidgetHost + 'static);
 
 /// Walk the widget subtree rooted at `root` and produce its ordered, clipped [`DisplayList`].
 ///
 /// # Safety
-/// `root` and every widget reachable through `Element::children` must be live — the same
-/// invariant the rest of the toolkit relies on for its `*mut dyn Element` tree.
+/// `root` and every widget reachable through `WidgetHost::children` must be live — the same
+/// invariant the rest of the toolkit relies on for its `*mut dyn WidgetHost` tree.
 pub fn paint_tree(ui: &UiContext, root: ElemPtr) -> DisplayList {
     let mut pc = PaintCtx::new();
     paint_root_into(ui, root, &mut pc);
@@ -43,13 +43,13 @@ pub fn paint_root_into(ui: &UiContext, root: ElemPtr, pc: &mut PaintCtx) {
 /// bounds). For hosts that build their frame as a [`PaintCtx`] and already emit a widget's
 /// geometry another way, but want its text without re-deriving it through the legacy
 /// `text_labels*` getters (the four hand-aggregate clients). The walk only reads through the
-/// widget, so a shared `&dyn Element` is enough.
-pub fn append_widget_text(ui: &UiContext, root: &dyn Element, pc: &mut PaintCtx) {
+/// widget, so a shared `&dyn WidgetHost` is enough.
+pub fn append_widget_text(ui: &UiContext, root: &dyn WidgetHost, pc: &mut PaintCtx) {
     // SAFETY: the walk only reads through `root` (paint_self/children/visible are all `&self`),
     // and widgets are concrete `'static` types — the invariant the toolkit's whole
-    // `*mut dyn Element` tree already relies on. Erase the borrowed trait-object lifetime bound
+    // `*mut dyn WidgetHost` tree already relies on. Erase the borrowed trait-object lifetime bound
     // to the `'static` `ElemPtr` the walk takes.
-    let ptr: ElemPtr = unsafe { std::mem::transmute::<*const dyn Element, ElemPtr>(root as *const dyn Element) };
+    let ptr: ElemPtr = unsafe { std::mem::transmute::<*const dyn WidgetHost, ElemPtr>(root as *const dyn WidgetHost) };
     let mut scratch = PaintCtx::new();
     paint_node(ui, ptr, &mut scratch);
     for item in scratch.finish().items {
@@ -65,7 +65,7 @@ pub fn append_widget_text(ui: &UiContext, root: &dyn Element, pc: &mut PaintCtx)
     }
 }
 
-/// The `Element` default `paint_self`'s LEAF branch as a reusable body: leaf geometry
+/// The `WidgetHost` default `paint_self`'s LEAF branch as a reusable body: leaf geometry
 /// (rounded quads, plain quads, arcs, circles) followed by the widget's fonted labels.
 /// Legacy leaf widgets' `paint_self` overrides call this with their own labels — the
 /// labels are PASSED IN rather than fetched through the per-widget text getters, so this
@@ -73,7 +73,7 @@ pub fn append_widget_text(ui: &UiContext, root: &dyn Element, pc: &mut PaintCtx)
 /// app-local legacy widgets (display-manager's status/session widgets, cloud's fuzzel)
 /// can use it too.
 pub fn paint_legacy_leaf(
-    w: &dyn Element,
+    w: &dyn WidgetHost,
     ui: &UiContext,
     pc: &mut PaintCtx,
     labels: Vec<(TextLabel, Option<String>, Option<[f32; 4]>)>,
@@ -98,14 +98,14 @@ pub fn paint_legacy_leaf(
 /// The scroll-ancestor text clamp the deleted default fonted getter applied. Always `None`
 /// since Phase 6av: ScrollBox (the last scroll ancestor type) was demoted to a plain
 /// embedded struct — it never appeared as a tree parent, so the walk never matched.
-pub fn scroll_ancestor_text_bounds(_w: &dyn Element, _ui: &UiContext) -> Option<[f32; 4]> {
+pub fn scroll_ancestor_text_bounds(_w: &dyn WidgetHost, _ui: &UiContext) -> Option<[f32; 4]> {
     None
 }
 
-/// The deleted `Element::text_labels` default's base-label synthesis: the control label
+/// The deleted `WidgetHost::text_labels` default's base-label synthesis: the control label
 /// stored on the widget base, positioned by the configured control-label layout. For
 /// legacy widgets whose only text was that label (List's columns=None frame).
-pub fn base_control_label(w: &dyn Element) -> Vec<TextLabel> {
+pub fn base_control_label(w: &dyn WidgetHost) -> Vec<TextLabel> {
     {
         let b = w.base();
         if let Some(ref label) = b.label {
@@ -128,7 +128,7 @@ pub fn base_control_label(w: &dyn Element) -> Vec<TextLabel> {
 /// default fonted getter produced: the widget's control font on every label plus the
 /// scroll-ancestor clamp.
 pub fn fonted_leaf_labels(
-    w: &dyn Element,
+    w: &dyn WidgetHost,
     ui: &UiContext,
     labels: Vec<TextLabel>,
 ) -> Vec<(TextLabel, Option<String>, Option<[f32; 4]>)> {
@@ -191,7 +191,7 @@ mod tests {
             Box::new(P { base: Widget::new(), tag, clips: false, vis: true })
         }
     }
-    impl Element for P {
+    impl WidgetHost for P {
         crate::impl_widget_base!(P);
         fn color(&self) -> [f32; 4] {
             [self.tag, 0.0, 0.0, 1.0]
@@ -333,7 +333,7 @@ mod tests {
         struct Rounded {
             base: Widget,
         }
-        impl Element for Rounded {
+        impl WidgetHost for Rounded {
             crate::impl_widget_base!(Rounded);
             fn color(&self) -> [f32; 4] {
                 [0.2, 0.4, 0.6, 1.0]
diff --git a/src/scene/tree.rs b/src/scene/tree.rs
index 070b142..ae1d538 100644
--- a/src/scene/tree.rs
+++ b/src/scene/tree.rs
@@ -2,7 +2,7 @@
 //!
 //! Today `UiContext` keeps the widget tree in two parallel `HashMap`s that must be maintained in
 //! lockstep by hand:
-//!   * `widget_registry: HashMap<WidgetId, *mut dyn Element>` — id → live pointer, and
+//!   * `widget_registry: HashMap<WidgetId, *mut dyn WidgetHost>` — id → live pointer, and
 //!   * `layout_tree: { parents: HashMap<WidgetId, WidgetId>, children: HashMap<WidgetId, Vec<WidgetId>> }`.
 //!
 //! This type folds both into a single generational [`Arena`], keyed through a `WidgetId → NodeId`
@@ -13,7 +13,7 @@
 //!
 //! ## One deliberate semantic change vs. the legacy maps
 //!
-//! The legacy maps are sometimes left **asymmetric**: `Element::set_parent(Some(p))` writes
+//! The legacy maps are sometimes left **asymmetric**: `WidgetHost::set_parent(Some(p))` writes
 //! `parents[child] = p` but does *not* add `child` to `children[p]`; `plate`/`parameters_bg`
 //! detach by doing `parents.remove(child)` while leaving `child` in `children[p]`. The arena keeps
 //! parent and child links **symmetric** by construction, so here `set_parent`/`detach` update both
@@ -27,23 +27,23 @@
 use std::collections::HashMap;
 
 use crate::scene::arena::{Arena, NodeId};
-use crate::widget::{Element, WidgetId};
+use crate::widget::{WidgetHost, WidgetId};
 
 /// One arena node's payload: the widget's stable id plus its live pointer. The pointer is `None`
 /// for a node that has been *linked* into the tree (as a parent/child) but not yet *registered*
 /// with a real widget — mirroring the legacy maps, where a `layout_tree` link can precede the
-/// `widget_registry` entry. (`*mut dyn Element` is a fat pointer, so `Option` is the natural
+/// `widget_registry` entry. (`*mut dyn WidgetHost` is a fat pointer, so `Option` is the natural
 /// "absent" representation — there is no thin null to use as a sentinel.)
 #[derive(Clone, Copy)]
 struct Entry {
     id: WidgetId,
-    ptr: Option<*mut (dyn Element + 'static)>,
+    ptr: Option<*mut (dyn WidgetHost + 'static)>,
 }
 
 /// Resolve an entry's pointer to a usable, non-null pointer (skipping link-only and null-data
 /// pointers exactly as the legacy `filter_map` over the registry did).
 #[inline]
-fn live_ptr(entry: &Entry) -> Option<*mut (dyn Element + 'static)> {
+fn live_ptr(entry: &Entry) -> Option<*mut (dyn WidgetHost + 'static)> {
     match entry.ptr {
         Some(p) if !p.is_null() => Some(p),
         _ => None,
@@ -93,7 +93,7 @@ impl WidgetTree {
     /// Register (or overwrite) the live pointer for `id`. Mirrors `register_widget`'s
     /// insert-overwrite semantics. Registering a `null` pointer is allowed (the node exists but
     /// resolves to `None`), matching the legacy behavior where a link can precede registration.
-    pub fn register(&mut self, id: WidgetId, ptr: *mut (dyn Element + 'static)) {
+    pub fn register(&mut self, id: WidgetId, ptr: *mut (dyn WidgetHost + 'static)) {
         let node = self.ensure_node(id);
         // `ensure_node` guarantees the node exists.
         self.arena.value_mut(node).unwrap().ptr = Some(ptr);
@@ -113,7 +113,7 @@ impl WidgetTree {
 
     /// Set or clear `child`'s parent. `Some(p)` links symmetrically (as [`link`](WidgetTree::link));
     /// `None` detaches `child` from its current parent. Replaces the legacy asymmetric
-    /// `Element::set_parent`.
+    /// `WidgetHost::set_parent`.
     pub fn set_parent(&mut self, child: WidgetId, parent: Option<WidgetId>) {
         match parent {
             Some(p) => self.link(p, child),
@@ -172,7 +172,7 @@ impl WidgetTree {
     }
 
     /// The live pointer for `id`, or `None` if unknown, link-only (null), or stale.
-    pub fn get_ptr(&self, id: WidgetId) -> Option<*mut (dyn Element + 'static)> {
+    pub fn get_ptr(&self, id: WidgetId) -> Option<*mut (dyn WidgetHost + 'static)> {
         let node = *self.by_id.get(&id)?;
         live_ptr(self.arena.value(node)?)
     }
@@ -185,7 +185,7 @@ impl WidgetTree {
     }
 
     /// `id`'s parent pointer, if the parent is registered (non-null).
-    pub fn parent_ptr(&self, id: WidgetId) -> Option<*mut (dyn Element + 'static)> {
+    pub fn parent_ptr(&self, id: WidgetId) -> Option<*mut (dyn WidgetHost + 'static)> {
         self.parent_id(id).and_then(|p| self.get_ptr(p))
     }
 
@@ -196,8 +196,8 @@ impl WidgetTree {
     }
 
     /// `id`'s child pointers in order, skipping any child that is link-only (null pointer) —
-    /// exactly matching the legacy `Element::children` `filter_map` over the registry.
-    pub fn children_ptrs(&self, id: WidgetId) -> Vec<*mut (dyn Element + 'static)> {
+    /// exactly matching the legacy `WidgetHost::children` `filter_map` over the registry.
+    pub fn children_ptrs(&self, id: WidgetId) -> Vec<*mut (dyn WidgetHost + 'static)> {
         let Some(&node) = self.by_id.get(&id) else { return Vec::new() };
         self.arena
             .children(node)
@@ -208,7 +208,7 @@ impl WidgetTree {
 
     /// Iterate every registered `(id, ptr)` with a non-null pointer, for the passes that sweep the
     /// whole registry (`clear_dirty`, `rebuild_spatial_grid`, coverage tests).
-    pub fn iter_registered(&self) -> impl Iterator<Item = (WidgetId, *mut (dyn Element + 'static))> + '_ {
+    pub fn iter_registered(&self) -> impl Iterator<Item = (WidgetId, *mut (dyn WidgetHost + 'static))> + '_ {
         self.by_id.values().filter_map(move |&node| {
             let entry = self.arena.value(node)?;
             live_ptr(entry).map(|p| (entry.id, p))
@@ -220,7 +220,7 @@ impl WidgetTree {
 mod tests {
     use super::*;
 
-    // A minimal real `Element` so tests exercise genuine `*mut dyn Element` payloads. The boxes
+    // A minimal real `WidgetHost` so tests exercise genuine `*mut dyn WidgetHost` payloads. The boxes
     // are kept alive in a local `Vec` for the duration of each test; we hand the tree raw
     // pointers into them, mirroring how widgets (owned by the app) are referenced by the tree.
     struct Marker {
@@ -228,7 +228,7 @@ mod tests {
         #[allow(dead_code)]
         tag: u32,
     }
-    impl Element for Marker {
+    impl WidgetHost for Marker {
         crate::impl_widget_base!(Marker);
         fn color(&self) -> [f32; 4] {
             [0.0, 0.0, 0.0, 0.0]
@@ -243,10 +243,10 @@ mod tests {
         fn new() -> Self {
             Widgets { boxes: Vec::new() }
         }
-        /// Create a widget, returning `(WidgetId, *mut dyn Element)`.
-        fn make(&mut self, tag: u32) -> (WidgetId, *mut (dyn Element + 'static)) {
+        /// Create a widget, returning `(WidgetId, *mut dyn WidgetHost)`.
+        fn make(&mut self, tag: u32) -> (WidgetId, *mut (dyn WidgetHost + 'static)) {
             let mut b = Box::new(Marker { base: crate::widget::Widget::new(), tag: tag });
-            let ptr: *mut (dyn Element + 'static) = &mut *b;
+            let ptr: *mut (dyn WidgetHost + 'static) = &mut *b;
             self.boxes.push(b);
             (WidgetId(tag as usize), ptr)
         }
diff --git a/src/widget/container/breadcrumb.rs b/src/widget/container/breadcrumb.rs
index 9c293e4..3f1318a 100644
--- a/src/widget/container/breadcrumb.rs
+++ b/src/widget/container/breadcrumb.rs
@@ -209,7 +209,7 @@ impl PathController for Breadcrumb {
 mod tests {
     use super::*;
     use crate::context::UiContext;
-    use crate::widget::Element;
+    use crate::widget::WidgetHost;
 
     #[test]
     fn test_breadcrumb_clicks() {
diff --git a/src/widget/container/container_layout.rs b/src/widget/container/container_layout.rs
index 83fbb33..aec6729 100644
--- a/src/widget/container/container_layout.rs
+++ b/src/widget/container/container_layout.rs
@@ -31,7 +31,7 @@ impl crate::layout::LayoutStrategy for OverlayLayout {
         (self.left, self.top, self.width, self.height)
     }
 
-    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn Element + 'static)], _ctx: &mut UiContext) -> f32 {
+    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn WidgetHost + 'static)], _ctx: &mut UiContext) -> f32 {
         for &child_ptr in children {
             unsafe {
                 (*child_ptr).set_rect(x, y, w, h);
@@ -40,7 +40,7 @@ impl crate::layout::LayoutStrategy for OverlayLayout {
         h
     }
 
-    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn Element + 'static)], ctx: &UiContext) -> Size {
+    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn WidgetHost + 'static)], ctx: &UiContext) -> Size {
         let mut max_w = 0.0f32;
         let mut max_h = 0.0f32;
         for &child_ptr in children {
@@ -87,11 +87,11 @@ impl crate::layout::LayoutStrategy for ManualLayout {
         (self.left, self.top, self.width, self.height)
     }
 
-    fn layout(&self, _x: f32, _y: f32, _w: f32, _h: f32, _children: &[*mut (dyn Element + 'static)], _ctx: &mut UiContext) -> f32 {
+    fn layout(&self, _x: f32, _y: f32, _w: f32, _h: f32, _children: &[*mut (dyn WidgetHost + 'static)], _ctx: &mut UiContext) -> f32 {
         self.height
     }
 
-    fn measure(&self, constraints: LayoutConstraints, _children: &[*mut (dyn Element + 'static)], _ctx: &UiContext) -> Size {
+    fn measure(&self, constraints: LayoutConstraints, _children: &[*mut (dyn WidgetHost + 'static)], _ctx: &UiContext) -> Size {
         Size {
             width: self.width.clamp(constraints.min_width, constraints.max_width),
             height: self.height.clamp(constraints.min_height, constraints.max_height),
@@ -148,7 +148,7 @@ impl crate::layout::LayoutStrategy for VerticalLayout {
         self.spacing
     }
 
-    fn layout(&self, x: f32, y: f32, w: f32, _h: f32, children: &[*mut (dyn Element + 'static)], ctx: &mut UiContext) -> f32 {
+    fn layout(&self, x: f32, y: f32, w: f32, _h: f32, children: &[*mut (dyn WidgetHost + 'static)], ctx: &mut UiContext) -> f32 {
         let left_x = x + self.padding_x;
         let available_w = (w - 2.0 * self.padding_x).max(1.0);
         let mut current_y = y + self.padding_y;
@@ -169,7 +169,7 @@ impl crate::layout::LayoutStrategy for VerticalLayout {
         (current_y - y).max(0.0)
     }
 
-    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn Element + 'static)], ctx: &UiContext) -> Size {
+    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn WidgetHost + 'static)], ctx: &UiContext) -> Size {
         let mut total_h = self.padding_y * 2.0;
         let mut max_w = 0.0f32;
         let spacing = self.spacing;
@@ -246,7 +246,7 @@ impl crate::layout::LayoutStrategy for GridLayout {
         self.gap
     }
 
-    fn layout(&self, x: f32, y: f32, w: f32, _h: f32, children: &[*mut (dyn Element + 'static)], ctx: &mut UiContext) -> f32 {
+    fn layout(&self, x: f32, y: f32, w: f32, _h: f32, children: &[*mut (dyn WidgetHost + 'static)], ctx: &mut UiContext) -> f32 {
         let count = children.len();
         if count == 0 {
             return 0.0;
@@ -288,7 +288,7 @@ impl crate::layout::LayoutStrategy for GridLayout {
         (max_h - y).max(0.0)
     }
 
-    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn Element + 'static)], ctx: &UiContext) -> Size {
+    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn WidgetHost + 'static)], ctx: &UiContext) -> Size {
         let cols = self.columns.max(1);
         let mut col_heights = vec![self.padding_y; cols];
         let total_gap = self.gap * (cols - 1) as f32;
@@ -374,7 +374,7 @@ impl crate::layout::LayoutStrategy for AdaptiveGridLayout {
         self.gap
     }
 
-    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn Element + 'static)], ctx: &mut UiContext) -> f32 {
+    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn WidgetHost + 'static)], ctx: &mut UiContext) -> f32 {
         let usable_w = (w - 2.0 * self.padding_x).max(1.0);
         let cols = (((usable_w + self.gap) / (self.min_col_width + self.gap)).floor().max(1.0)) as usize;
         let grid = GridLayout {
@@ -387,7 +387,7 @@ impl crate::layout::LayoutStrategy for AdaptiveGridLayout {
         grid.layout(x, y, w, h, children, ctx)
     }
 
-    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn Element + 'static)], ctx: &UiContext) -> Size {
+    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn WidgetHost + 'static)], ctx: &UiContext) -> Size {
         let usable_w = (constraints.max_width - 2.0 * self.padding_x).max(1.0);
         let cols = (((usable_w + self.gap) / (self.min_col_width + self.gap)).floor().max(1.0)) as usize;
         let grid = GridLayout {
@@ -433,7 +433,7 @@ impl crate::layout::LayoutStrategy for ColumnsLayout {
     fn allocate(&mut self, ww: f32, wh: f32) -> (f32, f32, f32, f32) { (0.0, 0.0, ww, wh) }
     fn get_gap(&self) -> f32 { self.spacing }
 
-    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn Element + 'static)], ctx: &mut UiContext) -> f32 {
+    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn WidgetHost + 'static)], ctx: &mut UiContext) -> f32 {
         let count = children.len();
         if count == 0 {
             return 0.0;
@@ -460,7 +460,7 @@ impl crate::layout::LayoutStrategy for ColumnsLayout {
         use_h + 2.0 * self.padding_y
     }
 
-    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn Element + 'static)], ctx: &UiContext) -> Size {
+    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn WidgetHost + 'static)], ctx: &UiContext) -> Size {
         let count = children.len();
         if count == 0 {
             return Size { width: constraints.min_width, height: constraints.min_height };
@@ -577,7 +577,7 @@ impl crate::layout::LayoutStrategy for MosaicLayout {
     fn allocate(&mut self, ww: f32, wh: f32) -> (f32, f32, f32, f32) { (0.0, 0.0, ww, wh) }
     fn get_gap(&self) -> f32 { self.gap }
 
-    fn layout(&self, x: f32, y: f32, w: f32, _h: f32, children: &[*mut (dyn Element + 'static)], ctx: &mut UiContext) -> f32 {
+    fn layout(&self, x: f32, y: f32, w: f32, _h: f32, children: &[*mut (dyn WidgetHost + 'static)], ctx: &mut UiContext) -> f32 {
         let count = children.len();
         if count == 0 {
             return 0.0;
@@ -607,7 +607,7 @@ impl crate::layout::LayoutStrategy for MosaicLayout {
         (packer.max_h - y).max(0.0)
     }
 
-    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn Element + 'static)], ctx: &UiContext) -> Size {
+    fn measure(&self, constraints: LayoutConstraints, children: &[*mut (dyn WidgetHost + 'static)], ctx: &UiContext) -> Size {
         let count = children.len();
         if count == 0 {
             return Size { width: constraints.min_width, height: constraints.min_height };
@@ -663,7 +663,7 @@ impl crate::layout::LayoutStrategy for ReverseMosaicLayout {
     fn allocate(&mut self, ww: f32, wh: f32) -> (f32, f32, f32, f32) { (0.0, 0.0, ww, wh) }
     fn get_gap(&self) -> f32 { self.gap }
 
-    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn Element + 'static)], ctx: &mut UiContext) -> f32 {
+    fn layout(&self, x: f32, y: f32, w: f32, h: f32, children: &[*mut (dyn WidgetHost + 'static)], ctx: &mut UiContext) -> f32 {
         let count = children.len();
         if count == 0 {
             return 0.0;
@@ -729,7 +729,7 @@ impl crate::layout::LayoutStrategy for ReverseMosaicLayout {
         h
     }
 
-    fn measure(&self, constraints: LayoutConstraints, _children: &[*mut (dyn Element + 'static)], _ctx: &UiContext) -> Size {
+    fn measure(&self, constraints: LayoutConstraints, _children: &[*mut (dyn WidgetHost + 'static)], _ctx: &UiContext) -> Size {
         Size {
             width: constraints.max_width,
             height: constraints.max_height,
diff --git a/src/widget/container/menu.rs b/src/widget/container/menu.rs
index b00ff09..77412d0 100644
--- a/src/widget/container/menu.rs
+++ b/src/widget/container/menu.rs
@@ -1,6 +1,6 @@
 //! Narrow-trait `MenuBar` (Phase 5o) — a titled bar of dropdown menus with an optional
 //! context selector on the title. The menu buttons live in an EMBEDDED legacy [`ButtonStrip`]
-//! (owned by value in the model, driven through `Element` calls — events reach it via
+//! (owned by value in the model, driven through `WidgetHost` calls — events reach it via
 //! `EventCtx::ui`, and [`Layout::arrange_children`] parents it back to the adapter so its
 //! parent-chain styling walks keep working). Dropdowns are painted through the popover hooks
 //! ([`Paint::popover`] / [`Paint::draw_popover`]) and layered by [`Layout::z_order`]. The
@@ -23,7 +23,7 @@ use crate::scene::layout::Rect;
 use crate::scene::paint::PaintCtx;
 use crate::widget::display::TextLabel;
 use crate::widget::{
-    Adapted, ButtonStrip, Element, ElementState, Event, EventCtx, Input, Key, Layout,
+    Adapted, ButtonStrip, WidgetHost, ElementState, Event, EventCtx, Input, Key, Layout,
     MenuController, MouseButton, NamedKey, PageSelector, Paint, DROPDOWN_ITEM_H,
 };
 
@@ -94,7 +94,7 @@ impl MenuBar {
             clicked_dropdown_item: None,
             last_arranged: None,
         });
-        Element::set_rect(&mut bar, x, y, w, h);
+        WidgetHost::set_rect(&mut bar, x, y, w, h);
         bar
     }
 
@@ -423,7 +423,7 @@ impl Layout for MenuBar {
         self.z_level
     }
 
-    fn arrange_children(&mut self, rect: Rect, _host: *mut (dyn Element + 'static)) {
+    fn arrange_children(&mut self, rect: Rect, _host: *mut (dyn WidgetHost + 'static)) {
         self.layout_strip(rect);
     }
 }
@@ -1068,7 +1068,7 @@ mod tests {
         let mut mb = bar();
         let (id, ptr) = (mb.id(), mb.as_ptr_mut());
         ctx.register_widget(id, ptr);
-        Element::set_rect(&mut mb, 0.0, 0.0, 400.0, 24.0);
+        WidgetHost::set_rect(&mut mb, 0.0, 0.0, 400.0, 24.0);
 
         // Click the "File" strip button (the strip commits selection on release): the dropdown
         // opens, the bar reports focused (conditional focus), and a popover rect exists.
@@ -1077,14 +1077,14 @@ mod tests {
         assert!(mb.mouse_input(MouseButton::Left, ElementState::Pressed, bx + bw / 2.0, by + bh / 2.0, &mut ctx));
         assert!(mb.mouse_input(MouseButton::Left, ElementState::Released, bx + bw / 2.0, by + bh / 2.0, &mut ctx));
         assert!(MenuController::is_menu_open(&*mb), "dropdown open");
-        assert!(Element::focused(&mb, &ctx), "bar holds focus while open");
-        let (dx, dy, _, _) = Element::popover_rect(&mb).expect("dropdown popover");
+        assert!(WidgetHost::focused(&mb, &ctx), "bar holds focus while open");
+        let (dx, dy, _, _) = WidgetHost::popover_rect(&mb).expect("dropdown popover");
 
         // Click the second item ("Save"): menu_click reports (0, 1) and everything closes.
         assert!(mb.mouse_input(MouseButton::Left, ElementState::Pressed, dx + 10.0, dy + DROPDOWN_ITEM_H * 1.5, &mut ctx));
         assert_eq!(MenuController::menu_click(&mut *mb), Some((0, 1)));
         assert!(!MenuController::is_menu_open(&*mb));
-        assert!(!Element::focused(&mb, &ctx), "focus released after the click");
+        assert!(!WidgetHost::focused(&mb, &ctx), "focus released after the click");
 
         // The PageSelector capability is reached through the concrete adapter too.
         assert!(PageSelector::sidebar_w(&*mb) > 0.0);
@@ -1096,11 +1096,11 @@ mod tests {
         let mut mb = bar();
         let (id, ptr) = (mb.id(), mb.as_ptr_mut());
         ctx.register_widget(id, ptr);
-        Element::set_rect(&mut mb, 0.0, 0.0, 400.0, 24.0);
+        WidgetHost::set_rect(&mut mb, 0.0, 0.0, 400.0, 24.0);
 
-        Element::set_visible(&mut mb, false);
+        WidgetHost::set_visible(&mut mb, false);
         assert!(!MenuController::is_menu_bar(&*mb), "hidden bar is not a menu bar");
-        assert!(!Element::hit_test(&mb, 10.0, 10.0, &ctx));
+        assert!(!WidgetHost::hit_test(&mb, 10.0, 10.0, &ctx));
         assert!(MenuController::get_menu_items_at(&*mb, 10.0, 10.0).is_none());
     }
 }
diff --git a/src/widget/container/paginator.rs b/src/widget/container/paginator.rs
index d578c36..2993902 100644
--- a/src/widget/container/paginator.rs
+++ b/src/widget/container/paginator.rs
@@ -19,7 +19,7 @@ use crate::scene::layout::Rect;
 use crate::scene::paint::PaintCtx;
 use crate::widget::input::ButtonStrip;
 use crate::widget::{
-    Adapted, Element, Event, EventCtx, Input, Layout, MenuController, PageSelector, Paint,
+    Adapted, WidgetHost, Event, EventCtx, Input, Layout, MenuController, PageSelector, Paint,
     UiContext, WidgetId,
 };
 
@@ -150,12 +150,12 @@ impl Layout for Paginator {
         true
     }
 
-    fn container_children(&self) -> Vec<*mut (dyn Element + 'static)> {
-        vec![&self.sidebar_menu as &dyn Element as *const (dyn Element + 'static) as *mut (dyn Element + 'static)]
+    fn container_children(&self) -> Vec<*mut (dyn WidgetHost + 'static)> {
+        vec![&self.sidebar_menu as &dyn WidgetHost as *const (dyn WidgetHost + 'static) as *mut (dyn WidgetHost + 'static)]
     }
 
     /// The legacy `set_rect` body: strip on the left at its measured width.
-    fn arrange_children(&mut self, rect: Rect, _host: *mut (dyn Element + 'static)) {
+    fn arrange_children(&mut self, rect: Rect, _host: *mut (dyn WidgetHost + 'static)) {
         let (x, y, h) = (rect.x, rect.y, rect.height);
         let sidebar_w = self.sidebar_w();
         self.sidebar_menu.set_rect(x, y, sidebar_w, h);
@@ -282,7 +282,7 @@ mod tests {
 
     fn paginator() -> Adapted<Paginator> {
         let mut p = Paginator::new(vec!["One".to_string(), "Two".to_string()]);
-        Element::set_rect(&mut p, 0.0, 0.0, 400.0, 300.0);
+        WidgetHost::set_rect(&mut p, 0.0, 0.0, 400.0, 300.0);
         p
     }
 
@@ -319,19 +319,19 @@ mod tests {
         // Legacy split: `extra_quads` is the children's chrome only; the sidebar background
         // quad lives in `all_quads` alone (email/layout-interface draw their own backgrounds
         // under `extra_quads`).
-        let extra = Element::extra_quads(&p);
+        let extra = WidgetHost::extra_quads(&p);
         let strip_extra = p.sidebar_menu.extra_quads();
         assert_eq!(extra.len(), strip_extra.len(), "children-only plain view (pages emit none)");
         let bg = colors::sidebar_bg_color();
         if bg[3] > 0.0 {
             let bg_quad = (0.0, 0.0, 400.0, 300.0, bg);
             assert!(!extra.contains(&bg_quad), "no own bg in extra_quads");
-            assert!(Element::all_quads(&p, &ctx).contains(&bg_quad), "own bg in all_quads");
+            assert!(WidgetHost::all_quads(&p, &ctx).contains(&bg_quad), "own bg in all_quads");
         }
 
         // The embedded strip + pages land in the registry on tick (the spatial grid feeds off
         // it — the registered strip is what blocks backplate drags over the sidebar).
-        Element::tick(&mut p, 0.016, &mut ctx);
+        WidgetHost::tick(&mut p, 0.016, &mut ctx);
         let strip_id = p.sidebar_menu.id();
         assert!(
             ctx.tree.iter_registered().any(|(w_id, _)| w_id == strip_id),
diff --git a/src/widget/container/parameters_bg.rs b/src/widget/container/parameters_bg.rs
index 9e44da9..3cd8ece 100644
--- a/src/widget/container/parameters_bg.rs
+++ b/src/widget/container/parameters_bg.rs
@@ -3,7 +3,7 @@
 //! buttons, section borders, and an inline emacs-flavored code editor), each row's widget owned
 //! by value in parallel `Vec<Option<..>>` fields (most already `Adapted<W>` from earlier
 //! phases), plus a raw-pointer `children` container list. The designer stores it as
-//! `Box<dyn Element>` and drives it through direct `dyn Element` calls; `window_runner`'s
+//! `Box<dyn WidgetHost>` and drives it through direct `dyn WidgetHost` calls; `window_runner`'s
 //! `get_child_widget_for_quad` downcasts to the concrete type through `as_any` (which the
 //! adapter forwards to the inner widget) and reads the pub sub-widget fields — both keep
 //! working unchanged.
@@ -27,7 +27,7 @@ use crate::scene::paint::PaintCtx;
 use crate::widget::display::{Float3, TextLabel};
 use crate::widget::input::{Button, Checkbox, ColorSelector, Dropdown, Slider, Spinbox, TextBox};
 use crate::widget::{
-    Adapted, Element, ElementState, Event, EventCtx, Input, Key, Layout, MouseButton,
+    Adapted, WidgetHost, ElementState, Event, EventCtx, Input, Key, Layout, MouseButton,
     MouseScrollDelta, NamedKey, Paint, ParamController, TextEditorState, UiContext,
 };
 
@@ -1747,7 +1747,7 @@ mod tests {
             .map(|(a, b, c)| (a.to_string(), b.to_string(), c.to_string()))
             .collect();
         ParamController::set_display_params(&mut *p, &params);
-        Element::set_rect(&mut p, 0.0, 0.0, 300.0, 400.0);
+        WidgetHost::set_rect(&mut p, 0.0, 0.0, 300.0, 400.0);
         p
     }
 
@@ -1784,7 +1784,7 @@ mod tests {
         assert_eq!(p.focused_param, Some(0), "code row focused");
         assert!(p.code_editor.is_some());
         p.code_editor.as_mut().unwrap().insert_text("y");
-        Element::unfocus(&mut p);
+        WidgetHost::unfocus(&mut p);
         assert_eq!(p.focused_param, None);
         assert!(p.code_editor.is_none());
         assert!(ParamController::node_params(&*p)[0].1.contains('y'), "editor buffer committed on unfocus");
@@ -1796,16 +1796,16 @@ mod tests {
         let p = panel_with(&[("Size", "1.00", "slider:0:2")]);
         // The designer's plain path: extra_quads carries the row chrome (clipped), including
         // the slider background it reads via rect()+color()...
-        let extra = Element::extra_quads(&p);
+        let extra = WidgetHost::extra_quads(&p);
         assert!(!extra.is_empty(), "row chrome served through extra_quads");
         // ...but NOT the panel's own PARAM_BG plate (the host draws that from color()).
-        let (x, y, w, h) = Element::rect(&p);
+        let (x, y, w, h) = WidgetHost::rect(&p);
         assert!(
             !extra.iter().any(|q| (q.0, q.1, q.2, q.3) == (x, y, w, h)),
             "panel bg plate is the host's, not extra_quads'"
         );
         // The no-double-draw contract of the plain-quad hatch.
-        assert!(Element::all_quads(&p, &ctx).is_empty());
+        assert!(WidgetHost::all_quads(&p, &ctx).is_empty());
         // Per-label hatch: the walk's text prims carry the widget font and viewport bounds.
         let mut scratch = crate::scene::paint::PaintCtx::new();
         crate::scene::painter::append_widget_text(&ctx, &p, &mut scratch);
@@ -1830,9 +1830,9 @@ mod tests {
             .collect();
         let mut p = ParametersBg::new();
         ParamController::set_display_params(&mut *p, &rows);
-        Element::set_rect(&mut p, 0.0, 0.0, 300.0, 200.0);
+        WidgetHost::set_rect(&mut p, 0.0, 0.0, 300.0, 200.0);
         assert!(p.content_h > 200.0);
-        assert!(Element::is_scrollable(&p));
+        assert!(WidgetHost::is_scrollable(&p));
         // Wheel over the panel body but off every slider row's x-span is impossible (rows are
         // full-width), so scroll via the region below the last visible row: use a y between
         // rows (the 2px slack above a row) — simplest is the bottom padding strip.
diff --git a/src/widget/container/scroll_box.rs b/src/widget/container/scroll_box.rs
index f509ddc..410b0f9 100644
--- a/src/widget/container/scroll_box.rs
+++ b/src/widget/container/scroll_box.rs
@@ -1,7 +1,7 @@
-//! Embedded scroll-math + scrollbar-chrome helper (Phase 6av: DEMOTED from `Element` to a
+//! Embedded scroll-math + scrollbar-chrome helper (Phase 6av: DEMOTED from `WidgetHost` to a
 //! plain struct). Never registered into the ctx tree by either consumer — TreeList and
 //! cce-test-interface's panel copy drive it entirely through concrete calls — so the
-//! `Element` impl was pure dyn-dispatch ballast. The former Element-default entry points the
+//! `WidgetHost` impl was pure dyn-dispatch ballast. The former WidgetHost-default entry points the
 //! consumers forward (`cursor_moved`, `tick`, drag hooks, `is_dragging`) are kept as
 //! inherent methods with the exact default-derived behavior.
 
@@ -82,7 +82,7 @@ impl ScrollBox {
         self.viewport_h = h + self.viewport_offset_h;
     }
 
-    /// The legacy `Element` default hit test over the base rect (ScrollBox never carried a
+    /// The legacy `WidgetHost` default hit test over the base rect (ScrollBox never carried a
     /// label or row expansion, so those branches are folded away).
     fn hit_test(&self, px: f32, py: f32, ctx: &UiContext) -> bool {
         if ctx.is_coordinate_covered(self.base.id(), px, py) {
@@ -98,7 +98,7 @@ impl ScrollBox {
     /// The legacy focus claim on scrollbar/list clicks: its only observable effect was
     /// unfocusing the previously focused widget (nothing ever queried focus ON the scroll
     /// box through the thread-local, and its own `unfocus` was a no-op) — so just release
-    /// the current holder instead of storing a pointer to a non-Element.
+    /// the current holder instead of storing a pointer to a non-WidgetHost.
     fn claim_focus(&self, ctx: &mut UiContext) {
         focus::clear_focus(Some(ctx));
     }
@@ -154,7 +154,7 @@ impl ScrollBox {
         self.scrollbar_dragging
     }
 
-    /// Legacy `Element` default parity: ScrollBox never overrode `is_dragging` — TreeList
+    /// Legacy `WidgetHost` default parity: ScrollBox never overrode `is_dragging` — TreeList
     /// forwards it and always got `false`.
     pub fn is_dragging(&self) -> bool {
         false
@@ -192,7 +192,7 @@ impl ScrollBox {
         self.scrollbar_dragging = false;
     }
 
-    /// The legacy `Element` default `cursor_moved` entry (cce-test-interface's panel copy
+    /// The legacy `WidgetHost` default `cursor_moved` entry (cce-test-interface's panel copy
     /// calls it): cover-check clears hover, otherwise falls into `on_cursor_moved`. The
     /// MouseLeave dispatch the default performed was a no-op for ScrollBox.
     pub fn cursor_moved(&mut self, px: f32, py: f32, ctx: &mut UiContext) -> bool {
@@ -242,7 +242,7 @@ impl ScrollBox {
         changed
     }
 
-    /// Legacy `Element` default parity (cce-test-interface's panel copy ticks it).
+    /// Legacy `WidgetHost` default parity (cce-test-interface's panel copy ticks it).
     pub fn tick(&mut self, _dt: f32, _ctx: &mut UiContext) -> bool {
         false
     }
@@ -301,7 +301,7 @@ impl ScrollBox {
     }
 
     pub fn keyboard_input(&mut self, event: &KeyEvent, ctx: &mut UiContext) -> bool {
-        // Focus never lands on the box itself (post-6av it is not an `Element`), and its id is
+        // Focus never lands on the box itself (post-6av it is not an `WidgetHost`), and its id is
         // never a tree ancestor of the focused widget — like the legacy address walk, this
         // gate only ever passes via the hover check below.
         let self_id = self.base.id();
@@ -431,7 +431,7 @@ mod tests {
         sb.update_bounds(300.0, 20.0, 100.0); // max_scroll = 200.0
 
         let mut ctx = UiContext::new();
-        // Hover the scroll box (the focus path took a ctx-registered Element; as a plain
+        // Hover the scroll box (the focus path took a ctx-registered WidgetHost; as a plain
         // struct the hovered branch is the live gate).
         ctx.set_cursor_pos(50.0, 50.0);
 
diff --git a/src/widget/container/spreadsheet.rs b/src/widget/container/spreadsheet.rs
index a3cfdb5..3bab1c2 100644
--- a/src/widget/container/spreadsheet.rs
+++ b/src/widget/container/spreadsheet.rs
@@ -63,7 +63,7 @@ impl Spreadsheet {
             scrollbar_thumb_hovered: false,
         });
         // The spreadsheet pane starts hidden (the designer toggles it in later).
-        crate::widget::Element::set_visible(&mut s, false);
+        crate::widget::WidgetHost::set_visible(&mut s, false);
         s
     }
 
@@ -109,7 +109,7 @@ impl Paint for Spreadsheet {
     }
 
     fn corner_style(&self, _rect: Rect) -> Option<(f32, (bool, bool, bool, bool))> {
-        // Legacy: rounded_corners override (all corners) with the Element-default 12.0 radius.
+        // Legacy: rounded_corners override (all corners) with the WidgetHost-default 12.0 radius.
         Some((12.0, (true, true, true, true)))
     }
 
@@ -365,12 +365,12 @@ impl SpreadsheetController for Spreadsheet {
 mod tests {
     use super::*;
     use crate::context::UiContext;
-    use crate::widget::Element;
+    use crate::widget::WidgetHost;
 
     fn filled(rows: usize) -> Adapted<Spreadsheet> {
         let mut s = Spreadsheet::new();
         s.set_visible(true);
-        Element::set_rect(&mut s, 0.0, 0.0, 200.0, 124.0); // viewport: 100 = ~4 rows of 24
+        WidgetHost::set_rect(&mut s, 0.0, 0.0, 200.0, 124.0); // viewport: 100 = ~4 rows of 24
         let data: Vec<Vec<String>> =
             (0..rows).map(|i| vec![format!("r{i}"), format!("v{i}")]).collect();
         SpreadsheetController::set_spreadsheet_data(&mut *s, vec!["a".into(), "b".into()], data);
@@ -396,9 +396,9 @@ mod tests {
         assert!(s.handle_event(&wheel, &mut ctx), "in-rect wheel consumed");
 
         // …which tick integrates into scroll movement and decays to a stop.
-        assert!(Element::tick(&mut s, 0.016, &mut ctx), "first tick moves the scroll");
+        assert!(WidgetHost::tick(&mut s, 0.016, &mut ctx), "first tick moves the scroll");
         let mut guard = 0;
-        while Element::tick(&mut s, 0.016, &mut ctx) {
+        while WidgetHost::tick(&mut s, 0.016, &mut ctx) {
             guard += 1;
             assert!(guard < 1000, "inertia must decay to a stop");
         }
@@ -417,20 +417,20 @@ mod tests {
         let rect = Rect { x: 0.0, y: 0.0, width: 200.0, height: 124.0 };
 
         // content 1200, viewport 100 -> overflowing, so the host may drag it.
-        assert!(Element::draggable(&s));
+        assert!(WidgetHost::draggable(&s));
 
         // Press on the scrollbar track (x >= 200-6-2-4): thumb jumps, drag engages.
-        Element::drag_begin(&mut s, 195.0, 80.0);
-        assert!(Element::is_dragging(&s));
-        assert!(Element::drag_update(&mut s, 195.0, 110.0), "thumb drag scrolls");
+        WidgetHost::drag_begin(&mut s, 195.0, 80.0);
+        assert!(WidgetHost::is_dragging(&s));
+        assert!(WidgetHost::drag_update(&mut s, 195.0, 110.0), "thumb drag scrolls");
         let dragged_to = s.inner().geom(rect).unwrap().scroll;
         assert!(dragged_to > 0.0);
-        Element::drag_end(&mut s);
-        assert!(!Element::is_dragging(&s));
+        WidgetHost::drag_end(&mut s);
+        assert!(!WidgetHost::is_dragging(&s));
 
         // A body press (left of the scrollbar) engages no drag.
-        Element::drag_begin(&mut s, 50.0, 60.0);
-        assert!(!Element::is_dragging(&s), "body press is not a scrollbar drag");
+        WidgetHost::drag_begin(&mut s, 50.0, 60.0);
+        assert!(!WidgetHost::is_dragging(&s), "body press is not a scrollbar drag");
 
         // End key jumps to max; Home returns to zero. (Keys route via keyboard_input.)
         let end = crate::widget::KeyEvent {
@@ -441,12 +441,12 @@ mod tests {
             ctrl: false,
             shift: false,
         };
-        assert!(Element::keyboard_input(&mut s, &end, &mut ctx));
+        assert!(WidgetHost::keyboard_input(&mut s, &end, &mut ctx));
         let g = s.inner().geom(rect).unwrap();
         assert_eq!(g.scroll, g.max_scroll);
 
         // Hidden: the focused-widget keyboard path must not consume keys.
         s.set_visible(false);
-        assert!(!Element::keyboard_input(&mut s, &end, &mut ctx), "hidden widget ignores keys");
+        assert!(!WidgetHost::keyboard_input(&mut s, &end, &mut ctx), "hidden widget ignores keys");
     }
 }
diff --git a/src/widget/container/treelist.rs b/src/widget/container/treelist.rs
index c30125c..55f526b 100644
--- a/src/widget/container/treelist.rs
+++ b/src/widget/container/treelist.rs
@@ -357,7 +357,7 @@ impl TreeList {
         }
     }
 
-    fn mouse_body(&mut self, button: MouseButton, state: ElementState, px: f32, py: f32, ui: &mut UiContext, host: Option<*mut (dyn Element + 'static)>, host_id: WidgetId) -> bool {
+    fn mouse_body(&mut self, button: MouseButton, state: ElementState, px: f32, py: f32, ui: &mut UiContext, host: Option<*mut (dyn WidgetHost + 'static)>, host_id: WidgetId) -> bool {
         let _ = host_id;
         if self.editing_key_idx.is_some() {
             if button == MouseButton::Left && state == ElementState::Pressed {
@@ -690,7 +690,7 @@ impl Paint for TreeList {
         true
     }
 
-    // Legacy TreeList kept the default Element focus/hover highlight overlay (the teal
+    // Legacy TreeList kept the default WidgetHost focus/hover highlight overlay (the teal
     // wash over the focused tree, drawn by the old all_quads default) — opt back in
     // (the 5q TextBox trap).
     fn legacy_focus_highlight(&self) -> bool {
diff --git a/src/widget/core.rs b/src/widget/core.rs
index 4db482b..99153ae 100644
--- a/src/widget/core.rs
+++ b/src/widget/core.rs
@@ -1,7 +1,7 @@
-use crate::widget::{Element, Key};
+use crate::widget::{WidgetHost, Key};
 
 pub mod focus {
-    use super::Element;
+    use super::WidgetHost;
     use crate::widget::WidgetId;
     use std::cell::Cell;
 
@@ -23,7 +23,7 @@ pub mod focus {
         }
     }
 
-    pub fn set_focused(w: &mut dyn Element, ctx: Option<&mut crate::context::UiContext>) {
+    pub fn set_focused(w: &mut dyn WidgetHost, ctx: Option<&mut crate::context::UiContext>) {
         set_focused_id(w.base().id(), ctx);
     }
 
@@ -39,7 +39,7 @@ pub mod focus {
         }
     }
 
-    pub fn is_focused(w: &dyn Element) -> bool {
+    pub fn is_focused(w: &dyn WidgetHost) -> bool {
         is_focused_id(w.base().id())
     }
 
@@ -53,7 +53,7 @@ pub mod focus {
         }
     }
 
-    pub fn clear_if_matches(w: &dyn Element) {
+    pub fn clear_if_matches(w: &dyn WidgetHost) {
         clear_if_matches_id(w.base().id());
     }
 
@@ -69,12 +69,12 @@ pub mod focus {
         FOCUSED_WIDGET.with(|cell| cell.get().is_some())
     }
 
-    pub fn link_parent_child(parent: &mut dyn Element, child: &mut dyn Element, ctx: &mut crate::context::UiContext) {
+    pub fn link_parent_child(parent: &mut dyn WidgetHost, child: &mut dyn WidgetHost, ctx: &mut crate::context::UiContext) {
         let parent_ptr = unsafe {
-            std::mem::transmute::<*mut dyn Element, *mut (dyn Element + 'static)>(parent as *mut dyn Element)
+            std::mem::transmute::<*mut dyn WidgetHost, *mut (dyn WidgetHost + 'static)>(parent as *mut dyn WidgetHost)
         };
         let child_ptr = unsafe {
-            std::mem::transmute::<*mut dyn Element, *mut (dyn Element + 'static)>(child as *mut dyn Element)
+            std::mem::transmute::<*mut dyn WidgetHost, *mut (dyn WidgetHost + 'static)>(child as *mut dyn WidgetHost)
         };
         let (p_id, c_id) = (parent.base().id(), child.base().id());
         ctx.register_widget(p_id, parent_ptr);
@@ -578,7 +578,7 @@ pub mod context_menu {
         CONTEXT_MENU.with(|m| m.borrow_mut().hide());
     }
 
-    pub fn clear_if_matches(w: &dyn Element) {
+    pub fn clear_if_matches(w: &dyn WidgetHost) {
         let id = w.base().id();
         CONTEXT_MENU.with(|m| {
             let mut menu = m.borrow_mut();
@@ -697,7 +697,7 @@ impl Widget {
 }
 
 
-pub fn clear_widget_references(w: &dyn Element) {
+pub fn clear_widget_references(w: &dyn WidgetHost) {
     focus::clear_if_matches(w);
     context_menu::clear_if_matches(w);
 }
@@ -709,11 +709,11 @@ macro_rules! impl_widget_base {
         fn base_mut(&mut self) -> &mut $crate::widget::Widget { &mut self.base }
         fn as_any(&self) -> &dyn std::any::Any { self }
         fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
-        fn as_ptr(&self) -> *mut (dyn $crate::widget::Element + 'static) {
-            self as *const Self as *mut Self as *mut (dyn $crate::widget::Element + 'static)
+        fn as_ptr(&self) -> *mut (dyn $crate::widget::WidgetHost + 'static) {
+            self as *const Self as *mut Self as *mut (dyn $crate::widget::WidgetHost + 'static)
         }
-        fn as_ptr_mut(&mut self) -> *mut (dyn $crate::widget::Element + 'static) {
-            self as *mut Self as *mut (dyn $crate::widget::Element + 'static)
+        fn as_ptr_mut(&mut self) -> *mut (dyn $crate::widget::WidgetHost + 'static) {
+            self as *mut Self as *mut (dyn $crate::widget::WidgetHost + 'static)
         }
     };
 }
diff --git a/src/widget/display/float3.rs b/src/widget/display/float3.rs
index 9c1746a..7a74186 100644
--- a/src/widget/display/float3.rs
+++ b/src/widget/display/float3.rs
@@ -1,6 +1,6 @@
 //! Narrow-trait `Float3` (Phase 5t) — three labeled slider rows (X/Y/Z) with click-to-edit
 //! numeric readouts, embedded by value inside `ParametersBg` (its only consumer), which drives
-//! it through direct `Element` calls and reads the pub value/edit fields through `Deref`. The
+//! it through direct `WidgetHost` calls and reads the pub value/edit fields through `Deref`. The
 //! model caches its laid-out rect ([`Layout::rect_assigned`] — `get_row_rects` is pub API with
 //! no rect parameter), draws everything in [`Paint::paint`], and keeps the legacy drag surface
 //! on the `Input` drag hooks. The readout click's legacy `focus::set_focused(self)` rides
@@ -325,7 +325,7 @@ impl Input for Float3 {
 mod tests {
     use super::*;
     use crate::context::UiContext;
-    use crate::widget::Element;
+    use crate::widget::WidgetHost;
 
     /// The ParametersBg drive pattern: readout click opens the edit, Enter/unfocus commits
     /// back into the normalized value, track press starts a drag.
@@ -333,7 +333,7 @@ mod tests {
     fn readout_edit_commits_on_unfocus() {
         let mut ctx = UiContext::new();
         let mut f = Float3::new().with_values([0.5, 0.5, 0.5]).with_range(0.0, 10.0);
-        Element::set_rect(&mut f, 0.0, 0.0, 300.0, 108.0);
+        WidgetHost::set_rect(&mut f, 0.0, 0.0, 300.0, 108.0);
 
         let rows = f.get_row_rects();
         assert_eq!(rows.len(), 3);
@@ -345,17 +345,17 @@ mod tests {
         assert_eq!(f.edit_buffer, "5.00");
 
         f.edit_buffer = "7.5".to_string();
-        Element::unfocus(&mut f);
+        WidgetHost::unfocus(&mut f);
         assert_eq!(f.editing_idx, None);
         assert!((f.values[1] - 0.75).abs() < 1e-4, "7.5 of 0..10 normalizes to 0.75");
 
         // Track press starts a drag; drag_update moves the value; release ends it.
         let track_y = rows[0].1 + 8.0;
         assert!(f.mouse_input(MouseButton::Left, ElementState::Pressed, 150.0, track_y, &mut ctx));
-        assert!(Element::is_dragging(&f));
-        Element::drag_update(&mut f, 260.0, track_y);
+        assert!(WidgetHost::is_dragging(&f));
+        WidgetHost::drag_update(&mut f, 260.0, track_y);
         assert!(f.values[0] > 0.5, "drag right raises the value");
-        Element::drag_end(&mut f);
-        assert!(!Element::is_dragging(&f));
+        WidgetHost::drag_end(&mut f);
+        assert!(!WidgetHost::is_dragging(&f));
     }
 }
diff --git a/src/widget/display/graph.rs b/src/widget/display/graph.rs
index 3d5677e..dbe2d90 100644
--- a/src/widget/display/graph.rs
+++ b/src/widget/display/graph.rs
@@ -43,7 +43,7 @@ pub struct GraphNode {
     pub outputs: usize,
 }
 
-/// The widget's own corner style: the legacy `Element` defaults it inherited
+/// The widget's own corner style: the legacy `WidgetHost` defaults it inherited
 /// (`corner_radius` 12.0, bottom corners rounded).
 const WIDGET_RADIUS: f32 = 12.0;
 const WIDGET_CORNERS: (bool, bool, bool, bool) = (false, false, true, true);
@@ -1019,11 +1019,11 @@ impl GraphController for Graph {
 mod tests {
     use super::*;
     use crate::context::UiContext;
-    use crate::widget::Element;
+    use crate::widget::WidgetHost;
 
     fn two_nodes() -> Adapted<Graph> {
         let mut g = Graph::new();
-        Element::set_rect(&mut g, 0.0, 0.0, 800.0, 600.0);
+        WidgetHost::set_rect(&mut g, 0.0, 0.0, 800.0, 600.0);
         g.set_grid_sizes(80.0, 40.0);
         g.set_skipped_sizes(20.0, 20.0);
         g.set_grid_origin(100.0, 100.0);
@@ -1052,14 +1052,14 @@ mod tests {
         // Node a occupies (100, 100, 80, 40). Press its body (away from ports/toggle).
         assert!(g.mouse_input(MouseButton::Left, ElementState::Pressed, 110.0, 120.0, &mut ctx));
         assert_eq!(g.selected_node(), Some(0));
-        assert!(Element::is_dragging(&g) && Element::draggable(&g));
+        assert!(WidgetHost::is_dragging(&g) && WidgetHost::draggable(&g));
 
         // Drag one grid step right (step_x = 100): snap puts the node at column 1, but cell
         // (1, 0) is free so it lands there.
-        Element::drag_begin(&mut g, 110.0, 120.0);
-        assert!(Element::drag_update(&mut g, 210.0, 120.0));
+        WidgetHost::drag_begin(&mut g, 110.0, 120.0);
+        assert!(WidgetHost::drag_update(&mut g, 210.0, 120.0));
         assert!(g.mouse_input(MouseButton::Left, ElementState::Released, 210.0, 120.0, &mut ctx));
-        assert!(!Element::is_dragging(&g));
+        assert!(!WidgetHost::is_dragging(&g));
         assert_eq!(g.get_nodes()[0].position, (1.0, 0.0));
 
         // An empty-space press clears the selection and is NOT consumed (legacy contract).
@@ -1090,8 +1090,8 @@ mod tests {
 
         // The plain view (designer path) and the rounded view (render_widget path) describe
         // the same quads: the rounded view adds only the widget background entry up front.
-        let plain = Element::extra_quads(&g);
-        let rounded = Element::all_rounded_quads(&g, &ctx);
+        let plain = WidgetHost::extra_quads(&g);
+        let rounded = WidgetHost::all_rounded_quads(&g, &ctx);
         assert!(!plain.is_empty());
         assert_eq!(rounded.len(), plain.len() + 1);
         for ((px, py, pw, ph, pc), (rx, ry, rw, rh, _, rc, _)) in plain.iter().zip(rounded.iter().skip(1)) {
@@ -1112,6 +1112,6 @@ mod tests {
 
         // And `all_quads` stays empty so render_widget hosts (reading BOTH getters) never
         // draw the geometry twice — the legacy Graph override's contract.
-        assert!(Element::all_quads(&g, &ctx).is_empty());
+        assert!(WidgetHost::all_quads(&g, &ctx).is_empty());
     }
 }
diff --git a/src/widget/display/label.rs b/src/widget/display/label.rs
index d6fb942..35a2575 100644
--- a/src/widget/display/label.rs
+++ b/src/widget/display/label.rs
@@ -5,7 +5,7 @@ use crate::scene::paint::PaintCtx;
 
 /// Narrow-trait text label (Phase 5f leaf sweep). The text lives on the model and is emitted by
 /// `paint` as a `Text` prim, which the adapter's prim-derived `text_labels` bridge serves to
-/// every legacy text path; `set_text` sync comes from the adapter's generic `Element::set_text`
+/// every legacy text path; `set_text` sync comes from the adapter's generic `WidgetHost::set_text`
 /// override via [`Paint::sync_label`].
 #[derive(Debug, Clone)]
 pub struct Label {
@@ -23,7 +23,7 @@ impl Label {
             color: colors::control_label_color_u8(),
         });
         // Keep the base copy in step too (context menus, fallback machinery).
-        Element::set_text(&mut l, text);
+        WidgetHost::set_text(&mut l, text);
         l
     }
 
@@ -91,11 +91,11 @@ mod tests {
     use super::*;
 
     /// Legacy `text_labels` parity through the prim bridge, and `set_text` staying in sync
-    /// through the adapter's `Element::set_text` override (the trait method apps actually hit).
+    /// through the adapter's `WidgetHost::set_text` override (the trait method apps actually hit).
     #[test]
     fn text_flows_and_set_text_syncs() {
         let mut l = Label::new("CPU: 3%").with_font_size(13.0).with_color([1, 2, 3]);
-        Element::set_rect(&mut l, 10.0, 20.0, 100.0, 16.0);
+        WidgetHost::set_rect(&mut l, 10.0, 20.0, 100.0, 16.0);
 
         let labels = l.own_text_labels();
         assert_eq!(labels.len(), 1);
@@ -104,12 +104,12 @@ mod tests {
         assert_eq!(labels[0].font_size, 13.0);
         assert_eq!(labels[0].color, [1, 2, 3]);
 
-        Element::set_text(&mut l, "CPU: 99%");
+        WidgetHost::set_text(&mut l, "CPU: 99%");
         assert_eq!(l.own_text_labels()[0].text, "CPU: 99%", "set_text reaches the paint source");
 
         let size = l.intrinsic_size().unwrap();
         assert!(size.width > 0.0);
-        assert!(!Element::blocks_backplate_drag(&l));
+        assert!(!WidgetHost::blocks_backplate_drag(&l));
     }
 }
 
diff --git a/src/widget/display/node.rs b/src/widget/display/node.rs
index 3c3409f..d86d644 100644
--- a/src/widget/display/node.rs
+++ b/src/widget/display/node.rs
@@ -1,7 +1,7 @@
 //! Narrow-trait `Node` (Phase 5k) — a network-editor node box: draggable with grid snap
 //! (self-moving, via [`Input::drag_reposition`]), a geometry-visibility toggle sub-zone, and
 //! two controller capabilities ([`ParamController`] + [`GeomController`]) re-exposed through
-//! the `Input` hooks for the legacy `Element::as_*_controller` downcasts.
+//! the `Input` hooks for the legacy `WidgetHost::as_*_controller` downcasts.
 
 use crate::colors;
 use crate::scene::layout::Rect;
@@ -49,7 +49,7 @@ impl Node {
             geom_toggled: false,
             toggle_hovered: false,
         });
-        crate::widget::Element::set_rect(&mut node, x, y, w, h);
+        crate::widget::WidgetHost::set_rect(&mut node, x, y, w, h);
         node
     }
 
@@ -249,7 +249,7 @@ impl GeomController for Node {
 mod tests {
     use super::*;
     use crate::context::UiContext;
-    use crate::widget::Element;
+    use crate::widget::WidgetHost;
 
     #[test]
     fn toggle_click_flips_geom_and_press_starts_drag() {
@@ -267,11 +267,11 @@ mod tests {
 
         // A press outside the toggle starts a drag; reposition snaps to the drag origin.
         assert!(node.mouse_input(MouseButton::Left, ElementState::Pressed, 110.0, 110.0, &mut ctx));
-        assert!(Element::is_dragging(&node));
-        assert!(Element::drag_update(&mut node, 150.0, 130.0));
-        assert_eq!(Element::rect(&node), (140.0, 120.0, 120.0, 40.0), "moved by the pointer delta");
+        assert!(WidgetHost::is_dragging(&node));
+        assert!(WidgetHost::drag_update(&mut node, 150.0, 130.0));
+        assert_eq!(WidgetHost::rect(&node), (140.0, 120.0, 120.0, 40.0), "moved by the pointer delta");
         assert!(node.mouse_input(MouseButton::Left, ElementState::Released, 150.0, 130.0, &mut ctx));
-        assert!(!Element::is_dragging(&node));
+        assert!(!WidgetHost::is_dragging(&node));
     }
 
     #[test]
diff --git a/src/widget/display/panel.rs b/src/widget/display/panel.rs
index 906bfa6..0ad1218 100644
--- a/src/widget/display/panel.rs
+++ b/src/widget/display/panel.rs
@@ -5,7 +5,7 @@
 use crate::colors;
 use crate::scene::layout::Rect;
 use crate::scene::paint::PaintCtx;
-use crate::widget::{Adapted, Element, ElementState, Event, EventCtx, Input, Layout, MouseButton, Paint};
+use crate::widget::{Adapted, WidgetHost, ElementState, Event, EventCtx, Input, Layout, MouseButton, Paint};
 
 pub struct Panel {
     dragging: bool,
@@ -17,7 +17,7 @@ pub struct Panel {
 impl Panel {
     pub fn new(x: f32, y: f32, w: f32, h: f32) -> Adapted<Panel> {
         let mut p = Adapted::new(Panel { dragging: false, drag_ox: 0.0, drag_oy: 0.0, bounds: None });
-        Element::set_rect(&mut p, x, y, w, h);
+        WidgetHost::set_rect(&mut p, x, y, w, h);
         p
     }
 
diff --git a/src/widget/display/progress_bar.rs b/src/widget/display/progress_bar.rs
index c3c10aa..ce68e67 100644
--- a/src/widget/display/progress_bar.rs
+++ b/src/widget/display/progress_bar.rs
@@ -1,4 +1,4 @@
-//! The first widget migrated off `Element` onto the narrow traits (Phase 5c). `ProgressBar`
+//! The first widget migrated off `WidgetHost` onto the narrow traits (Phase 5c). `ProgressBar`
 //! implements only [`Layout`] + [`Paint`] + [`Input`]; [`ProgressBar::new`] returns it already
 //! wrapped in [`Adapted`], so construction sites (`Box::new(ProgressBar::new(0.65))`, optionally
 //! `.with_label(..)`) are unchanged by the migration.
@@ -56,7 +56,7 @@ impl Input for ProgressBar {}
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::widget::{Element, UiContext};
+    use crate::widget::{WidgetHost, UiContext};
 
     /// The reverse bridge reproduces the legacy `all_rounded_quads` output: track quad at the
     /// content rect, fill quad at `w * value` with the radius clamped to half the height.
@@ -64,9 +64,9 @@ mod tests {
     fn reverse_bridge_matches_legacy_geometry() {
         let ctx = UiContext::new();
         let mut bar = ProgressBar::new(0.5);
-        Element::set_rect(&mut bar, 10.0, 20.0, 100.0, 8.0);
+        WidgetHost::set_rect(&mut bar, 10.0, 20.0, 100.0, 8.0);
 
-        let quads = Element::all_rounded_quads(&bar, &ctx);
+        let quads = WidgetHost::all_rounded_quads(&bar, &ctx);
         let radius = crate::layout::slider_corner_radius();
         assert_eq!(quads.len(), 2, "track + fill");
         assert_eq!(quads[0], (10.0, 20.0, 100.0, 8.0, radius, colors::progress_bg(), (true, true, true, true)));
@@ -81,13 +81,13 @@ mod tests {
     fn fill_clamps_to_track() {
         let ctx = UiContext::new();
         let mut over = ProgressBar::new(2.0);
-        Element::set_rect(&mut over, 0.0, 0.0, 100.0, 8.0);
-        let quads = Element::all_rounded_quads(&over, &ctx);
+        WidgetHost::set_rect(&mut over, 0.0, 0.0, 100.0, 8.0);
+        let quads = WidgetHost::all_rounded_quads(&over, &ctx);
         assert_eq!(quads[1].2, 100.0, "over-1 value fills the whole track");
 
         let mut empty = ProgressBar::new(0.0);
-        Element::set_rect(&mut empty, 0.0, 0.0, 100.0, 8.0);
-        assert_eq!(Element::all_rounded_quads(&empty, &ctx).len(), 1, "zero value emits track only");
+        WidgetHost::set_rect(&mut empty, 0.0, 0.0, 100.0, 8.0);
+        assert_eq!(WidgetHost::all_rounded_quads(&empty, &ctx).len(), 1, "zero value emits track only");
     }
 
     /// The detached-label convention survives the adapter: `set_rect` grows the widget by the
@@ -97,20 +97,20 @@ mod tests {
     fn label_inflates_rect_and_insets_paint() {
         let ctx = UiContext::new();
         let mut bar = ProgressBar::new(0.5).with_label("Progress");
-        Element::set_rect(&mut bar, 0.0, 10.0, 100.0, 8.0);
+        WidgetHost::set_rect(&mut bar, 0.0, 10.0, 100.0, 8.0);
 
-        let (_, y, _, h) = Element::rect(&bar);
+        let (_, y, _, h) = WidgetHost::rect(&bar);
         let offset = h - 8.0;
         assert!(offset >= 0.0, "rect grew by the label offset");
         assert_eq!(y, 10.0, "origin is unchanged");
 
-        let quads = Element::all_rounded_quads(&bar, &ctx);
+        let quads = WidgetHost::all_rounded_quads(&bar, &ctx);
         assert_eq!(quads[0].1, 10.0 + offset, "track is painted below the label region");
         assert_eq!(quads[0].3, 8.0, "track keeps the assigned height");
 
         // preferred_height forwards from the narrow intrinsic size.
-        assert_eq!(Element::preferred_height(&bar), Some(crate::layout::progressbar_height()));
+        assert_eq!(WidgetHost::preferred_height(&bar), Some(crate::layout::progressbar_height()));
         // Runtime type-name matching still sees "ProgressBar", not Adapted<..>.
-        assert_eq!(Element::type_name(&bar), "ProgressBar");
+        assert_eq!(WidgetHost::type_name(&bar), "ProgressBar");
     }
 }
diff --git a/src/widget/display/separator.rs b/src/widget/display/separator.rs
index 5bb38cb..b5cb77d 100644
--- a/src/widget/display/separator.rs
+++ b/src/widget/display/separator.rs
@@ -3,7 +3,7 @@
 //! callers position it via `set_rect`/`rect` (cce-status-interface's rotation loop was updated
 //! accordingly).
 
-use crate::widget::{Adapted, Element, Input, Layout, Paint};
+use crate::widget::{Adapted, WidgetHost, Input, Layout, Paint};
 
 #[derive(Debug, Clone)]
 pub struct Separator {
@@ -13,7 +13,7 @@ pub struct Separator {
 impl Separator {
     pub fn new(x: f32, y: f32, w: f32, h: f32, color: [f32; 4]) -> Adapted<Separator> {
         let mut sep = Adapted::new(Separator { color });
-        Element::set_rect(&mut sep, x, y, w, h);
+        WidgetHost::set_rect(&mut sep, x, y, w, h);
         sep
     }
 }
@@ -39,18 +39,18 @@ mod tests {
     #[test]
     fn constructor_places_the_rect_and_bridge_emits_it() {
         let sep = Separator::new(100.0, 0.0, 1.0, 24.0, [0.3, 0.3, 0.3, 1.0]);
-        assert_eq!(Element::rect(&sep), (100.0, 0.0, 1.0, 24.0));
-        assert_eq!(Element::color(&sep), [0.3, 0.3, 0.3, 1.0]);
-        assert_eq!(Element::extra_quads(&sep), vec![(100.0, 0.0, 1.0, 24.0, [0.3, 0.3, 0.3, 1.0])]);
-        assert!(!Element::blocks_backplate_drag(&sep));
+        assert_eq!(WidgetHost::rect(&sep), (100.0, 0.0, 1.0, 24.0));
+        assert_eq!(WidgetHost::color(&sep), [0.3, 0.3, 0.3, 1.0]);
+        assert_eq!(WidgetHost::extra_quads(&sep), vec![(100.0, 0.0, 1.0, 24.0, [0.3, 0.3, 0.3, 1.0])]);
+        assert!(!WidgetHost::blocks_backplate_drag(&sep));
     }
 
     /// The status bar's vertical-rotation pattern, post-migration: transpose via rect/set_rect.
     #[test]
     fn rotation_via_set_rect() {
         let mut sep = Separator::new(100.0, 0.0, 1.0, 24.0, [0.3, 0.3, 0.3, 1.0]);
-        let (x, y, w, h) = Element::rect(&sep);
-        Element::set_rect(&mut sep, y, x, h, w);
-        assert_eq!(Element::rect(&sep), (0.0, 100.0, 24.0, 1.0));
+        let (x, y, w, h) = WidgetHost::rect(&sep);
+        WidgetHost::set_rect(&mut sep, y, x, h, w);
+        assert_eq!(WidgetHost::rect(&sep), (0.0, 100.0, 24.0, 1.0));
     }
 }
diff --git a/src/widget/display/serialize.rs b/src/widget/display/serialize.rs
index fc0f9d7..9447648 100644
--- a/src/widget/display/serialize.rs
+++ b/src/widget/display/serialize.rs
@@ -1,6 +1,6 @@
 use crate::widget::*;
 
-fn serialize_single_widget(w: &dyn Element, json: &mut String) {
+fn serialize_single_widget(w: &dyn WidgetHost, json: &mut String) {
     let (x, y, width, height) = w.rect();
     let label = w.label().or_else(|| w.base().label.clone()).unwrap_or_default();
     let focused = w.base().focused;
@@ -24,7 +24,7 @@ fn serialize_single_widget(w: &dyn Element, json: &mut String) {
     let mut is_vertical = false;
     let mut checked_states = Vec::new();
     // Concrete capability lookup (Phase 6aw): the MenuController implementors a serialized
-    // roster can hold are Adapted<MenuBar> and Adapted<Paginator> — Element's discovery
+    // roster can hold are Adapted<MenuBar> and Adapted<Paginator> — WidgetHost's discovery
     // hooks are gone.
     let mc: Option<&dyn MenuController> = w
         .as_any()
@@ -84,7 +84,7 @@ fn serialize_single_widget(w: &dyn Element, json: &mut String) {
 
 /// Serialize the visible widgets' menu state. Takes dyn refs (not boxes): the designer's
 /// roster is concretely typed since the Phase 6bb retype and lends a per-slot dyn view.
-pub fn serialize_widgets(widgets: &[&dyn Element]) -> String {
+pub fn serialize_widgets(widgets: &[&dyn WidgetHost]) -> String {
     let mut json = String::new();
     json.push('[');
     let mut first = true;
diff --git a/src/widget/display/sidebar.rs b/src/widget/display/sidebar.rs
index 858bc6b..e7605a9 100644
--- a/src/widget/display/sidebar.rs
+++ b/src/widget/display/sidebar.rs
@@ -2,14 +2,14 @@
 //! x/y/w/h fields now live on the `Adapted` base.
 
 use crate::colors;
-use crate::widget::{Adapted, Element, Input, Layout, Paint};
+use crate::widget::{Adapted, WidgetHost, Input, Layout, Paint};
 
 pub struct Sidebar;
 
 impl Sidebar {
     pub fn new(w: f32) -> Adapted<Sidebar> {
         let mut s = Adapted::new(Sidebar);
-        Element::set_rect(&mut s, 0.0, 0.0, w, 0.0);
+        WidgetHost::set_rect(&mut s, 0.0, 0.0, w, 0.0);
         s
     }
 }
diff --git a/src/widget/display/splitter.rs b/src/widget/display/splitter.rs
index 2f18997..0bb57fd 100644
--- a/src/widget/display/splitter.rs
+++ b/src/widget/display/splitter.rs
@@ -4,7 +4,7 @@
 
 use crate::colors;
 use crate::scene::layout::Rect;
-use crate::widget::{Adapted, Element, ElementState, Event, EventCtx, Input, Layout, MouseButton, Paint};
+use crate::widget::{Adapted, WidgetHost, ElementState, Event, EventCtx, Input, Layout, MouseButton, Paint};
 
 pub struct Splitter {
     hovered: bool,
@@ -15,7 +15,7 @@ pub struct Splitter {
 impl Splitter {
     pub fn new(w: f32) -> Adapted<Splitter> {
         let mut s = Adapted::new(Splitter { hovered: false, dragging: false, drag_ox: 0.0 });
-        Element::set_rect(&mut s, 0.0, 0.0, w, 0.0);
+        WidgetHost::set_rect(&mut s, 0.0, 0.0, w, 0.0);
         s
     }
 }
diff --git a/src/widget/display/status_bar.rs b/src/widget/display/status_bar.rs
index 88b9c06..dac85c9 100644
--- a/src/widget/display/status_bar.rs
+++ b/src/widget/display/status_bar.rs
@@ -83,7 +83,7 @@ impl Adapted<StatusBar> {
 
 impl Layout for StatusBar {
     /// The status text draws inside the bar; the base label must never inflate the rect or
-    /// emit a detached label (`Element::set_text` writes both the base copy and
+    /// emit a detached label (`WidgetHost::set_text` writes both the base copy and
     /// [`Paint::sync_label`]).
     fn inline_label(&self) -> bool {
         true
@@ -107,7 +107,7 @@ impl Paint for StatusBar {
         Some((0.0, (false, false, false, false)))
     }
 
-    /// `Element::set_text` lands here: swap the text and drop the shaped buffer so
+    /// `WidgetHost::set_text` lands here: swap the text and drop the shaped buffer so
     /// `prepare_text` rebuilds it.
     fn sync_label(&mut self, label: &str) {
         if self.text != label {
@@ -159,7 +159,7 @@ impl Input for StatusBar {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::widget::Element;
+    use crate::widget::WidgetHost;
 
     /// The shaped-buffer lifecycle behind the old manual-host path: `set_text` drops the
     /// buffer, `prepare_text` rebuilds it. (The `get_text_items` getter that served it is
@@ -168,23 +168,23 @@ mod tests {
     fn manual_host_text_pipeline() {
         let mut fs = glyphon::FontSystem::new();
         let mut bar = StatusBar::new().with_text("hello").with_text_offset_x(15.0);
-        Element::set_rect(&mut bar, 0.0, 570.0, 800.0, 30.0);
+        WidgetHost::set_rect(&mut bar, 0.0, 570.0, 800.0, 30.0);
 
         assert!(bar.text_buf.is_none(), "no buffer before prepare_text");
-        Element::prepare_text(&mut bar, &mut fs);
+        WidgetHost::prepare_text(&mut bar, &mut fs);
         assert!(bar.text_buf.is_some(), "one shaped buffer");
 
         // set_text drops the stale buffer; prepare_text reshapes.
-        Element::set_text(&mut bar, "world");
+        WidgetHost::set_text(&mut bar, "world");
         assert!(bar.text_buf.is_none(), "buffer dropped on text change");
-        Element::prepare_text(&mut bar, &mut fs);
+        WidgetHost::prepare_text(&mut bar, &mut fs);
         assert!(bar.text_buf.is_some());
         assert_eq!(bar.text, "world");
 
         // Parentless: cornerless plain bg through the plain-quad bridge, at STATUS_BG.
-        let extra = Element::extra_quads(&bar);
+        let extra = WidgetHost::extra_quads(&bar);
         assert_eq!(extra.len(), 1, "cornerless bg quad");
-        assert_eq!(Element::corner_style(&bar).1, (false, false, false, false));
-        assert!(!Element::blocks_backplate_drag(&bar));
+        assert_eq!(WidgetHost::corner_style(&bar).1, (false, false, false, false));
+        assert!(!WidgetHost::blocks_backplate_drag(&bar));
     }
 }
diff --git a/src/widget/display/status_dot.rs b/src/widget/display/status_dot.rs
index 77f0c64..ecf62bf 100644
--- a/src/widget/display/status_dot.rs
+++ b/src/widget/display/status_dot.rs
@@ -1,6 +1,6 @@
 //! Narrow-trait status dot (Phase 5c leaf sweep).
 //!
-//! **Deliberate behavior fix:** the legacy `Element` impl only set `color()` and never emitted
+//! **Deliberate behavior fix:** the legacy `WidgetHost` impl only set `color()` and never emitted
 //! geometry on any render path (`all_quads` and `all_rounded_quads` were both empty for it, and
 //! `render_widget` never reads `color()` directly), so the dot was **invisible** — a probe test
 //! against the legacy widget confirmed zero rects emitted through `render_widget`. The narrow
@@ -56,18 +56,18 @@ impl Input for StatusDot {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::widget::{Element, UiContext};
+    use crate::widget::{WidgetHost, UiContext};
 
     #[test]
     fn emits_its_color_quad_through_the_bridge() {
         let mut dot = StatusDot::new(DotStatus::Warning);
-        Element::set_rect(&mut dot, 5.0, 6.0, 10.0, 10.0);
+        WidgetHost::set_rect(&mut dot, 5.0, 6.0, 10.0, 10.0);
         assert_eq!(
-            Element::extra_quads(&dot),
+            WidgetHost::extra_quads(&dot),
             vec![(5.0, 6.0, 10.0, 10.0, [0.90, 0.60, 0.10, 1.0])],
         );
         // Drags pass through, as legacy declared.
-        assert!(!Element::blocks_backplate_drag(&dot));
+        assert!(!WidgetHost::blocks_backplate_drag(&dot));
         // State mutation through Deref, as call sites write it.
         dot.set_status(DotStatus::Error);
         assert_eq!(dot.status, DotStatus::Error);
diff --git a/src/widget/display/usage_bar.rs b/src/widget/display/usage_bar.rs
index e8c6071..eeca0ad 100644
--- a/src/widget/display/usage_bar.rs
+++ b/src/widget/display/usage_bar.rs
@@ -55,23 +55,23 @@ impl Input for UsageBar {}
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::widget::Element;
+    use crate::widget::WidgetHost;
 
     /// Byte-identical to the legacy `extra_quads` override: full-width bg quad, then a fill quad
     /// scaled by the clamped value.
     #[test]
     fn bridge_matches_legacy_extra_quads() {
         let mut bar = UsageBar::new(0.5).with_colors([0.1, 0.2, 0.3, 1.0], [0.4, 0.5, 0.6, 1.0]);
-        Element::set_rect(&mut bar, 12.0, 30.0, 200.0, 8.0);
+        WidgetHost::set_rect(&mut bar, 12.0, 30.0, 200.0, 8.0);
         assert_eq!(
-            Element::extra_quads(&bar),
+            WidgetHost::extra_quads(&bar),
             vec![
                 (12.0, 30.0, 200.0, 8.0, [0.4, 0.5, 0.6, 1.0]),
                 (12.0, 30.0, 100.0, 8.0, [0.1, 0.2, 0.3, 1.0]),
             ],
         );
         // Nothing leaks onto the rounded path (apps read both getters).
-        assert!(Element::all_rounded_quads(&bar, &crate::widget::UiContext::new()).is_empty());
+        assert!(WidgetHost::all_rounded_quads(&bar, &crate::widget::UiContext::new()).is_empty());
     }
 
     #[test]
diff --git a/src/widget/input/button.rs b/src/widget/input/button.rs
index 2b635b7..8d6b8a5 100644
--- a/src/widget/input/button.rs
+++ b/src/widget/input/button.rs
@@ -8,7 +8,7 @@ use crate::colors;
 use crate::scene::layout::{Rect, Size};
 use crate::scene::paint::PaintCtx;
 use crate::widget::{
-    Adapted, Control, Element, ElementState, Event, EventCtx, Input, Justification, Layout,
+    Adapted, Control, WidgetHost, ElementState, Event, EventCtx, Input, Justification, Layout,
     MouseButton, Paint,
 };
 
@@ -68,7 +68,7 @@ impl Button {
 
     fn adapted(kind: ButtonKind, x: f32, y: f32, w: f32, h: f32) -> Adapted<Button> {
         let mut b = Adapted::new(Button::model(kind));
-        Element::set_rect(&mut b, x, y, w, h);
+        WidgetHost::set_rect(&mut b, x, y, w, h);
         b
     }
 
@@ -404,13 +404,13 @@ mod tests {
         // Press in, release in -> click.
         assert!(ctx.propagate_event(&press(20.0, 20.0), ptr));
         assert!(ctx.propagate_event(&release(25.0, 20.0), ptr), "release consumed (was pressed)");
-        assert!(Element::take_click(&mut b));
+        assert!(WidgetHost::take_click(&mut b));
         assert_eq!(fired.load(std::sync::atomic::Ordering::SeqCst), 1, "callback fired");
 
         // Press in, release OUT -> cancelled, no click, but release still consumed.
         assert!(ctx.propagate_event(&press(20.0, 20.0), ptr));
         assert!(ctx.propagate_event(&release(500.0, 500.0), ptr), "cancelling release consumed");
-        assert!(!Element::take_click(&mut b), "no click on out-of-rect release");
+        assert!(!WidgetHost::take_click(&mut b), "no click on out-of-rect release");
         assert_eq!(fired.load(std::sync::atomic::Ordering::SeqCst), 1, "callback not re-fired");
 
         // Release without a press is not consumed.
@@ -425,8 +425,8 @@ mod tests {
         let b = Button::new(0.0, 0.0, 100.0, 24.0).with_label("Go");
 
         let radius = crate::layout::button_corner_radius();
-        let rounded = Element::all_rounded_quads(&b, &ctx);
-        let plain = Element::extra_quads(&b);
+        let rounded = WidgetHost::all_rounded_quads(&b, &ctx);
+        let plain = WidgetHost::extra_quads(&b);
         if radius > 0.0 {
             assert!(!rounded.is_empty() && plain.is_empty(), "rounded config -> rounded path only");
             assert_eq!(rounded[0].4, radius);
@@ -440,9 +440,9 @@ mod tests {
         let est = b.label_width("Go");
         assert_eq!(labels[0].x, (100.0 - est) / 2.0, "center-justified");
 
-        // Selection state flows through the Element forward (list hosts push it).
+        // Selection state flows through the WidgetHost forward (list hosts push it).
         let mut b = b;
-        Element::set_selected(&mut b, true);
+        WidgetHost::set_selected(&mut b, true);
         assert!(b.selected);
     }
 }
diff --git a/src/widget/input/checkbox.rs b/src/widget/input/checkbox.rs
index d5d5aa0..fb450f6 100644
--- a/src/widget/input/checkbox.rs
+++ b/src/widget/input/checkbox.rs
@@ -1,4 +1,4 @@
-//! Narrow-trait `Checkbox` and `Toggle` (Phase 5e — first interactive widgets off `Element`).
+//! Narrow-trait `Checkbox` and `Toggle` (Phase 5e — first interactive widgets off `WidgetHost`).
 //!
 //! Both are inline-label widgets: they paint their own label (with hover/focus-dependent color)
 //! inside their rect, so they track `hovered`/`focused` themselves from the `MouseEnter`/
@@ -456,7 +456,7 @@ impl Control for Adapted<Toggle> {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::widget::{Element, UiContext};
+    use crate::widget::{WidgetHost, UiContext};
 
     fn click_at(x: f32, y: f32) -> Event {
         Event::MouseButton {
@@ -475,13 +475,13 @@ mod tests {
         let mut cb = Checkbox::new();
         let (id, ptr) = (cb.id(), cb.as_ptr_mut());
         ctx.register_widget(id, ptr);
-        Element::set_rect(&mut cb, 0.0, 0.0, 20.0, 20.0);
+        WidgetHost::set_rect(&mut cb, 0.0, 0.0, 20.0, 20.0);
 
         assert!(ctx.propagate_event(&click_at(10.0, 10.0), ptr), "in-rect click consumed");
         assert!(cb.checked(), "click checked it");
-        assert!(Element::take_click(&mut cb), "take_click reads once");
-        assert!(!Element::take_click(&mut cb), "...then clears");
-        assert!(Element::take_change(&mut cb));
+        assert!(WidgetHost::take_click(&mut cb), "take_click reads once");
+        assert!(!WidgetHost::take_click(&mut cb), "...then clears");
+        assert!(WidgetHost::take_change(&mut cb));
 
         assert!(!ctx.propagate_event(&click_at(100.0, 100.0), ptr), "miss is not consumed");
         assert!(cb.checked(), "miss does not toggle");
@@ -490,13 +490,13 @@ mod tests {
     #[test]
     fn checkbox_value_string_round_trip() {
         let mut cb = Checkbox::new();
-        assert_eq!(Element::get_value_string(&cb), Some("false".to_string()));
-        assert!(Element::set_value_string(&mut cb, "on"));
+        assert_eq!(WidgetHost::get_value_string(&cb), Some("false".to_string()));
+        assert!(WidgetHost::set_value_string(&mut cb, "on"));
         assert!(cb.checked());
-        assert_eq!(Element::value(&cb), 1);
-        assert!(!Element::set_value_string(&mut cb, "on"), "unchanged value reports false");
-        assert!(!Element::set_value_string(&mut cb, "junk"), "unparsable reports false");
-        assert!(Element::take_change(&mut cb), "set_value_string marked the change");
+        assert_eq!(WidgetHost::value(&cb), 1);
+        assert!(!WidgetHost::set_value_string(&mut cb, "on"), "unchanged value reports false");
+        assert!(!WidgetHost::set_value_string(&mut cb, "junk"), "unparsable reports false");
+        assert!(WidgetHost::take_change(&mut cb), "set_value_string marked the change");
     }
 
     /// Wide (labeled) mode reproduces the legacy `extra_quads` geometry through the bridge:
@@ -506,9 +506,9 @@ mod tests {
     fn checkbox_wide_mode_bridge_parity() {
         let ctx = UiContext::new();
         let mut cb = Checkbox::new().with_label("Enable");
-        Element::set_rect(&mut cb, 0.0, 0.0, 200.0, 24.0);
+        WidgetHost::set_rect(&mut cb, 0.0, 0.0, 200.0, 24.0);
 
-        let quads = Element::extra_quads(&cb);
+        let quads = WidgetHost::extra_quads(&cb);
         // Unchecked: box bg + 4 border edges = 5 quads, at the legacy box position.
         assert_eq!(quads.len(), 5);
         let (box_x, box_y, box_size) = (200.0 - 18.0 - 8.0, (24.0 - 18.0) / 2.0, 18.0);
@@ -516,7 +516,7 @@ mod tests {
 
         // Hover flips the box + border colors (tracked from MouseEnter, not base state).
         cb.inner_mut().hovered = true;
-        let quads = Element::extra_quads(&cb);
+        let quads = WidgetHost::extra_quads(&cb);
         assert_eq!(quads[0].4, colors::checkbox_hover());
 
         // Label text comes through the prim-derived text bridge at the legacy position.
@@ -526,7 +526,7 @@ mod tests {
         assert_eq!(labels[0].x, 8.0);
 
         // Inline label => no set_rect inflation.
-        assert_eq!(Element::rect(&cb), (0.0, 0.0, 200.0, 24.0));
+        assert_eq!(WidgetHost::rect(&cb), (0.0, 0.0, 200.0, 24.0));
         let _ = &ctx;
     }
 
@@ -536,32 +536,32 @@ mod tests {
         let mut t = Toggle::new();
         let (id, ptr) = (t.id(), t.as_ptr_mut());
         ctx.register_widget(id, ptr);
-        Element::set_rect(&mut t, 0.0, 0.0, 60.0, 30.0);
+        WidgetHost::set_rect(&mut t, 0.0, 0.0, 60.0, 30.0);
 
         // Geometry parity is config-dependent (rounded vs square toggle); assert the invariant
         // that holds in both: the bordered half flips with the state.
-        let before: Vec<_> = Element::all_rounded_quads(&t, &ctx);
-        let before_quads = Element::extra_quads(&t);
+        let before: Vec<_> = WidgetHost::all_rounded_quads(&t, &ctx);
+        let before_quads = WidgetHost::extra_quads(&t);
 
         assert!(ctx.propagate_event(&click_at(30.0, 15.0), ptr), "toggle consumed the click");
         assert!(t.toggled());
-        assert!(Element::take_click(&mut t));
+        assert!(WidgetHost::take_click(&mut t));
 
-        let after: Vec<_> = Element::all_rounded_quads(&t, &ctx);
-        let after_quads = Element::extra_quads(&t);
+        let after: Vec<_> = WidgetHost::all_rounded_quads(&t, &ctx);
+        let after_quads = WidgetHost::extra_quads(&t);
         assert!(
             before != after || before_quads != after_quads,
             "toggling changes the emitted geometry (border switches halves)",
         );
 
         // preferred_height forwards the legacy toggle height.
-        assert_eq!(Element::preferred_height(&t), Some(crate::layout::toggle_height()));
+        assert_eq!(WidgetHost::preferred_height(&t), Some(crate::layout::toggle_height()));
     }
 
     #[test]
     fn toggle_set_label_via_deref_reaches_paint() {
         let mut t = Toggle::new();
-        Element::set_rect(&mut t, 0.0, 0.0, 60.0, 30.0);
+        WidgetHost::set_rect(&mut t, 0.0, 0.0, 60.0, 30.0);
         t.set_label("ON"); // the network.rs pattern: live label updates through Deref
         let labels = t.own_text_labels();
         assert_eq!(labels.len(), 1);
diff --git a/src/widget/input/dropdown.rs b/src/widget/input/dropdown.rs
index bc917d4..388db80 100644
--- a/src/widget/input/dropdown.rs
+++ b/src/widget/input/dropdown.rs
@@ -5,7 +5,7 @@
 //!
 //! Parity notes (all legacy-faithful, verified against the pre-migration impl):
 //! - `parent_snapshot` is the data form of the legacy public, direct-write-only `parent`
-//!   pointer: legacy `set_parent` never wrote it (the Element default only touched the tree —
+//!   pointer: legacy `set_parent` never wrote it (the WidgetHost default only touched the tree —
 //!   Ramp's dummy-ctx `set_parent` calls were silently discarded), so the Ramp popover clamp
 //!   and the fade-blend parent color activate only for callers that assign the field, exactly
 //!   as before — no production writer exists. The backplate-concentric corner walk it once
@@ -13,14 +13,14 @@
 //! - The row-rect hit expansion (`base.row_x/row_w`) is dropped, consistent with every other
 //!   migrated control: `Input::hit` tests the widget rect plus the open popover.
 //! - `Layout::intrinsic_measure_width` (new hook) preserves the `auto_width` measure behavior
-//!   (cce-system-settings sizes its page dropdown from `Element::measure`).
+//!   (cce-system-settings sizes its page dropdown from `WidgetHost::measure`).
 
 use crate::colors;
 use crate::scene::layout::{Rect, Size};
 use crate::scene::paint::PaintCtx;
 use crate::widget::model::{Adapted, EventCtx, Input, Layout, Paint};
 use crate::widget::{
-    Control, Element, ElementState, Event, Key, MouseButton, NamedKey,
+    Control, WidgetHost, ElementState, Event, Key, MouseButton, NamedKey,
 };
 
 /// Read-data stand-in for the legacy direct-write `parent` pointer (6bd — no stored widget
@@ -34,7 +34,7 @@ pub struct ParentSnapshot {
     pub color: [f32; 4],
 }
 
-/// Side-layout label inset — the legacy `Element::label_x_offset` default for non-exempt
+/// Side-layout label inset — the legacy `WidgetHost::label_x_offset` default for non-exempt
 /// widgets (Dropdown was never in the exempt list).
 fn side_offset(label: &Option<String>) -> f32 {
     if crate::layout::control_label_layout() == "side" && label.is_some() {
@@ -519,7 +519,7 @@ impl Adapted<Dropdown> {
     /// Popover geometry from the widget's laid-out rect — the legacy inherent
     /// `get_popover_geom` shape, for callers that hold the wrapper.
     pub fn get_popover_geom(&self) -> (f32, f32, f32, f32) {
-        let (x, y, w, h) = Element::rect(self);
+        let (x, y, w, h) = WidgetHost::rect(self);
         let top = self.inner().label_top();
         self.inner().popover_geom(Rect { x, y: y + top, width: w, height: h - top })
     }
@@ -936,9 +936,9 @@ mod tests {
 
         // Link the dropdown to the Ramp's read-data (the legacy direct-write path)
         dd.parent_snapshot = Some(ParentSnapshot {
-            rect: crate::widget::Element::rect(&ramp),
+            rect: crate::widget::WidgetHost::rect(&ramp),
             is_ramp: true,
-            color: crate::widget::Element::color(&ramp),
+            color: crate::widget::WidgetHost::color(&ramp),
         });
 
         // Compute geometry
@@ -1008,7 +1008,7 @@ mod tests {
         );
     }
 
-    /// Migration additions: popover routing through the adapter (`Element::popover_rect` /
+    /// Migration additions: popover routing through the adapter (`WidgetHost::popover_rect` /
     /// `render_popover`), outside-press close, and Escape via routed key events.
     #[test]
     fn popover_reaches_hosts_through_the_adapter() {
@@ -1017,11 +1017,11 @@ mod tests {
         let mut dd = Dropdown::new(options, 0);
         dd.set_rect(10.0, 10.0, 100.0, 24.0);
 
-        assert!(Element::popover_rect(&dd).is_none(), "closed dropdown registers no popover");
+        assert!(WidgetHost::popover_rect(&dd).is_none(), "closed dropdown registers no popover");
 
         dd.mouse_input(MouseButton::Left, ElementState::Pressed, 50.0, 20.0, &mut dummy);
         assert!(dd.open);
-        let (rx, ry, rw, rh) = Element::popover_rect(&dd).expect("open dropdown registers its popover");
+        let (rx, ry, rw, rh) = WidgetHost::popover_rect(&dd).expect("open dropdown registers its popover");
         assert_eq!((rx, ry), (10.0, 34.0), "popover opens under the trigger");
         assert!(rw >= 100.0 && rh == 48.0);
 
diff --git a/src/widget/input/slider.rs b/src/widget/input/slider.rs
index e3bbdc7..99b4c1c 100644
--- a/src/widget/input/slider.rs
+++ b/src/widget/input/slider.rs
@@ -688,50 +688,50 @@ impl Control for Adapted<RangeSlider> {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::widget::{Element, UiContext};
+    use crate::widget::{WidgetHost, UiContext};
 
-    /// The legacy rangeslider interaction test, driven through the Element drag forwards
+    /// The legacy rangeslider interaction test, driven through the WidgetHost drag forwards
     /// (hosts call these directly): thumb selection by proximity, constrained updates.
     #[test]
     fn rangeslider_interaction() {
         let mut rs = RangeSlider::new();
-        Element::set_rect(&mut rs, 10.0, 10.0, 200.0, 20.0);
+        WidgetHost::set_rect(&mut rs, 10.0, 10.0, 200.0, 20.0);
         assert_eq!(rs.values(), (0.2, 0.8));
 
         // Thumb size 18, range 182; low center = 55.4.
-        Element::drag_begin(&mut rs, 55.4, 20.0);
+        WidgetHost::drag_begin(&mut rs, 55.4, 20.0);
         assert_eq!(rs.active_thumb, Some(ActiveThumb::Low));
-        assert!(Element::drag_update(&mut rs, 100.9, 20.0));
+        assert!(WidgetHost::drag_update(&mut rs, 100.9, 20.0));
         assert!((rs.values().0 - 0.45).abs() < 0.01);
         assert_eq!(rs.values().1, 0.8);
-        Element::drag_end(&mut rs);
+        WidgetHost::drag_end(&mut rs);
         assert_eq!(rs.active_thumb, None);
 
         // High thumb 0.8 -> 0.6.
-        Element::drag_begin(&mut rs, 164.6, 20.0);
+        WidgetHost::drag_begin(&mut rs, 164.6, 20.0);
         assert_eq!(rs.active_thumb, Some(ActiveThumb::High));
-        assert!(Element::drag_update(&mut rs, 128.2, 20.0));
+        assert!(WidgetHost::drag_update(&mut rs, 128.2, 20.0));
         assert!((rs.values().1 - 0.6).abs() < 0.01);
-        Element::drag_end(&mut rs);
+        WidgetHost::drag_end(&mut rs);
     }
 
     #[test]
     fn rangeslider_overlap_and_constraint() {
         let mut rs = RangeSlider::new().with_values(0.5, 0.5);
-        Element::set_rect(&mut rs, 10.0, 10.0, 200.0, 20.0);
+        WidgetHost::set_rect(&mut rs, 10.0, 10.0, 200.0, 20.0);
 
-        Element::drag_begin(&mut rs, 109.0, 20.0);
+        WidgetHost::drag_begin(&mut rs, 109.0, 20.0);
         assert_eq!(rs.active_thumb, Some(ActiveThumb::Low));
-        Element::drag_end(&mut rs);
+        WidgetHost::drag_end(&mut rs);
 
-        Element::drag_begin(&mut rs, 111.0, 20.0);
+        WidgetHost::drag_begin(&mut rs, 111.0, 20.0);
         assert_eq!(rs.active_thumb, Some(ActiveThumb::High));
-        Element::drag_end(&mut rs);
+        WidgetHost::drag_end(&mut rs);
 
-        Element::drag_begin(&mut rs, 110.0, 20.0);
-        Element::drag_update(&mut rs, 150.0, 20.0);
+        WidgetHost::drag_begin(&mut rs, 110.0, 20.0);
+        WidgetHost::drag_update(&mut rs, 150.0, 20.0);
         assert_eq!(rs.values().0, 0.5, "low constrained to high");
-        Element::drag_end(&mut rs);
+        WidgetHost::drag_end(&mut rs);
     }
 
 #[test]
@@ -740,10 +740,10 @@ fn probe_slider_bridge() {
     
     let ctx = UiContext::new();
     let mut sl = Slider::new().with_label("Slider");
-    Element::set_rect(&mut sl, 20.0, 220.0, 200.0, 40.0);
-    eprintln!("rect         = {:?}", Element::rect(&sl));
-    eprintln!("extra_quads  = {:?}", Element::extra_quads(&sl));
-    eprintln!("rounded      = {:?}", Element::all_rounded_quads(&sl, &ctx));
+    WidgetHost::set_rect(&mut sl, 20.0, 220.0, 200.0, 40.0);
+    eprintln!("rect         = {:?}", WidgetHost::rect(&sl));
+    eprintln!("extra_quads  = {:?}", WidgetHost::extra_quads(&sl));
+    eprintln!("rounded      = {:?}", WidgetHost::all_rounded_quads(&sl, &ctx));
     eprintln!("labels       = {:?}", sl.own_text_labels().iter().map(|l| l.text.clone()).collect::<Vec<_>>());
 }
 
@@ -755,22 +755,22 @@ fn probe_slider_bridge() {
         let mut sl = Slider::new().with_value(0.5);
         let (id, ptr) = (sl.id(), sl.as_ptr_mut());
         ctx.register_widget(id, ptr);
-        Element::set_rect(&mut sl, 0.0, 0.0, 100.0, 20.0);
+        WidgetHost::set_rect(&mut sl, 0.0, 0.0, 100.0, 20.0);
 
         // Press on the track grabs the thumb.
         assert!(ctx.propagate_event(
             &Event::MouseButton { button: MouseButton::Left, state: ElementState::Pressed, x: 50.0, y: 10.0, local_x: 50.0, local_y: 10.0 },
             ptr,
         ));
-        assert!(Element::is_dragging(&sl));
-        assert!(Element::drag_update(&mut sl, 80.0, 10.0));
+        assert!(WidgetHost::is_dragging(&sl));
+        assert!(WidgetHost::drag_update(&mut sl, 80.0, 10.0));
         assert!(sl.inner().value() > 0.5);
-        Element::drag_end(&mut sl);
+        WidgetHost::drag_end(&mut sl);
 
         // Wheel adjusts value when the gesture starts fresh.
         ctx.scroll_gesture_new = true;
         let before = sl.inner().value();
-        assert!(Element::mouse_wheel(
+        assert!(WidgetHost::mouse_wheel(
             &mut sl,
             &MouseScrollDelta::LineDelta(0.0, 1.0),
             50.0,
@@ -778,6 +778,6 @@ fn probe_slider_bridge() {
             &mut ctx,
         ));
         assert!(sl.inner().value() < before, "scroll up decreases value");
-        assert!(Element::take_change(&mut sl));
+        assert!(WidgetHost::take_change(&mut sl));
     }
 }
diff --git a/src/widget/input/spinbox.rs b/src/widget/input/spinbox.rs
index 30549cf..023c254 100644
--- a/src/widget/input/spinbox.rs
+++ b/src/widget/input/spinbox.rs
@@ -440,7 +440,7 @@ impl Control for Adapted<Spinbox> {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::widget::{Element, UiContext};
+    use crate::widget::{WidgetHost, UiContext};
 
     #[test]
     fn spinbox_button_zones_step_the_value() {
@@ -448,24 +448,24 @@ mod tests {
         let mut sb = Spinbox::new(0, -100, 100, 1);
         let (id, ptr) = (sb.id(), sb.as_ptr_mut());
         ctx.register_widget(id, ptr);
-        Element::set_rect(&mut sb, 10.0, 20.0, 100.0, 26.0);
+        WidgetHost::set_rect(&mut sb, 10.0, 20.0, 100.0, 26.0);
 
         // Legacy test: click at (75, 33) lands in the decrement zone.
-        assert!(Element::mouse_input(&mut sb, MouseButton::Left, ElementState::Pressed, 75.0, 33.0, &mut ctx));
+        assert!(WidgetHost::mouse_input(&mut sb, MouseButton::Left, ElementState::Pressed, 75.0, 33.0, &mut ctx));
         assert_eq!(sb.value, -1);
-        assert!(Element::take_change(&mut sb));
+        assert!(WidgetHost::take_change(&mut sb));
 
         // Increment zone (past 77.5% of the width).
-        assert!(Element::mouse_input(&mut sb, MouseButton::Left, ElementState::Pressed, 92.0, 33.0, &mut ctx));
+        assert!(WidgetHost::mouse_input(&mut sb, MouseButton::Left, ElementState::Pressed, 92.0, 33.0, &mut ctx));
         assert_eq!(sb.value, 0);
     }
 
     #[test]
     fn spinbox_value_string_decimals_round_trip() {
         let mut sb = Spinbox::new(150, 0, 1000, 5).with_decimals(2);
-        assert_eq!(Element::get_value_string(&sb), Some("1.50".to_string()));
-        assert!(Element::set_value_string(&mut sb, "2.75"));
+        assert_eq!(WidgetHost::get_value_string(&sb), Some("1.50".to_string()));
+        assert!(WidgetHost::set_value_string(&mut sb, "2.75"));
         assert_eq!(sb.value, 275);
-        assert_eq!(Element::value(&sb), 275);
+        assert_eq!(WidgetHost::value(&sb), 275);
     }
 }
diff --git a/src/widget/input/text_box.rs b/src/widget/input/text_box.rs
index 7b0987e..2963b98 100644
--- a/src/widget/input/text_box.rs
+++ b/src/widget/input/text_box.rs
@@ -1,6 +1,6 @@
 //! Narrow-trait `TextBox` (Phase 5q). The widest-surface leaf so far: real selection-aware
 //! clipboard (the new `Input` cut/copy/paste/select-all/clear hooks — their defaults replicate
-//! the whole-value `Element` defaults for everyone else), load-bearing glyph shaping through
+//! the whole-value `WidgetHost` defaults for everyone else), load-bearing glyph shaping through
 //! `Paint::prepare_text` (cursor↔pixel mapping reads the measured advances), the row-hit
 //! restoration (`Layout::hit_row_rect` — cce-files' save-name box relies on row hits), a
 //! width/max-width clamp on both rect paths (`Layout::adjust_rect` + `adjust_row_rect`), the
@@ -35,7 +35,7 @@ pub fn get_font_db() -> &'static resvg::usvg::fontdb::Database {
     })
 }
 
-/// Side-layout label inset — the legacy `Element::label_x_offset` default for non-exempt
+/// Side-layout label inset — the legacy `WidgetHost::label_x_offset` default for non-exempt
 /// widgets (TextBox was never in the exempt list).
 fn side_offset(label: &Option<String>) -> f32 {
     if crate::layout::control_label_layout() == "side" && label.is_some() {
@@ -1644,7 +1644,7 @@ mod tests {
         tb.select_anchor = Some(7); // starts at "Line 2"
         tb.cursor_idx = 13;        // ends at end of "Line 2"
 
-        let has_rounded = Element::corner_style(&tb).1 != (false, false, false, false);
+        let has_rounded = WidgetHost::corner_style(&tb).1 != (false, false, false, false);
         let has_highlight = if has_rounded {
             let rounded = tb.all_rounded_quads(&dummy);
             println!("Rounded quads: {:?}", rounded);
@@ -1694,7 +1694,7 @@ mod tests {
         assert!(opts.contains(&"Cear".to_string()));
 
         // Simulate choosing the "Cear" option
-        Element::context_action(&mut tb, crate::widget::ContextAction::ClearText);
+        WidgetHost::context_action(&mut tb, crate::widget::ContextAction::ClearText);
         assert_eq!(tb.text, "");
         assert_eq!(tb.edit_buffer, "");
     }
diff --git a/src/widget/layout_helper.rs b/src/widget/layout_helper.rs
index 21b5629..d29eb08 100644
--- a/src/widget/layout_helper.rs
+++ b/src/widget/layout_helper.rs
@@ -1,4 +1,4 @@
-use crate::widget::Element;
+use crate::widget::WidgetHost;
 
 pub struct ColumnLayout {
     pub x: f32,
@@ -21,14 +21,14 @@ impl ColumnLayout {
         }
     }
 
-    pub fn add_widget(&mut self, widget: &mut dyn Element, height: f32) {
+    pub fn add_widget(&mut self, widget: &mut dyn WidgetHost, height: f32) {
         let label_off = widget.base().label_offset();
         let total_h = height + label_off;
         widget.set_rect(self.x + self.margin, self.current_y, self.width - 2.0 * self.margin, height);
         self.current_y += total_h + self.gap;
     }
 
-    pub fn add_row(&mut self, widgets: &[*mut dyn Element], height: f32, gap: f32) {
+    pub fn add_row(&mut self, widgets: &[*mut dyn WidgetHost], height: f32, gap: f32) {
         let count = widgets.len();
         if count == 0 {
             return;
@@ -81,7 +81,7 @@ impl RowLayout {
         }
     }
 
-    pub fn add_widget(&mut self, widget: &mut dyn Element, width: f32) {
+    pub fn add_widget(&mut self, widget: &mut dyn WidgetHost, width: f32) {
         widget.set_rect(self.current_x, self.y + self.margin, width, self.height - 2.0 * self.margin);
         self.current_x += width + self.gap;
     }
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index b13c842..9484c36 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -76,7 +76,7 @@ pub enum Justification {
 }
 
 /// A context-menu action dispatched on the menu's target widget (6bd phase 1: one enum
-/// replaces the 13 per-action `Element` methods). `ClearText` is the search-box "Cear" item.
+/// replaces the 13 per-action `WidgetHost` methods). `ClearText` is the search-box "Cear" item.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum ContextAction {
     Cut,
@@ -112,19 +112,19 @@ pub struct LayoutTree {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub struct WidgetPtr(pub *mut (dyn Element + 'static));
+pub struct WidgetPtr(pub *mut (dyn WidgetHost + 'static));
 
 impl WidgetPtr {
     pub fn is_null(&self) -> bool {
         self.0.is_null()
     }
-    pub fn as_ptr(&self) -> *mut (dyn Element + 'static) {
+    pub fn as_ptr(&self) -> *mut (dyn WidgetHost + 'static) {
         self.0
     }
 }
 
 impl std::ops::Deref for WidgetPtr {
-    type Target = dyn Element + 'static;
+    type Target = dyn WidgetHost + 'static;
     fn deref(&self) -> &Self::Target {
         assert!(!self.0.is_null(), "Attempted to dereference a null WidgetPtr!");
         unsafe { &*self.0 }
@@ -187,7 +187,13 @@ pub struct Size {
     pub height: f32,
 }
 
-pub trait Element {
+/// The single host surface every widget presents to the machinery (context routing, the
+/// paint walk, the render loop, app dyn broadcasts). **Formerly `Element`**, the ~125-method
+/// god-trait — renamed at the 6bd flip once census-driven shrink batches brought it down to
+/// the measured blueprint. `Adapted<W>` is the one production implementor; concrete behavior
+/// lives on the narrow `Layout`/`Paint`/`Input` traits it wraps. The direct-dispatch and
+/// value blocks shrink further as apps move to routed events / concrete slots.
+pub trait WidgetHost {
     /// The widget's shared base state — GUARANTEED (the flip): the `Option` escape hatch
     /// and its `WidgetId(0)` sentinel class are gone. `Adapted` (the one production
     /// implementor) always owns a base; test shims carry one via `impl_widget_base!`.
@@ -214,8 +220,8 @@ pub trait Element {
     // stand-ins nothing could legitimately use. `impl_widget_base!` provides all four.
     fn as_any(&self) -> &dyn std::any::Any;
     fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
-    fn as_ptr(&self) -> *mut (dyn Element + 'static);
-    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static);
+    fn as_ptr(&self) -> *mut (dyn WidgetHost + 'static);
+    fn as_ptr_mut(&mut self) -> *mut (dyn WidgetHost + 'static);
 
     fn handle_event(&mut self, event: &Event, ctx: &mut UiContext) -> bool {
         match event {
@@ -518,7 +524,7 @@ pub trait Element {
     fn is_child_visible(&self, _child_id: WidgetId) -> bool { true }
     fn set_modifiers(&mut self, _ctrl: bool, _shift: bool, _alt: bool) {}
 
-    fn parent(&self, ctx: &UiContext) -> Option<*mut (dyn Element + 'static)> {
+    fn parent(&self, ctx: &UiContext) -> Option<*mut (dyn WidgetHost + 'static)> {
         ctx.tree.parent_ptr(self.base().id())
     }
 
@@ -527,7 +533,7 @@ pub trait Element {
     // operation — concrete callers ride the inherent `Adapted` methods, dyn callers go
     // through `focus::link_parent_child` or `ctx.tree` directly.
 
-    fn children(&self, ctx: &UiContext) -> Vec<*mut (dyn Element + 'static)> {
+    fn children(&self, ctx: &UiContext) -> Vec<*mut (dyn WidgetHost + 'static)> {
         ctx.tree.children_ptrs(self.base().id())
     }
 
@@ -554,7 +560,7 @@ pub trait Element {
     }
 }
 
-pub trait Control: Element {
+pub trait Control: WidgetHost {
     fn set_label(&mut self, label: &str) {
         self.base_mut().label = Some(label.to_string());
     }
@@ -690,7 +696,7 @@ pub trait GeomController {
     fn take_geom_toggle(&mut self) -> bool;
 }
 
-pub fn label_offset(w: &dyn Element) -> f32 {
+pub fn label_offset(w: &dyn WidgetHost) -> f32 {
     let name = w.type_name();
     if name == "Label" || name == "Button" || name == "Checkbox" || name == "Toggle" {
         return 0.0;
diff --git a/src/widget/model.rs b/src/widget/model.rs
index 7e5708b..22a14d7 100644
--- a/src/widget/model.rs
+++ b/src/widget/model.rs
@@ -1,26 +1,26 @@
-//! Narrow, single-concern widget traits + an adapter into the legacy `Element` tree — Phase 5 of
+//! Narrow, single-concern widget traits + an adapter into the legacy `WidgetHost` tree — Phase 5 of
 //! the core rebuild (see `docs/rfc-core-rebuild.md` §3.5 and §5).
 //!
-//! Phase 5 replaces the ~123-method [`Element`] god-trait with small traits, one per concern. A
-//! *non-breaking supertrait carve-out* of `Element` is not possible in Rust, for two reasons found
+//! Phase 5 replaces the ~123-method [`WidgetHost`] god-trait with small traits, one per concern. A
+//! *non-breaking supertrait carve-out* of `WidgetHost` is not possible in Rust, for two reasons found
 //! by experiment:
 //!
 //! 1. The structural methods the layout/paint passes need (`rect`, `children`, `set_rect`, …) are
 //!    overridden in dozens of widgets across cce-ui **and** the app crates. Moving them off
-//!    `Element` breaks every override; merely *declaring* them on a supertrait breaks every call
+//!    `WidgetHost` breaks every override; merely *declaring* them on a supertrait breaks every call
 //!    site too, because a supertrait method is always in scope on the subtrait — `elem.children()`
-//!    on a `&dyn Element` becomes ambiguous.
+//!    on a `&dyn WidgetHost` becomes ambiguous.
 //! 2. Trait-object coercion does not offer a way around it: a blanket "view" impl
-//!    `impl<T: Element> Paint for T` does **not** let `&dyn Element` coerce to `&dyn Paint`
+//!    `impl<T: WidgetHost> Paint for T` does **not** let `&dyn WidgetHost` coerce to `&dyn Paint`
 //!    (that coercion only exists for real supertraits).
 //!
 //! So we take the RFC's recommended **adapter** path. The traits here — [`Layout`] and [`Paint`] —
-//! are *independent* of `Element` (no super/sub relationship). A widget written against them is
-//! placed into the existing `*mut dyn Element` tree by wrapping it in [`Adapted`], whose `Element`
+//! are *independent* of `WidgetHost` (no super/sub relationship). A widget written against them is
+//! placed into the existing `*mut dyn WidgetHost` tree by wrapping it in [`Adapted`], whose `WidgetHost`
 //! impl forwards each legacy method to the matching narrow-trait method and supplies the
-//! [`Widget`] base that `Element`'s rect/id/dirty machinery reads. Existing `impl Element` widgets
+//! [`Widget`] base that `WidgetHost`'s rect/id/dirty machinery reads. Existing `impl WidgetHost` widgets
 //! are untouched; new or migrated widgets implement only the concern traits they need; both kinds
-//! coexist in one tree. When the last widget is migrated, `Element` and this adapter are deleted.
+//! coexist in one tree. When the last widget is migrated, `WidgetHost` and this adapter are deleted.
 //!
 //! This commit lands the two concerns the scene passes already consume: [`Layout`] drives
 //! [`crate::scene::bridge`] and [`Paint`] drives [`crate::scene::painter`]. The input/event
@@ -29,7 +29,7 @@
 use crate::scene::layout::{Rect, Size};
 use crate::scene::paint::{PaintCtx, Prim};
 use crate::widget::{
-    Element, Event, TextLabel, UiContext, Widget, WidgetId,
+    WidgetHost, Event, TextLabel, UiContext, Widget, WidgetId,
 };
 
 /// Layout inputs for the scene layout engine — the RFC's `Widget` concern, named `Layout` here to
@@ -63,24 +63,24 @@ pub trait Layout {
         0.0
     }
 
-    /// Whether `Element::measure` should prefer [`intrinsic_size`](Layout::intrinsic_size)'s
+    /// Whether `WidgetHost::measure` should prefer [`intrinsic_size`](Layout::intrinsic_size)'s
     /// width over the current rect width (Dropdown's `auto_width` measure override — hosts size
     /// it from `measure`, e.g. cce-system-settings' page dropdown). Default: keep the legacy
-    /// `Element::measure` width (the current rect's).
+    /// `WidgetHost::measure` width (the current rect's).
     fn intrinsic_measure_width(&self) -> bool {
         false
     }
 
     /// Whether the adapter's hit test substitutes the base row rect (`row_x`/`row_w`, pushed in
     /// by row-layout hosts via `set_row_rect`) plus the side-label inset — the legacy
-    /// `Element::hit_test` default geometry. Migrated controls so far dropped it (accepted
+    /// `WidgetHost::hit_test` default geometry. Migrated controls so far dropped it (accepted
     /// drift); TextBox restores it (cce-files' save-name box relies on row hits). Default: off,
     /// keeping the other migrated widgets exactly as they shipped.
     fn hit_row_rect(&self) -> bool {
         false
     }
 
-    /// Adjust a row-rect assignment before it lands on the base (`Element::set_row_rect` —
+    /// Adjust a row-rect assignment before it lands on the base (`WidgetHost::set_row_rect` —
     /// TextBox clamps the row width to its `width`/`max_width`). Default: identity.
     fn adjust_row_rect(&self, x: f32, w: f32) -> (f32, f32) {
         (x, w)
@@ -92,14 +92,14 @@ pub trait Layout {
     /// re-clamps its scroll, the legacy `set_rect` side effect. Default: ignore.
     fn rect_assigned(&mut self, _rect: Rect) {}
 
-    // --- Container concern (transitional). Legacy containers own `Vec<*mut dyn Element>`
+    // --- Container concern (transitional). Legacy containers own `Vec<*mut dyn WidgetHost>`
     // children (child-arranging `set_rect` has no ctx to reach the tree) and every one
     // hand-copies the same subtree plumbing: geometry/text aggregation, tick/popover/text-item
     // recursion, hit-through-children. A migrated container keeps the pointer Vec in its model
     // (exposed through these hooks) and the ADAPTER does the shared plumbing once, filtered by
     // `child_visible`. What stays per-widget: child arrangement (`arrange_children` /
     // `layout_children_ctx`) and any event proxying (in `on_event`, via `EventCtx::ui`).
-    // Dies with `Element`: the arena owns the tree and the scene walk owns recursion.
+    // Dies with `WidgetHost`: the arena owns the tree and the scene walk owns recursion.
 
     /// Whether this widget is a container serving
     /// [`container_children`](Layout::container_children). Cheap gate, checked per getter.
@@ -108,7 +108,7 @@ pub trait Layout {
     }
 
     /// The container's child pointers, in stacking order.
-    fn container_children(&self) -> Vec<*mut (dyn Element + 'static)> {
+    fn container_children(&self) -> Vec<*mut (dyn WidgetHost + 'static)> {
         Vec::new()
     }
 
@@ -120,17 +120,17 @@ pub trait Layout {
 
     /// Position children after a `set_rect` (no ctx available — use the owned pointers).
     /// Called only while the widget is visible, matching the legacy overrides. `host` is the
-    /// adapter's `*mut dyn Element` — widgets that embed a legacy child (MenuBar's
+    /// adapter's `*mut dyn WidgetHost` — widgets that embed a legacy child (MenuBar's
     /// ButtonStrip) parent it back to the host so legacy parent-chain styling walks work.
-    fn arrange_children(&mut self, _rect: Rect, _host: *mut (dyn Element + 'static)) {}
+    fn arrange_children(&mut self, _rect: Rect, _host: *mut (dyn WidgetHost + 'static)) {}
 
     /// Per-child visibility policy for the adapter's subtree plumbing (Switcher exposes only
     /// the active child). Default: every child.
-    fn child_visible(&self, _child: *mut (dyn Element + 'static)) -> bool {
+    fn child_visible(&self, _child: *mut (dyn WidgetHost + 'static)) -> bool {
         true
     }
 
-    /// Legacy `Element::z_index` (host render ordering; MenuBar's dropdowns layer at 100+).
+    /// Legacy `WidgetHost::z_index` (host render ordering; MenuBar's dropdowns layer at 100+).
     fn z_order(&self) -> i32 {
         0
     }
@@ -141,13 +141,13 @@ pub trait Layout {
     /// `Vec` reallocation) — and the registration is load-bearing: the spatial grid is rebuilt
     /// from registered widgets, and it is the registered ButtonStrip (whose
     /// `blocks_backplate_drag` is true) that makes the sidebar block backplate drags. The
-    /// adapter calls this from `Element::tick` and `Element::layout`, mirroring the legacy
+    /// adapter calls this from `WidgetHost::tick` and `WidgetHost::layout`, mirroring the legacy
     /// cadence. `host_id` is the adapter's id, for `link_ids`. Default: nothing embedded.
     fn register_embedded_children(&mut self, _host_id: WidgetId, _ctx: &mut UiContext) {}
 }
 
 /// The paint concern — a widget's fill color, its own (non-recursive) geometry emission, and
-/// whether it clips its children. Mirrors `Element::color` / `paint_self` / `clips_children`, but
+/// whether it clips its children. Mirrors `WidgetHost::color` / `paint_self` / `clips_children`, but
 /// [`paint`](Paint::paint) receives the laid-out `rect` as a parameter (the RFC shape) rather than
 /// reading a stored rect, so a narrow widget carries no base of its own.
 pub trait Paint {
@@ -175,7 +175,7 @@ pub trait Paint {
     /// laid-out rect (MenuBar's corners depend on where it sits against its parent's edges).
     /// **Transitional:** this exists only for legacy render paths that draw widget backgrounds
     /// themselves from style properties (`widget_vertices` / `push_widget_vertices` readers of
-    /// `Element::corner_radius` + `rounded_corners`) — the widget's real geometry is whatever
+    /// `WidgetHost::corner_radius` + `rounded_corners`) — the widget's real geometry is whatever
     /// [`paint`](Paint::paint) emits. Dies with those paths. Default: sharp corners.
     fn corner_style(&self, _rect: Rect) -> Option<(f32, (bool, bool, bool, bool))> {
         None
@@ -188,7 +188,7 @@ pub trait Paint {
         None
     }
 
-    /// Draw this widget's own popover (legacy `Element::render_popover`).
+    /// Draw this widget's own popover (legacy `WidgetHost::render_popover`).
     fn draw_popover(&self, _rect: Rect, _pc: &mut dyn crate::layout::RenderTarget) {}
 
     /// Solid border `(color, thickness)` of the widget's background quad. **Transitional**, like
@@ -199,7 +199,7 @@ pub trait Paint {
     }
 
     /// Font for this widget's text on legacy text paths (`render_widget` reads
-    /// `Element::widget_font`). **Transitional.**
+    /// `WidgetHost::widget_font`). **Transitional.**
     fn widget_font(&self) -> Option<String> {
         None
     }
@@ -228,7 +228,7 @@ pub trait Paint {
     // getters. A migrated widget emits the rounded view from `paint`; when it also serves a
     // plain view, the adapter returns it verbatim from `extra_quads` and empties `all_quads`
     // (mirroring legacy Graph's highlight-only override) so render_widget-style hosts that
-    // read BOTH getters never draw the geometry twice. Dies with `Element`.
+    // read BOTH getters never draw the geometry twice. Dies with `WidgetHost`.
 
     /// Whether this widget serves [`legacy_plain_quads`](Paint::legacy_plain_quads).
     fn serves_legacy_plain_quads(&self) -> bool {
@@ -248,7 +248,7 @@ pub trait Paint {
         None
     }
 
-    /// Per-frame text shaping against the app's `FontSystem` (legacy `Element::prepare_text`
+    /// Per-frame text shaping against the app's `FontSystem` (legacy `WidgetHost::prepare_text`
     /// overrides). TextBox measures its glyph advances here — load-bearing for cursor↔pixel
     /// mapping, not just a render cache. Receives the laid-out content rect. Default: nothing
     /// to shape.
@@ -256,7 +256,7 @@ pub trait Paint {
 
     /// Whether [`paint`](Paint::paint) emits the widget's ENTIRE subtree, so the paint walk
     /// must not also descend into its (ctx-linked) children — the legacy
-    /// `Element::renders_own_subtree` contract. TreeList: its field widgets stay ctx-linked
+    /// `WidgetHost::renders_own_subtree` contract. TreeList: its field widgets stay ctx-linked
     /// for event propagation, but their pixels come from `paint`'s own child pass (which
     /// gates the add-key popover box on the popover actually being open).
     fn paints_own_subtree(&self) -> bool {
@@ -265,7 +265,7 @@ pub trait Paint {
 
 
     /// Whether the adapter re-enables the legacy shared focus/hover highlight overlay
-    /// (`Element::highlight_quad`'s default) for this widget. The adapter suppresses it for
+    /// (`WidgetHost::highlight_quad`'s default) for this widget. The adapter suppresses it for
     /// migrated widgets — matching the `None` overrides most legacy controls carried — but
     /// legacy TextBox kept the default: the focused editor gets the primary-highlight tint
     /// over its background (data-editor's teal editing wash). Default: suppressed.
@@ -284,7 +284,7 @@ pub trait Paint {
         false
     }
 
-    /// Forward the legacy `Element::highlight_quad` to somewhere else entirely — Paginator
+    /// Forward the legacy `WidgetHost::highlight_quad` to somewhere else entirely — Paginator
     /// served its ButtonStrip's highlight (the hovered-tab tint cce-layout-interface draws by
     /// calling `highlight_quad` directly). Outer `Some` replaces the adapter's highlight logic
     /// with the inner value; `None` (default) keeps the standard behavior
@@ -332,7 +332,7 @@ pub struct EventCtx<'a> {
     /// The routing context, when routed. **Transitional** — narrow widgets should only touch the
     /// legacy shared fields (scroll gesture state) until those get typed helpers here.
     pub ui: Option<&'a mut UiContext>,
-    self_ptr: Option<*mut (dyn Element + 'static)>,
+    self_ptr: Option<*mut (dyn WidgetHost + 'static)>,
 }
 
 impl EventCtx<'_> {
@@ -365,14 +365,14 @@ impl EventCtx<'_> {
     /// The adapter's pointer, for legacy sites that must hand it onward — TreeList makes
     /// itself the focus target (`set_focused_ptr`) and the context-menu target
     /// (`show_context_menu`) with the pointer hosts registered. Transitional; dies with
-    /// `Element`. None outside a routed path.
-    pub(crate) fn host_ptr(&self) -> Option<*mut (dyn Element + 'static)> {
+    /// `WidgetHost`. None outside a routed path.
+    pub(crate) fn host_ptr(&self) -> Option<*mut (dyn WidgetHost + 'static)> {
         self.self_ptr
     }
 }
 
 /// The input concern — hit-testing and event handling against the laid-out rect. Mirrors the
-/// legacy `Element::hit_test` / `handle_event` pair, but with the RFC's centralizations: the
+/// legacy `WidgetHost::hit_test` / `handle_event` pair, but with the RFC's centralizations: the
 /// default hit is plain rect containment (no per-widget address hacks), and pointer-positioned
 /// events are hit-gated by the adapter *before* they reach [`on_event`](Input::on_event), so a
 /// narrow widget never re-implements the "am I actually under the cursor?" boilerplate that every
@@ -396,7 +396,7 @@ pub trait Input {
 
     /// Whether pressing on this widget blocks dragging the movable backplate under it. Passive
     /// display widgets (separators, status dots) return `false` so drags pass through them.
-    /// Default: `true`, matching the legacy `Element` default.
+    /// Default: `true`, matching the legacy `WidgetHost` default.
     fn blocks_backplate_drag(&self) -> bool {
         true
     }
@@ -447,13 +447,13 @@ pub trait Input {
         false
     }
 
-    /// The widget's value as an integer (legacy `Element::value`).
+    /// The widget's value as an integer (legacy `WidgetHost::value`).
     fn value(&self) -> i32 {
         0
     }
 
     // --- Clipboard/selection surface (the context menu's Cut/Copy/Paste/Select-All actions
-    // call these on their target Element). The defaults replicate the `Element` defaults
+    // call these on their target WidgetHost). The defaults replicate the `WidgetHost` defaults
     // byte-for-byte (whole-value copy through the value-string pair), so widgets migrated
     // before these hooks existed keep their exact behavior; TextBox overrides with real
     // selection-aware implementations.
@@ -495,7 +495,7 @@ pub trait Input {
         true
     }
 
-    /// Selection state pushed in by list/row hosts (legacy `Element::set_selected`).
+    /// Selection state pushed in by list/row hosts (legacy `WidgetHost::set_selected`).
     fn set_selected(&mut self, _selected: bool) {}
 
     // --- Drag surface: legacy hosts (designer, control_panel, parameters_bg, graph, audio…)
@@ -523,7 +523,7 @@ pub trait Input {
     /// Movement bounds pushed in by hosts (reached via the inherent `Adapted::set_drag_bounds`).
     fn set_drag_bounds(&mut self, _bx: f32, _by: f32, _bw: f32, _bh: f32) {}
 
-    // --- Tick surface: hosts broadcast `Element::tick(dt)` every frame (the designer's render
+    // --- Tick surface: hosts broadcast `WidgetHost::tick(dt)` every frame (the designer's render
     // loop) to advance time-based widget state — inertial scroll velocity, here. Transitional:
     // §3.6 `Animated<T>` + arena-driven frame requests replace hand-ticked state.
 
@@ -542,35 +542,35 @@ pub trait Input {
     }
 
     /// Whether this widget wants `tick` calls from tick-gating hosts (legacy
-    /// `Element::wants_tick`; the designer ticks unconditionally and ignores this).
+    /// `WidgetHost::wants_tick`; the designer ticks unconditionally and ignores this).
     fn wants_tick(&self) -> bool {
         false
     }
 
-    /// Whether this widget consumes scroll gestures (legacy `Element::is_scrollable`, read by
+    /// Whether this widget consumes scroll gestures (legacy `WidgetHost::is_scrollable`, read by
     /// the router's scroll-gesture gating).
     fn scrollable(&self) -> bool {
         false
     }
 
     // --- Controller capabilities (transitional, like the polling surface above). The legacy
-    // tree reaches a widget's typed API through the `Element::as_*_controller` downcast pairs;
-    // `Element` is implemented exactly once (for `Adapted<W>`), so a migrated controller widget
+    // tree reaches a widget's typed API through the `WidgetHost::as_*_controller` downcast pairs;
+    // `WidgetHost` is implemented exactly once (for `Adapted<W>`), so a migrated controller widget
     // re-exposes its controller impl through these hooks instead — `Some(self)` when `W`
-    // implements the trait. Dies with `Element`: the end state reaches a controller through the
+    // implements the trait. Dies with `WidgetHost`: the end state reaches a controller through the
     // concrete `Adapted<W>` (or a `&dyn XController` held directly), per RFC §3.5.
 
 
     /// Keyboard modifier state pushed in by hosts before dispatch (legacy
-    /// `Element::set_modifiers`).
+    /// `WidgetHost::set_modifiers`).
     fn set_modifiers(&mut self, _ctrl: bool, _shift: bool, _alt: bool) {}
 
-    /// The widget's visibility flag changed through `Element::set_visible` (the adapter owns
+    /// The widget's visibility flag changed through `WidgetHost::set_visible` (the adapter owns
     /// the flag) — legacy hideable widgets used the setter for side effects (MenuBar closes
     /// its dropdowns and invalidates layout).
     fn visibility_changed(&mut self, _visible: bool) {}
 
-    /// The widget's `Element::focused` answer, given the base flag — MenuBar reports focused
+    /// The widget's `WidgetHost::focused` answer, given the base flag — MenuBar reports focused
     /// while any of its dropdowns is open, beyond the flag itself. Default: the flag.
     fn is_focused(&self, base_focused: bool) -> bool {
         base_focused
@@ -578,20 +578,20 @@ pub trait Input {
 
 }
 
-/// Wraps a narrow-trait widget `W` so it lives in the legacy `*mut dyn Element` tree. Carries the
-/// [`Widget`] base that `Element`'s rect / id / dirty machinery needs, and forwards the concern
+/// Wraps a narrow-trait widget `W` so it lives in the legacy `*mut dyn WidgetHost` tree. Carries the
+/// [`Widget`] base that `WidgetHost`'s rect / id / dirty machinery needs, and forwards the concern
 /// methods to `W`. See the module docs for why this bridge exists rather than a supertrait split.
 ///
-/// The bounds live on the struct (not just the `Element` impl) so `Drop` can clear the global
-/// focus / context-menu references through `&dyn Element` — the same guard legacy widgets with
+/// The bounds live on the struct (not just the `WidgetHost` impl) so `Drop` can clear the global
+/// focus / context-menu references through `&dyn WidgetHost` — the same guard legacy widgets with
 /// `Drop` impls (e.g. the old `Checkbox`) carried.
 #[derive(Debug, Clone)]
 pub struct Adapted<W: Layout + Paint + Input + 'static> {
     base: Widget,
-    /// The [`Widget`] base carries no visibility, and the legacy `Element` defaults are a no-op
+    /// The [`Widget`] base carries no visibility, and the legacy `WidgetHost` defaults are a no-op
     /// `set_visible` + always-true `visible()` — every hideable legacy widget stores its own
     /// flag. The adapter owns it once for all migrated widgets: hosts toggle panes through
-    /// `Element::set_visible` (the designer), and the hit-test/render bridges gate on it.
+    /// `WidgetHost::set_visible` (the designer), and the hit-test/render bridges gate on it.
     visible: bool,
     inner: W,
 }
@@ -677,22 +677,22 @@ impl<W: Layout + Paint + Input + 'static> Adapted<W> {
 }
 
 impl<W: Layout + Paint + Input + 'static> Adapted<W> {
-    /// Movement bounds pushed in by hosts (off the `Element` trait since 6bd — the one
+    /// Movement bounds pushed in by hosts (off the `WidgetHost` trait since 6bd — the one
     /// production caller is concrete: designer's network panel).
     pub fn set_drag_bounds(&mut self, bx: f32, by: f32, bw: f32, bh: f32) {
         Input::set_drag_bounds(&mut self.inner, bx, by, bw, bh)
     }
 
-    /// Unlink all tree children (off `Element` in 6bd batch 2 — every caller is a concrete
+    /// Unlink all tree children (off `WidgetHost` in 6bd batch 2 — every caller is a concrete
     /// `Adapted` field).
     pub fn clear_children(&mut self, ctx: &mut UiContext) {
         ctx.clear_children_ids(self.base.id());
     }
 
-    /// Register + link a child under this widget (off `Element` in 6bd batch 4; dyn callers
+    /// Register + link a child under this widget (off `WidgetHost` in 6bd batch 4; dyn callers
     /// went to `focus::link_parent_child`/tree ops).
-    pub fn add_child(&mut self, child: *mut (dyn Element + 'static), ctx: &mut UiContext) {
-        // The old Element default's tree link…
+    pub fn add_child(&mut self, child: *mut (dyn WidgetHost + 'static), ctx: &mut UiContext) {
+        // The old WidgetHost default's tree link…
         let c_id = unsafe { (*child).base().id() };
         let p_id = self.base.id();
         let self_ptr = self.as_ptr();
@@ -709,9 +709,9 @@ impl<W: Layout + Paint + Input + 'static> Adapted<W> {
         }
     }
 
-    /// Register + (un)link this widget under a parent (off `Element` in 6bd batch 4).
-    pub fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, ctx: &mut UiContext) {
-        // Replica of the old Element default: symmetric tree link.
+    /// Register + (un)link this widget under a parent (off `WidgetHost` in 6bd batch 4).
+    pub fn set_parent(&mut self, parent: Option<*mut (dyn WidgetHost + 'static)>, ctx: &mut UiContext) {
+        // Replica of the old WidgetHost default: symmetric tree link.
         let id = self.base.id();
         if let Some(p_ptr) = parent {
             let p_id = unsafe { (*p_ptr).base().id() };
@@ -724,7 +724,7 @@ impl<W: Layout + Paint + Input + 'static> Adapted<W> {
         }
     }
 
-    /// The model's intrinsic content size (off the `Element` trait since 6bd — the concrete
+    /// The model's intrinsic content size (off the `WidgetHost` trait since 6bd — the concrete
     /// callers are fonts'/graph's hand-laid button/dropdown sizing).
     pub fn intrinsic_size(&self) -> Option<Size> {
         Layout::intrinsic_size(&self.inner)
@@ -756,7 +756,7 @@ impl<W: Layout + Paint + Input + 'static> Adapted<W> {
     /// The container's children that pass the [`Layout::child_visible`] policy — the set the
     /// adapter's subtree plumbing (aggregation, recursion, hit-through) operates on. Empty for
     /// non-containers.
-    fn visible_children(&self) -> Vec<*mut (dyn Element + 'static)> {
+    fn visible_children(&self) -> Vec<*mut (dyn WidgetHost + 'static)> {
         if !Layout::has_container_children(&self.inner) {
             return Vec::new();
         }
@@ -830,14 +830,14 @@ impl<W: Layout + Paint + Input + 'static> Adapted<W> {
     }
 
     /// The base-label text of a *detached*-label widget — a replica of the legacy default
-    /// `Element::text_labels` body (which an overriding impl can no longer call).
+    /// `WidgetHost::text_labels` body (which an overriding impl can no longer call).
     fn base_label_fallback(&self) -> Vec<TextLabel> {
         let b = &self.base;
         if let Some(ref label) = b.label {
             let (_, font_size) = crate::layout::control_label_font_detached_parsed();
             let color = crate::colors::control_label_color_detached_for_state(b.hovered, b.focused);
             if crate::layout::control_label_layout() == "side" {
-                let label_x = Element::label_x_offset(self);
+                let label_x = WidgetHost::label_x_offset(self);
                 if label_x > 0.0 {
                     let y_pos = crate::layout::align_text_y(b.y, b.h, font_size, 0.0);
                     return vec![TextLabel { text: label.clone(), x: b.x + 4.0, y: y_pos, font_size, color }];
@@ -867,7 +867,7 @@ impl<W: Layout + Paint + Input + 'static> std::ops::DerefMut for Adapted<W> {
     }
 }
 
-impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
+impl<W: Layout + Paint + Input + 'static> WidgetHost for Adapted<W> {
     fn base(&self) -> &Widget {
         &self.base
     }
@@ -882,11 +882,11 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
     fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
         &mut self.inner
     }
-    fn as_ptr(&self) -> *mut (dyn Element + 'static) {
-        self as *const Self as *mut Self as *mut (dyn Element + 'static)
+    fn as_ptr(&self) -> *mut (dyn WidgetHost + 'static) {
+        self as *const Self as *mut Self as *mut (dyn WidgetHost + 'static)
     }
-    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
-        self as *mut Self as *mut (dyn Element + 'static)
+    fn as_ptr_mut(&mut self) -> *mut (dyn WidgetHost + 'static) {
+        self as *mut Self as *mut (dyn WidgetHost + 'static)
     }
 
     fn set_visible(&mut self, visible: bool) {
@@ -900,11 +900,11 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
     }
 
     // --- Container concern: tree lifecycle, child layout, and subtree recursion. The tree
-    // itself stays in `ctx.tree` (the Element defaults' store); a container model additionally
+    // itself stays in `ctx.tree` (the WidgetHost defaults' store); a container model additionally
     // keeps its own pointer Vec via the `Layout` hooks, because `set_rect`-time arrangement
     // has no ctx to reach the tree.
 
-    fn children(&self, ctx: &UiContext) -> Vec<*mut (dyn Element + 'static)> {
+    fn children(&self, ctx: &UiContext) -> Vec<*mut (dyn WidgetHost + 'static)> {
         if Layout::has_container_children(&self.inner) {
             return Layout::container_children(&self.inner);
         }
@@ -927,7 +927,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
         Layout::z_order(&self.inner)
     }
 
-    fn parent(&self, ctx: &UiContext) -> Option<*mut (dyn Element + 'static)> {
+    fn parent(&self, ctx: &UiContext) -> Option<*mut (dyn WidgetHost + 'static)> {
         ctx.tree.parent_ptr(self.base.id())
     }
 
@@ -941,7 +941,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
 
 
     fn layout(&mut self, origin: crate::widget::Point, constraints: crate::widget::LayoutConstraints, ctx: &mut UiContext) {
-        // The Element default (measure + set_rect), plus recursive child layout for visible
+        // The WidgetHost default (measure + set_rect), plus recursive child layout for visible
         // containers — the ctx-carrying half of the arrangement the model can't do in
         // `arrange_children`.
         let size = self.measure(constraints, ctx);
@@ -1012,7 +1012,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
         Layout::intrinsic_size(&self.inner).map(|s| s.height)
     }
 
-    /// The `Element::measure` default, except the width consults the intrinsic size when the
+    /// The `WidgetHost::measure` default, except the width consults the intrinsic size when the
     /// widget opts in ([`Layout::intrinsic_measure_width`] — Dropdown's `auto_width`).
     fn measure(&self, constraints: crate::widget::LayoutConstraints, _ctx: &UiContext) -> crate::widget::Size {
         let (_, _, w, h) = self.rect();
@@ -1032,7 +1032,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
     /// hover-highlight overlay is suppressed (matching what most control widgets' `None`
     /// overrides do today) — unless the widget opts back in
     /// ([`Paint::legacy_focus_highlight`], TextBox), in which case this replicates the
-    /// `Element` default byte-for-byte: primary tint when ctx-focused (or active), secondary
+    /// `WidgetHost` default byte-for-byte: primary tint when ctx-focused (or active), secondary
     /// when hovered, over the row-substituted, side-label-inset span.
     fn highlight_quad(&self, ctx: &UiContext) -> Option<(f32, f32, f32, f32, [f32; 4])> {
         // A forwarding widget (Paginator → its ButtonStrip) serves the forwarded value here —
@@ -1052,7 +1052,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
         } else {
             return None;
         };
-        let label_x = Element::label_x_offset(self);
+        let label_x = WidgetHost::label_x_offset(self);
         let hx = if self.base.row_w > 0.0 { self.base.row_x } else { self.base.x } + label_x;
         let hw = if self.base.row_w > 0.0 { self.base.row_w } else { self.base.w } - label_x;
         Some((hx, self.base.y, hw, self.base.h, hc))
@@ -1064,7 +1064,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
         std::any::type_name::<W>().split("::").last().unwrap_or("Widget")
     }
 
-    /// Text-content mutation (legacy `Element::set_text` wrote only `base.label`): keep the base
+    /// Text-content mutation (legacy `WidgetHost::set_text` wrote only `base.label`): keep the base
     /// copy and the widget's own copy ([`Paint::sync_label`]) in step, like `set_label`.
     fn set_text(&mut self, text: &str) {
         self.base.label = Some(text.to_string());
@@ -1079,7 +1079,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
         Paint::clips_children(&self.inner)
     }
     fn corner_style(&self) -> (f32, (bool, bool, bool, bool)) {
-        // 12.0 / all-off mirrors the `Element` default for widgets without a corner style.
+        // 12.0 / all-off mirrors the `WidgetHost` default for widgets without a corner style.
         Paint::corner_style(&self.inner, self.content_rect())
             .unwrap_or((12.0, (false, false, false, false)))
     }
@@ -1125,7 +1125,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
         // highlight — replicate for opt-in widgets, over the background (same draw order).
         // Forwarded highlights stay out: the paint walk reaches the owning child itself.
         if Paint::legacy_focus_highlight(&self.inner) {
-            if let Some((hx, hy, hw, hh, hc)) = Element::highlight_quad(self, ui) {
+            if let Some((hx, hy, hw, hh, hc)) = WidgetHost::highlight_quad(self, ui) {
                 if hc != crate::colors::HIGHLIGHT_SECONDARY {
                     ctx.quad(Rect { x: hx, y: hy, width: hw, height: hh }, hc);
                 }
@@ -1148,7 +1148,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
         }
     }
 
-    // The legacy per-widget text getters are deleted from `Element`: this adapter's text
+    // The legacy per-widget text getters are deleted from `WidgetHost`: this adapter's text
     // reaches the frame through `paint_self` above (prim-derived own labels + the
     // detached base label), and composites that need a concrete Adapted child's labels
     // call `own_labels_with_font_and_bounds` directly (pub(crate)).
@@ -1175,7 +1175,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
                 _ => None,
             })
             .collect();
-        // Containers recurse, matching the `Element` default this override replaces.
+        // Containers recurse, matching the `WidgetHost` default this override replaces.
         for child in self.visible_children() {
             out.extend(unsafe { &*child }.all_rounded_quads(ctx));
         }
@@ -1204,7 +1204,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
     /// When the widget serves a legacy plain-quad view, its geometry reaches
     /// `render_widget`-style hosts (which read BOTH quad getters) through `all_rounded_quads`
     /// only — `all_quads` must stay empty or they draw it twice. Mirrors legacy Graph's
-    /// highlight-only `all_quads` override. Otherwise: the `Element` default minus the shared
+    /// highlight-only `all_quads` override. Otherwise: the `WidgetHost` default minus the shared
     /// highlight (suppressed for all adapted widgets via `highlight_quad -> None`).
     fn all_quads(&self, ctx: &UiContext) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
         if Paint::serves_legacy_plain_quads(&self.inner) {
@@ -1213,12 +1213,12 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
         // Own prims directly (NOT `extra_quads`, which may serve the child aggregation — those
         // children arrive once, through the recursion below).
         let mut quads = if self.visible() { self.own_plain_quads() } else { Vec::new() };
-        // The `Element` default's highlight inclusion (secondary/hover tint excluded), live
+        // The `WidgetHost` default's highlight inclusion (secondary/hover tint excluded), live
         // only for widgets that opt into the legacy overlay. A forwarded highlight
         // ([`Paint::forwarded_highlight`]) is deliberately excluded: its owner's aggregation
         // already carries it, matching the legacy container `all_quads` overrides.
         if Paint::legacy_focus_highlight(&self.inner) {
-            if let Some(hq) = Element::highlight_quad(self, ctx) {
+            if let Some(hq) = WidgetHost::highlight_quad(self, ctx) {
                 if hq.4 != crate::colors::HIGHLIGHT_SECONDARY {
                     quads.push(hq);
                 }
@@ -1303,7 +1303,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
     }
     /// Row-rect assignment (row-layout hosts): apply the widget's clamp
     /// ([`Layout::adjust_row_rect`] — TextBox's `width`/`max_width`), then the base write the
-    /// `Element` default does.
+    /// `WidgetHost` default does.
     fn set_row_rect(&mut self, x: f32, w: f32) {
         let (rx, rw) = Layout::adjust_row_rect(&self.inner, x, w);
         self.base.row_x = rx;
@@ -1358,7 +1358,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
     }
     // --- Legacy direct-dispatch entry points. Hosts (treelist's add-key button, parameters_bg's
     // checkboxes, app pages) call these ON the widget instead of routing an Event through
-    // `propagate_event`; without these overrides they'd hit the inert Element defaults and the
+    // `propagate_event`; without these overrides they'd hit the inert WidgetHost defaults and the
     // widget would go deaf on those paths. Route them into `handle_event` so the hit-gating /
     // context-menu / on_event pipeline applies identically on both paths.
 
@@ -1400,7 +1400,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
         if Input::on_event(&mut self.inner, &event, &mut ectx) {
             return true;
         }
-        // The legacy default `Element::on_cursor_moved` body: base hover flag + synthesized
+        // The legacy default `WidgetHost::on_cursor_moved` body: base hover flag + synthesized
         // MouseEnter/MouseLeave (which re-enter `handle_event` and reach `on_event`).
         let was = self.base.hovered;
         let is_hit = self.hit_test(px, py, ctx);
@@ -1465,7 +1465,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
                 return false;
             }
             let (mut hx, mut hw) = if self.base.row_w > 0.0 { (self.base.row_x, self.base.row_w) } else { (x, w) };
-            let label_x = Element::label_x_offset(self);
+            let label_x = WidgetHost::label_x_offset(self);
             hx += label_x;
             hw -= label_x;
             return Input::hit(&self.inner, Rect { x: hx, y, width: hw, height: h }, px, py);
@@ -1484,7 +1484,7 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
         }
         match event {
             // A hit right-press on a context-menu widget routes to the shared config menu —
-            // `on_event` can't (that policy needs the target's Element pointer), so the adapter
+            // `on_event` can't (that policy needs the target's WidgetHost pointer), so the adapter
             // owns it.
             Event::MouseButton {
                 button: crate::widget::MouseButton::Right,
@@ -1546,7 +1546,7 @@ mod tests {
     use crate::scene::painter::paint_tree;
     use crate::widget::UiContext;
 
-    /// A leaf that only knows the two narrow concerns — no `Element` in sight: it reports an
+    /// A leaf that only knows the two narrow concerns — no `WidgetHost` in sight: it reports an
     /// intrinsic size ([`Layout`]) and a color ([`Paint`]).
     struct Dot {
         color: [f32; 4],
@@ -1574,7 +1574,7 @@ mod tests {
     }
     impl Input for Col {}
 
-    fn rect_of(ptr: *mut (dyn Element + 'static)) -> Rect {
+    fn rect_of(ptr: *mut (dyn WidgetHost + 'static)) -> Rect {
         let (x, y, w, h) = unsafe { (*ptr).rect() };
         Rect { x, y, width: w, height: h }
     }
@@ -1583,7 +1583,7 @@ mod tests {
     fn narrow_widget_lays_out_and_paints_through_the_adapter() {
         // A pure narrow-trait widget tree (Col + two Dots), wrapped in `Adapted`, is laid out by
         // the existing bridge and painted by the existing painter — proving a widget that never
-        // touches `Element` participates in both live passes.
+        // touches `WidgetHost` participates in both live passes.
         let mut ctx = UiContext::new();
         let mut root = Box::new(Adapted::new(Col));
         let mut a = Box::new(Adapted::new(Dot { color: [1.0, 0.0, 0.0, 1.0], size: Size::new(10.0, 10.0) }));
@@ -1629,7 +1629,7 @@ mod tests {
     }
 
     /// A narrow interactive widget: counts left-clicks and records hover transitions — all
-    /// through [`Input::on_event`], never touching `Element`.
+    /// through [`Input::on_event`], never touching `WidgetHost`.
     struct Clicker {
         clicks: u32,
         entered: u32,
@@ -1697,7 +1697,7 @@ mod tests {
     }
 
     /// A narrow widget that is also a controller: the controller trait is reached through the
-    /// concrete `Adapted<W>` by deref (Phase 6aw -- the `Element::as_*_controller` discovery
+    /// concrete `Adapted<W>` by deref (Phase 6aw -- the `WidgetHost::as_*_controller` discovery
     /// hooks are deleted).
     struct Crumbs {
         segs: Vec<String>,