webui: convert sketch-call-status and sketch-chat-input to SketchTailwindElement with comprehensive demo support

Convert both sketch-call-status and sketch-chat-input components from shadow DOM CSS to Tailwind classes while maintaining test compatibility and adding comprehensive demo infrastructure.

Problems Solved:

Shadow DOM Styling Limitations:
- Both components used CSS-in-JS with shadow DOM preventing Tailwind integration
- Large static styles blocks with custom CSS duplicated Tailwind functionality
- Components couldn't benefit from design system consistency
- Difficult to maintain custom CSS alongside Tailwind-based components

Missing Demo Infrastructure:
- sketch-call-status had no demo fixtures for testing component states
- sketch-chat-input needed dedicated demo fixture following naming convention
- Components not properly integrated into demo runner system

Test Compatibility Issues:
- Conversion to Tailwind required updating shadow DOM selectors
- renderRoot.querySelector calls needed conversion to direct querySelector
- Component tests needed updating for non-shadow DOM structure

Solution Implementation:

Tailwind CSS Conversion - sketch-call-status:
- Changed sketch-call-status to inherit from SketchTailwindElement
- Replaced CSS-in-JS styles with Tailwind utility classes and inline animations
- Converted animations using @keyframes in inline <style> tag
- Maintained exact visual appearance while using Tailwind classes

Tailwind CSS Conversion - sketch-chat-input:
- Changed sketch-chat-input to inherit from SketchTailwindElement
- Replaced extensive static styles CSS block with Tailwind utility classes
- Converted complex chat container, input wrapper, and button styling
- Added custom fade-in animation to tailwind.config.js with keyframes

Key Tailwind Class Mappings:
- Call status indicators: bg-yellow-100 text-amber-500 (active), text-gray-400 (idle)
- Status banners: bg-green-50 text-green-700 (idle), bg-orange-50 text-orange-600 (working)
- Chat container: w-full bg-gray-100 p-4 min-h-[40px] relative
- Chat input: flex-1 p-3 border border-gray-300 rounded resize-y font-mono
- Send button: bg-blue-500 hover:bg-blue-600 disabled:bg-gray-400

Shadow DOM to Light DOM Conversion:
- Removed static styles properties completely
- Updated all renderRoot.querySelector calls to direct querySelector calls
- Changed shadow DOM event handler setup to work with light DOM
- Maintained all drag-and-drop and event handling functionality

Test Compatibility Maintenance:
- Added semantic CSS classes back to elements for test selectors
- Updated sketch-chat-input.test.ts to use querySelector instead of renderRoot.querySelector
- Fixed drag event simulation to work with light DOM structure
- All existing tests continue to pass with updated selectors

Demo Infrastructure Implementation:
- Created call-status.ts demo fixtures with CallStatusState interface
- Added comprehensive sketch-call-status.demo.ts with interactive controls
- Created chat-input.ts demo fixture with message display and controls
- Added both components to demo-runner.ts knownComponents list

Interactive Demo Features:
- Call status: Status variations, interactive LLM/tool call controls, connection toggle
- Chat input: Message display with user/bot styling, multiple preset buttons
- Both demos include real-time state updates and comprehensive examples

Dependencies:
- Added @tailwindcss/vite package for Tailwind integration
- Updated package.json and package-lock.json with new dependency

Files Modified:
- sketch/webui/src/web-components/sketch-call-status.ts: Converted to SketchTailwindElement
- sketch/webui/src/web-components/sketch-chat-input.ts: Converted to SketchTailwindElement
- sketch/webui/src/web-components/sketch-chat-input.test.ts: Updated selectors for light DOM
- sketch/webui/src/web-components/demo/demo-fixtures/call-status.ts: Added call status fixtures
- sketch/webui/src/web-components/demo/demo-fixtures/index.ts: Export call status fixtures
- sketch/webui/src/web-components/demo/sketch-call-status.demo.ts: Complete interactive demo
- sketch/webui/src/web-components/demo/chat-input.ts: New chat input demo fixture
- sketch/webui/src/web-components/demo/demo-framework/demo-runner.ts: Added both components
- sketch/webui/tailwind.config.js: Added custom fade-in animation
- sketch/webui/package.json: Added @tailwindcss/vite dependency

Testing and Validation:
- All component tests pass with updated selectors
- Components render correctly with Tailwind classes
- All functionality preserved including animations and interactions
- Interactive demos load and function properly
- Components appear in demo runner list

