webui: Update status indicators

- Remove green dot connection indicator
- Add DISCONNECTED state with red styling when connection is lost
- Update the status bar to show DISCONNECTED instead of IDLE/WORKING when disconnected
- Create demo page to preview all three status states

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: skR3m0v3Gr3nD0tD1sc0nn3ct3dR3d

Change-ID: sa2b3679b9cdcaf80k
diff --git a/webui/src/web-components/demo/sketch-network-status.demo.html b/webui/src/web-components/demo/sketch-network-status.demo.html
index f248a5d..b0aad7e 100644
--- a/webui/src/web-components/demo/sketch-network-status.demo.html
+++ b/webui/src/web-components/demo/sketch-network-status.demo.html
@@ -3,20 +3,51 @@
     <title>sketch-network-status demo</title>
     <link rel="stylesheet" href="demo.css" />
     <script type="module" src="../sketch-network-status.ts"></script>
+    <script type="module" src="../sketch-call-status.ts"></script>
+    <style>
+      .status-container {
+        margin: 20px 0;
+        padding: 10px;
+        border: 1px solid #ccc;
+        border-radius: 4px;
+      }
+      .label {
+        font-weight: bold;
+        margin-bottom: 5px;
+      }
+    </style>
   </head>
   <body>
-    <h1>sketch-network-status demo</h1>
-
-    Connected:
-    <sketch-network-status
-      connection="connected"
-      message="connected"
-    ></sketch-network-status>
-
-    Error:
-    <sketch-network-status
-      connection="error"
-      error="error"
-    ></sketch-network-status>
+    <h1>Status Indicators Demo</h1>
+    
+    <div class="status-container">
+      <div class="label">Connected State:</div>
+      <sketch-call-status
+        .isDisconnected="false"
+        .isIdle="true"
+        .llmCalls="0"
+        .toolCalls='[]'
+      ></sketch-call-status>
+    </div>
+    
+    <div class="status-container">
+      <div class="label">Working State:</div>
+      <sketch-call-status
+        .isDisconnected="false"
+        .isIdle="false"
+        .llmCalls="1"
+        .toolCalls='["bash"]'
+      ></sketch-call-status>
+    </div>
+    
+    <div class="status-container">
+      <div class="label">Disconnected State:</div>
+      <sketch-call-status
+        .isDisconnected="true"
+        .isIdle="true"
+        .llmCalls="0"
+        .toolCalls='[]'
+      ></sketch-call-status>
+    </div>
   </body>
 </html>
