webui: migrate mobile components to SketchTailwindElement

Complete migration of all mobile web components from LitElement to
SketchTailwindElement base class with Tailwind CSS styling:

Components migrated:
- mobile-chat-input.ts: Chat input with file upload, textarea auto-resize
- mobile-chat.ts: Message display with markdown rendering and tool calls
- mobile-diff.ts: Git diff viewer with Monaco editor integration
- mobile-shell.ts: Main container coordinating mobile UI layout
- mobile-title.ts: Header with connection status and view switching

Key changes:
- Replaced LitElement inheritance with SketchTailwindElement
- Converted all CSS-in-JS styles to Tailwind utility classes
- Removed static styles blocks and shadow DOM styling
- Added custom animations via document.head for non-Tailwind effects
- Preserved all existing functionality and component interactions

Technical improvements:
- Consistent iOS safe area support with env() CSS functions
- Proper flexbox layouts for mobile responsive design
- Maintained accessibility with proper ARIA labels and focus states
- Enhanced hover and active states using Tailwind modifiers
- Optimized touch interactions with -webkit-overflow-scrolling

The mobile components now follow the established SketchTailwindElement
pattern while maintaining full feature parity with the original
shadow DOM implementations.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s21f840091392b02ek
diff --git a/webui/src/web-components/mobile-chat.test.ts b/webui/src/web-components/mobile-chat.test.ts
index 54ddf2e..1b57f03 100644
--- a/webui/src/web-components/mobile-chat.test.ts
+++ b/webui/src/web-components/mobile-chat.test.ts
@@ -68,17 +68,10 @@
   const errorBubble = component.locator(".message.error .message-bubble");
   await expect(errorBubble).toBeVisible();
 
-  // Verify the background color and text color
-  const bgColor = await errorBubble.evaluate((el) => {
-    return window.getComputedStyle(el).backgroundColor;
-  });
-  const textColor = await errorBubble.evaluate((el) => {
-    return window.getComputedStyle(el).color;
-  });
-
-  // Check that we have red-ish colors (these will be RGB values)
-  expect(bgColor).toMatch(/rgb\(255, 235, 238\)/); // #ffebee
-  expect(textColor).toMatch(/rgb\(211, 47, 47\)/); // #d32f2f
+  // Verify the element has the correct CSS classes for red styling
+  const errorBubbleClasses = await errorBubble.getAttribute("class");
+  expect(errorBubbleClasses).toContain("bg-red-50");
+  expect(errorBubbleClasses).toContain("text-red-700");
 });
 
 test("filters messages correctly", async ({ mount }) => {