diff --git a/packages/devtools/README.md b/packages/devtools/README.md
index 6a582ae94..28d23b669 100644
--- a/packages/devtools/README.md
+++ b/packages/devtools/README.md
@@ -21,7 +21,9 @@ The widget renders nothing in production builds (`NODE_ENV === "production"`) un
`@openuidev/react-lang` ships with this package and auto-mounts the widget in development — no manual `` needed. Mounting it manually still works (e.g. to customize props): only one instance ever renders, and a manually mounted instance takes precedence over the auto-mounted one.
-In development, `createLibrary()` registers the live library with the widget. The **OpenUI Paste** banner at the bottom of the drawer widens the drawer into an editor against that library (host CSS included), with Render / Validation / Tree / JSON / Stream panels and simulated stream playback. A stream event's **Debug** button opens its response the same way. Eject moves the view into a separate window. The first visit opens a short step-by-step guide (also on **Help**); dismissing it is remembered.
+**OpenUI Inspect** (the event drawer) and **OpenUI Debug** are independent tools on independent trays. Debug docks beside Inspect rather than growing out of it, and each closes on its own: dismissing Debug leaves the event list where it was, and vice versa.
+
+In development, `createLibrary()` registers the live library with the widget. The **OpenUI Debug** banner at the bottom of the Inspect tray opens an editor against that library (host CSS included), with Render / Validation / Tree / JSON / Stream panels and simulated stream playback. A stream event's **Debug** button opens its response the same way. Eject moves the view into a separate window. The first visit opens a short step-by-step guide (also on **Help**); dismissing it is remembered.
Display filters ("auto-open on error", "errors only") and the theme live behind the gear in the drawer header. The theme is Light or Dark, chosen manually and remembered across reloads: nothing is auto-detected from the host page or the OS, and it styles the devtools chrome only — never your app. The floating Shiro toggle stays dark so the branded mark stays readable.
diff --git a/packages/devtools/src/IconButton.tsx b/packages/devtools/src/IconButton.tsx
new file mode 100644
index 000000000..5d542b90b
--- /dev/null
+++ b/packages/devtools/src/IconButton.tsx
@@ -0,0 +1,63 @@
+import { useState, type ButtonHTMLAttributes, type CSSProperties } from "react";
+
+/**
+ * The widget's square icon buttons — header actions, close crosses, the
+ * settings trigger. They sit on their tray with no chrome until pointed at,
+ * then take a fill; keeping that in one component means every one of them
+ * behaves the same without threading hover state through each call site.
+ */
+export function IconButton({
+ active = false,
+ outlined = false,
+ style,
+ ...props
+}: ButtonHTMLAttributes & {
+ /** Held open, e.g. the settings trigger while its menu shows. */
+ active?: boolean;
+ /** Carries its own border, for buttons that sit on a busy surface. */
+ outlined?: boolean;
+}) {
+ const [hovered, setHovered] = useState(false);
+ return (
+