diff --git a/webui/src/web-components/demo/status-demo.html b/webui/src/web-components/demo/status-demo.html
new file mode 100644
index 0000000..063c693
--- /dev/null
+++ b/webui/src/web-components/demo/status-demo.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Status Demo</title>
+    <script type="module" src="../sketch-call-status.ts"></script>
+    <style>
+      body {
+        font-family: system-ui, sans-serif;
+        max-width: 800px;
+        margin: 0 auto;
+        padding: 20px;
+      }
+      .demo-section {
+        margin-bottom: 40px;
+      }
+      .demo-item {
+        margin-bottom: 20px;
+        padding: 15px;
+        border: 1px solid #ccc;
+        border-radius: 5px;
+      }
+      h2 {
+        margin-top: 0;
+      }
+      .status-display {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        height: 60px;
+        background-color: #f5f5f5;
+        border-radius: 4px;
+        margin-top: 10px;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Status Indicators Demo</h1>
+    <p>This demo shows the status indicators with the DISCONNECTED state.</p>
+    
+    <div class="demo-section">
+      <div class="demo-item">
+        <h2>IDLE State</h2>
+        <div class="status-display">
+          <sketch-call-status id="idle-status"></sketch-call-status>
+        </div>
+      </div>
+      
+      <div class="demo-item">
+        <h2>WORKING State</h2>
+        <div class="status-display">
+          <sketch-call-status id="working-status"></sketch-call-status>
+        </div>
+      </div>
+      
+      <div class="demo-item">
+        <h2>DISCONNECTED State</h2>
+        <div class="status-display">
+          <sketch-call-status id="disconnected-status"></sketch-call-status>
+        </div>
+      </div>
+    </div>
+
+    <script>
+      // Set up the demo after components are defined
+      window.addEventListener('DOMContentLoaded', () => {
+        // IDLE status
+        const idleStatus = document.getElementById('idle-status');
+        idleStatus.isIdle = true;
+        idleStatus.isDisconnected = false;
+        idleStatus.llmCalls = 0;
+        idleStatus.toolCalls = [];
+        
+        // WORKING status
+        const workingStatus = document.getElementById('working-status');
+        workingStatus.isIdle = false;
+        workingStatus.isDisconnected = false;
+        workingStatus.llmCalls = 1;
+        workingStatus.toolCalls = ['bash'];
+        
+        // DISCONNECTED status
+        const disconnectedStatus = document.getElementById('disconnected-status');
+        disconnectedStatus.isIdle = true;
+        disconnectedStatus.isDisconnected = true;
+        disconnectedStatus.llmCalls = 0;
+        disconnectedStatus.toolCalls = [];
+      });
+    </script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/webui/src/web-components/demo/status-indicators.demo.html b/webui/src/web-components/demo/status-indicators.demo.html
new file mode 100644
index 0000000..5fa9400
--- /dev/null
+++ b/webui/src/web-components/demo/status-indicators.demo.html
@@ -0,0 +1,111 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Status Indicators Demo</title>
+    <script type="module" src="../sketch-call-status.ts"></script>
+    <script type="module" src="../sketch-network-status.ts"></script>
+    <style>
+      body {
+        font-family: system-ui, sans-serif;
+        max-width: 800px;
+        margin: 0 auto;
+        padding: 20px;
+      }
+      .demo-container {
+        display: flex;
+        flex-direction: column;
+        gap: 20px;
+      }
+      .status-container {
+        padding: 20px;
+        border: 1px solid #ccc;
+        border-radius: 5px;
+        background-color: #f9f9f9;
+      }
+      .label {
+        font-weight: bold;
+        margin-bottom: 10px;
+        font-size: 16px;
+      }
+      .status-row {
+        display: flex;
+        align-items: center;
+        gap: 10px;
+        padding: 10px 0;
+        border-bottom: 1px solid #eee;
+      }
+      .status-item {
+        min-width: 200px;
+      }
+      h1 {
+        margin-bottom: 20px;
+      }
+      .status-view {
+        background-color: white;
+        border: 1px solid #ddd;
+        padding: 10px;
+        border-radius: 4px;
+      }
+      .description {
+        margin-top: 10px;
+        color: #666;
+        font-size: 14px;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Status Indicators Demo</h1>
+    <p>This demo shows the new status indicators without the green connection dot.</p>
+    
+    <div class="demo-container">
+      <div class="status-container">
+        <div class="label">Connected States:</div>
+        
+        <div class="status-row">
+          <div class="status-item">IDLE:</div>
+          <div class="status-view">
+            <sketch-call-status
+              .isDisconnected="false"
+              .isIdle="true"
+              .llmCalls="0"
+              .toolCalls="[]"
+            ></sketch-call-status>
+          </div>
+          <div class="description">Agent is connected but not actively working</div>
+        </div>
+        
+        <div class="status-row">
+          <div class="status-item">WORKING:</div>
+          <div class="status-view">
+            <sketch-call-status
+              .isDisconnected="false"
+              .isIdle="false"
+              .llmCalls="1"
+              .toolCalls='["bash"]'
+            ></sketch-call-status>
+          </div>
+          <div class="description">Agent is connected and actively working</div>
+        </div>
+      </div>
+      
+      <div class="status-container">
+        <div class="label">Disconnected State:</div>
+        
+        <div class="status-row">
+          <div class="status-item">DISCONNECTED:</div>
+          <div class="status-view">
+            <sketch-call-status
+              .isDisconnected="true"
+              .isIdle="true"
+              .llmCalls="0"
+              .toolCalls="[]"
+            ></sketch-call-status>
+          </div>
+          <div class="description">Connection lost to the agent</div>
+        </div>
+      </div>
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/webui/src/web-components/sketch-app-shell.ts b/webui/src/web-components/sketch-app-shell.ts
index aebabd9..3c39a55 100644
--- a/webui/src/web-components/sketch-app-shell.ts
+++ b/webui/src/web-components/sketch-app-shell.ts
@@ -1022,6 +1022,7 @@
               ? this.messages[this.messages.length - 1]?.end_of_turn &&
                 !this.messages[this.messages.length - 1]?.parent_conversation_id
               : true}
+            .isDisconnected=${this.connectionStatus === "disconnected"}
           ></sketch-call-status>
 
           <sketch-network-status
diff --git a/webui/src/web-components/sketch-call-status.test.ts b/webui/src/web-components/sketch-call-status.test.ts
index 88ae3bd..7dc16a5 100644
--- a/webui/src/web-components/sketch-call-status.test.ts
+++ b/webui/src/web-components/sketch-call-status.test.ts
@@ -136,3 +136,48 @@
     "2 tool calls in progress: bash, think",
   );
 });
