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-shell.ts b/webui/src/web-components/mobile-shell.ts
index dd59ad8..5672be9 100644
--- a/webui/src/web-components/mobile-shell.ts
+++ b/webui/src/web-components/mobile-shell.ts
@@ -1,8 +1,9 @@
-import { css, html, LitElement } from "lit";
+import { html } from "lit";
 import { customElement, property, state } from "lit/decorators.js";
 import { ConnectionStatus, DataManager } from "../data";
 import { AgentMessage, State } from "../types";
 import { aggregateAgentMessages } from "./aggregateAgentMessages";
+import { SketchTailwindElement } from "./sketch-tailwind-element";
 
 import "./mobile-title";
 import "./mobile-chat";
@@ -10,7 +11,7 @@
 import "./mobile-diff";
 
 @customElement("mobile-shell")
-export class MobileShell extends LitElement {
+export class MobileShell extends SketchTailwindElement {
   private dataManager = new DataManager();
 
   @state()
@@ -25,55 +26,6 @@
   @state()
   currentView: "chat" | "diff" = "chat";
 
-  static styles = css`
-    :host {
-      display: flex;
-      flex-direction: column;
-      /* Use dynamic viewport height for better iOS support */
-      height: 100dvh;
-      /* Fallback for browsers that don't support dvh */
-      height: 100vh;
-      /* iOS Safari custom property fallback */
-      height: calc(var(--vh, 1vh) * 100);
-      /* Additional iOS Safari fix */
-      min-height: 100vh;
-      min-height: -webkit-fill-available;
-      width: 100vw;
-      background-color: #ffffff;
-      font-family:
-        -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", sans-serif;
-    }
-
-    .mobile-container {
-      display: flex;
-      flex-direction: column;
-      height: 100%;
-      overflow: hidden;
-    }
-
-    mobile-title {
-      flex-shrink: 0;
-    }
-
-    mobile-chat {
-      flex: 1;
-      overflow: hidden;
-      min-height: 0;
-    }
-
-    mobile-diff {
-      flex: 1;
-      overflow: hidden;
-      min-height: 0;
-    }
-
-    mobile-chat-input {
-      flex-shrink: 0;
-      /* Ensure proper height calculation */
-      min-height: 64px;
-    }
-  `;
-
   connectedCallback() {
     super.connectedCallback();
     this.setupDataManager();
@@ -166,8 +118,12 @@
       (this.state?.outstanding_tool_calls?.length ?? 0) > 0;
 
     return html`
-      <div class="mobile-container">
+      <div
+        class="flex flex-col bg-white font-sans w-screen overflow-hidden"
+        style="height: 100dvh; height: 100vh; height: calc(var(--vh, 1vh) * 100); min-height: 100vh; min-height: -webkit-fill-available;"
+      >
         <mobile-title
+          class="flex-shrink-0"
           .connectionStatus=${this.connectionStatus}
           .isThinking=${isThinking}
           .skabandAddr=${this.state?.skaband_addr}
@@ -179,13 +135,17 @@
         ${this.currentView === "chat"
           ? html`
               <mobile-chat
+                class="flex-1 overflow-hidden min-h-0"
                 .messages=${this.messages}
                 .isThinking=${isThinking}
               ></mobile-chat>
             `
-          : html` <mobile-diff></mobile-diff> `}
+          : html`<mobile-diff
+              class="flex-1 overflow-hidden min-h-0"
+            ></mobile-diff>`}
 
         <mobile-chat-input
+          class="flex-shrink-0 min-h-[64px]"
           .disabled=${this.connectionStatus !== "connected"}
           @send-message=${this.handleSendMessage}
         ></mobile-chat-input>