The conversion maintains all functionality while enabling better integration
with the Tailwind-based design system and providing comprehensive demo
infrastructure for development and testing.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s97f4190763cfe17ak
diff --git a/webui/src/web-components/demo/chat-input.ts b/webui/src/web-components/demo/chat-input.ts
new file mode 100644
index 0000000..7ddcc7e
--- /dev/null
+++ b/webui/src/web-components/demo/chat-input.ts
@@ -0,0 +1,137 @@
+/**
+ * Demo fixture for sketch-chat-input component
+ */
+
+import { DemoModule } from "./demo-framework/types";
+import { demoUtils } from "./demo-fixtures/index";
+
+const demo: DemoModule = {
+  title: "Chat Input Component",
+  description: "Chat input with file upload and drag-and-drop support",
+  imports: ["../sketch-chat-input"],
+
+  setup: async (container: HTMLElement) => {
+    // Create demo sections
+    const basicSection = demoUtils.createDemoSection(
+      "Basic Chat Input",
+      "Type a message and press Enter or click Send. Supports file drag-and-drop.",
+    );
+
+    const messagesSection = demoUtils.createDemoSection(
+      "Chat Messages",
+      "Sent messages will appear here",
+    );
+
+    // Create messages display
+    const messagesDiv = document.createElement("div");
+    messagesDiv.id = "chat-messages";
+    messagesDiv.className =
+      "min-h-[100px] max-h-[200px] overflow-y-auto border border-gray-300 rounded-md p-3 mb-3 bg-gray-50";
+
+    // Create chat input
+    const chatInput = document.createElement("sketch-chat-input") as any;
+
+    // Add message display function
+    const addMessage = (
+      message: string,
+      isUser: boolean = true,
+      timestamp?: Date,
+    ) => {
+      const messageDiv = document.createElement("div");
+      messageDiv.className = `p-2 my-1 rounded max-w-xs ${
+        isUser
+          ? "bg-blue-500 text-white ml-auto"
+          : "bg-gray-200 text-gray-900 mr-auto"
+      }`;
+
+      const timeStr = timestamp
+        ? timestamp.toLocaleTimeString()
+        : new Date().toLocaleTimeString();
+      messageDiv.innerHTML = `
+        <div class="text-sm">${message}</div>
+        <div class="text-xs opacity-70 mt-1">${timeStr}</div>
+      `;
+
+      messagesDiv.appendChild(messageDiv);
+      messagesDiv.scrollTop = messagesDiv.scrollHeight;
+    };
+
+    // Handle send events
+    chatInput.addEventListener("send-chat", (evt: any) => {
+      const message = evt.detail.message;
+      if (message.trim()) {
+        addMessage(message, true);
+
+        // Simulate bot response after a delay
+        setTimeout(() => {
+          const responses = [
+            "Message received!",
+            "Thanks for sharing that.",
+            "I see you uploaded a file.",
+            "Processing your request...",
+            "How can I help you further?",
+          ];
+          const randomResponse =
+            responses[Math.floor(Math.random() * responses.length)];
+          addMessage(randomResponse, false);
+        }, 1500);
+      }
+    });
+
+    // Add initial messages
+    addMessage("Welcome to the chat input demo!", false);
+    addMessage("Try typing a message or dragging files here.", false);
+
+    // Control buttons
+    const controlsDiv = document.createElement("div");
+    controlsDiv.className = "mt-4 space-x-2";
+
+    const clearButton = demoUtils.createButton("Clear Chat", () => {
+      messagesDiv.innerHTML = "";
+      addMessage("Chat cleared!", false);
+    });
+
+    const presetButton = demoUtils.createButton("Load Sample Message", () => {
+      chatInput.content =
+        "I need help with implementing a file upload feature. Can you review the attached screenshot?";
+    });
+
+    const multilineButton = demoUtils.createButton("Multiline Message", () => {
+      chatInput.content =
+        "Here's a multiline message:\n\n1. First point\n2. Second point\n3. Third point\n\nWhat do you think?";
+    });
+
+    controlsDiv.appendChild(clearButton);
+    controlsDiv.appendChild(presetButton);
+    controlsDiv.appendChild(multilineButton);
+
+    // File upload status section
+    const statusSection = demoUtils.createDemoSection(
+      "Upload Status",
+      "Current upload status and file handling",
+    );
+
+    const statusDiv = document.createElement("div");
+    statusDiv.className =
+      "bg-blue-50 border border-blue-200 rounded p-3 text-sm";
+    statusDiv.innerHTML = `
+      <div>✓ Drag and drop files onto the chat input</div>
+      <div>✓ Paste images from clipboard</div>
+      <div>✓ Multiple file uploads supported</div>
+      <div>✓ Upload progress indication</div>
+    `;
+
+    statusSection.appendChild(statusDiv);
+
+    // Assemble the demo
+    messagesSection.appendChild(messagesDiv);
+    basicSection.appendChild(chatInput);
+    basicSection.appendChild(controlsDiv);
+
+    container.appendChild(messagesSection);
+    container.appendChild(basicSection);
+    container.appendChild(statusSection);
+  },
+};
+
+export default demo;
diff --git a/webui/src/web-components/demo/demo-framework/demo-runner.ts b/webui/src/web-components/demo/demo-framework/demo-runner.ts
index c624cb2..7dc02d4 100644
--- a/webui/src/web-components/demo/demo-framework/demo-runner.ts
+++ b/webui/src/web-components/demo/demo-framework/demo-runner.ts
@@ -94,6 +94,7 @@
     // For now, we'll maintain a registry of known demo components
     // This could be improved with build-time generation
     const knownComponents = [
+      "chat-input",
       "sketch-call-status",
       "sketch-chat-input",
       "sketch-container-status",