+
+test("displays IDLE status when isIdle is true and not disconnected", async ({ mount }) => {
+  const component = await mount(SketchCallStatus, {
+    props: {
+      isIdle: true,
+      isDisconnected: false,
+      llmCalls: 0,
+      toolCalls: [],
+    },
+  });
+
+  // Check that the status banner has the correct class and text
+  await expect(component.locator(".status-banner")).toHaveClass(/status-idle/);
+  await expect(component.locator(".status-banner")).toHaveText("IDLE");
+});
+
+test("displays WORKING status when isIdle is false and not disconnected", async ({ mount }) => {
+  const component = await mount(SketchCallStatus, {
+    props: {
+      isIdle: false,
+      isDisconnected: false,
+      llmCalls: 1,
+      toolCalls: [],
+    },
+  });
+
+  // Check that the status banner has the correct class and text
+  await expect(component.locator(".status-banner")).toHaveClass(/status-working/);
+  await expect(component.locator(".status-banner")).toHaveText("WORKING");
+});
+
+test("displays DISCONNECTED status when isDisconnected is true regardless of isIdle", async ({ mount }) => {
+  const component = await mount(SketchCallStatus, {
+    props: {
+      isIdle: true, // Even when idle
+      isDisconnected: true,
+      llmCalls: 0,
+      toolCalls: [],
+    },
+  });
+
+  // Check that the status banner has the correct class and text
+  await expect(component.locator(".status-banner")).toHaveClass(/status-disconnected/);
+  await expect(component.locator(".status-banner")).toHaveText("DISCONNECTED");
+});
diff --git a/webui/src/web-components/sketch-call-status.ts b/webui/src/web-components/sketch-call-status.ts
index a390093..69211b3 100644
--- a/webui/src/web-components/sketch-call-status.ts
+++ b/webui/src/web-components/sketch-call-status.ts
@@ -15,6 +15,9 @@
 
   @property()
   isIdle: boolean = false;
+  
+  @property()
+  isDisconnected: boolean = false;
 
   static styles = css`
     @keyframes gentle-pulse {
@@ -94,12 +97,12 @@
       font-weight: bold;
       text-align: center;
       letter-spacing: 0.5px;
-      width: 64px; /* Fixed width for the banner */
+      width: 104px; /* Wider to accommodate DISCONNECTED text */
       left: 50%;
       transform: translateX(-50%);
       top: 60%; /* Position a little below center */
       z-index: 10; /* Ensure it appears above the icons */
-      opacity: 0.6;
+      opacity: 0.9;
     }
 
     .status-working {
@@ -111,6 +114,12 @@
       background-color: #e6f4ea;
       color: #0d652d;
     }
+    
+    .status-disconnected {
+      background-color: #ffebee; /* Light red */
+      color: #d32f2f; /* Red */
+      font-weight: bold;
+    }
   `;
 
   render() {
@@ -126,8 +135,17 @@
 
     const agentState = `${this.agentState ? " (" + this.agentState + ")" : ""}`;
 
-    // Determine working state - working if not idle
-    const isWorking = !this.isIdle;
+    // Determine state - disconnected takes precedence, then working vs idle
+    let statusClass = "status-idle";
+    let statusText = "IDLE";
+    
+    if (this.isDisconnected) {
+      statusClass = "status-disconnected";
+      statusText = "DISCONNECTED";
+    } else if (!this.isIdle) {
+      statusClass = "status-working";
+      statusText = "WORKING";
+    }
 
     return html`
       <div class="call-status-container">
@@ -152,9 +170,9 @@
           </div>
         </div>
         <div
-          class="status-banner ${isWorking ? "status-working" : "status-idle"}"
+          class="status-banner ${statusClass}"
         >
-          ${isWorking ? "WORKING" : "IDLE"}
+          ${statusText}
         </div>
       </div>
     `;
diff --git a/webui/src/web-components/sketch-network-status.test.ts b/webui/src/web-components/sketch-network-status.test.ts
index bf0f4ba..6930910 100644
--- a/webui/src/web-components/sketch-network-status.test.ts
+++ b/webui/src/web-components/sketch-network-status.test.ts
@@ -1,33 +1,28 @@
 import { test, expect } from "@sand4rt/experimental-ct-web";
 import { SketchNetworkStatus } from "./sketch-network-status";
 
-// Test for the status indicator dot
-test("shows status indicator dot when connected", async ({ mount }) => {
+// Test that the network status component doesn't display visible content
+// since we've removed the green dot indicator
+test("network status component is not visible", async ({ mount }) => {
   const component = await mount(SketchNetworkStatus, {
     props: {
       connection: "connected",
     },
   });
 
-  // The status container and indicator should be visible
-  await expect(component.locator(".status-container")).toBeVisible();
-  await expect(component.locator(".status-indicator")).toBeVisible();
-  await expect(component.locator(".status-indicator")).toHaveClass(/connected/);
+  // The status container should exist but be hidden with display: none
+  await expect(component.locator(".status-container")).toHaveCSS("display", "none");
 });
 
-// Test that tooltip shows error message when provided
-test("includes error in tooltip when provided", async ({ mount }) => {
-  const errorMsg = "Connection error";
+// Test that the network status component remains invisible regardless of connection state
+test("network status component is not visible when disconnected", async ({ mount }) => {
   const component = await mount(SketchNetworkStatus, {
     props: {
       connection: "disconnected",
-      error: errorMsg,
+      error: "Connection error",
     },
   });
 
-  await expect(component.locator(".status-indicator")).toBeVisible();
-  await expect(component.locator(".status-indicator")).toHaveAttribute(
-    "title",
-    "Connection status: disconnected - Connection error",
-  );
+  // The status container should exist but be hidden with display: none
+  await expect(component.locator(".status-container")).toHaveCSS("display", "none");
 });
diff --git a/webui/src/web-components/sketch-network-status.ts b/webui/src/web-components/sketch-network-status.ts
index 8a5a883..7029975 100644
--- a/webui/src/web-components/sketch-network-status.ts
+++ b/webui/src/web-components/sketch-network-status.ts
@@ -16,43 +16,7 @@
 
   static styles = css`
     .status-container {
-      display: flex;
-      align-items: center;
-      justify-content: center;
-    }
-
-    .status-indicator {
-      width: 10px;
-      height: 10px;
-      border-radius: 50%;
-    }
-
-    .status-indicator.connected {
-      background-color: #2e7d32; /* Green */
-      box-shadow: 0 0 5px rgba(46, 125, 50, 0.5);
-    }
-
-    .status-indicator.disconnected {
-      background-color: #d32f2f; /* Red */
-      box-shadow: 0 0 5px rgba(211, 47, 47, 0.5);
-    }
-
-    .status-indicator.connecting {
-      background-color: #f57c00; /* Orange */
-      box-shadow: 0 0 5px rgba(245, 124, 0, 0.5);
-      animation: pulse 1.5s infinite;
-    }
-
-    @keyframes pulse {
-      0% {
-        opacity: 0.6;
-      }
-      50% {
-        opacity: 1;
-      }
-      100% {
-        opacity: 0.6;
-      }
+      display: none; /* Hide by default - we're removing the dot */
     }
   `;
 
@@ -71,15 +35,10 @@
   }
 
   render() {
-    // Only show the status indicator dot (no text)
+    // We no longer show any content as the dot is being removed
+    // The connection status will now be handled by the call-status component
     return html`
       <div class="status-container">
-        <div
-          class="status-indicator ${this.connection}"
-          title="Connection status: ${this.connection}${this.error
-            ? ` - ${this.error}`
-            : ""}"
-        ></div>
       </div>
     `;
   }