webui: dark mode support to demo fmwk, tool cards

Demo framework fixes:
- sketch-push-button.demo.ts: add dark variants for bg, border, text colors
- chat-input.ts: add dark variants for message containers and status sections
- demo-runner.ts: replace inline error styles with Tailwind dark mode classes
- sketch-call-status.demo.ts: fix hardcoded white backgrounds in status cards
- sketch-diff-range-picker.demo.ts: add dark variants to picker and status displays
- sketch-timeline-message.demo.ts: fix message container backgrounds
- sketch-view-mode-select.demo.ts: comprehensive dark mode for all scenarios

Tool card fixes:
- Update shared createPreElement function with dark:bg-gray-700/dark:text-gray-100
- bash tool: fix command display and result areas
- think tool: fix input content area with proper dark background
- patch tool: comprehensive diff rendering with dark variants for added/removed/context lines
- codereview tool: inherits dark mode through shared utilities

All components now use consistent dark mode patterns with proper contrast:
bg-white dark:bg-gray-800, border-gray-200 dark:border-gray-700,
text-gray-600 dark:text-gray-300, matching existing components.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s8ac5253d0cbaa3ack
diff --git a/webui/src/web-components/demo/chat-input.ts b/webui/src/web-components/demo/chat-input.ts
index 7ddcc7e..ca72939 100644
--- a/webui/src/web-components/demo/chat-input.ts
+++ b/webui/src/web-components/demo/chat-input.ts
@@ -26,7 +26,7 @@
     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";
+      "min-h-[100px] max-h-[200px] overflow-y-auto border border-gray-300 dark:border-gray-600 rounded-md p-3 mb-3 bg-gray-50 dark:bg-gray-900";
 
     // Create chat input
     const chatInput = document.createElement("sketch-chat-input") as any;
@@ -41,7 +41,7 @@
       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"
+          : "bg-gray-200 dark:bg-gray-700 text-gray-900 dark:text-gray-100 mr-auto"
       }`;
 
       const timeStr = timestamp
@@ -113,7 +113,7 @@
 
     const statusDiv = document.createElement("div");
     statusDiv.className =
-      "bg-blue-50 border border-blue-200 rounded p-3 text-sm";
+      "bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded p-3 text-sm text-blue-800 dark:text-blue-200";
     statusDiv.innerHTML = `
       <div>✓ Drag and drop files onto the chat input</div>
       <div>✓ Paste images from clipboard</div>
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 6b59c38..680651b 100644
--- a/webui/src/web-components/demo/demo-framework/demo-runner.ts
+++ b/webui/src/web-components/demo/demo-framework/demo-runner.ts
@@ -195,19 +195,12 @@
    */
   private showError(message: string, error: any): void {
     this.container.innerHTML = `
-      <div style="
-        padding: 20px;
-        background: #fee;
-        border: 1px solid #fcc;
-        border-radius: 4px;
-        color: #800;
-        font-family: monospace;
-      ">
-        <h3>Demo Error</h3>
-        <p><strong>${message}</strong></p>
-        <details>
-          <summary>Error Details</summary>
-          <pre>${error.stack || error.message || error}</pre>
+      <div class="p-5 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded text-red-800 dark:text-red-200 font-mono">
+        <h3 class="text-lg font-semibold mb-2">Demo Error</h3>
+        <p class="mb-4"><strong>${message}</strong></p>
+        <details class="text-sm">
+          <summary class="cursor-pointer hover:text-red-600 dark:hover:text-red-300">Error Details</summary>
+          <pre class="mt-2 p-2 bg-red-100 dark:bg-red-800/30 rounded text-xs overflow-auto">${error.stack || error.message || error}</pre>
         </details>
       </div>
     `;
diff --git a/webui/src/web-components/demo/sketch-call-status.demo.ts b/webui/src/web-components/demo/sketch-call-status.demo.ts
index d17e2f0..91502dd 100644
--- a/webui/src/web-components/demo/sketch-call-status.demo.ts
+++ b/webui/src/web-components/demo/sketch-call-status.demo.ts
@@ -39,8 +39,8 @@
       label: string,
     ) => {
       const wrapper = document.createElement("div");
-      wrapper.style.cssText =
-        "margin: 15px 0; padding: 10px; border: 1px solid #e1e5e9; border-radius: 6px; background: white;";
+      wrapper.className =
+        "my-4 p-3 border border-gray-200 dark:border-gray-700 rounded bg-white dark:bg-gray-800";
 
       const labelEl = document.createElement("h4");
       labelEl.textContent = label;
@@ -215,8 +215,8 @@
     statusVariationsSection.appendChild(workingDisconnectedStatus);
 
     const interactiveWrapper = document.createElement("div");
-    interactiveWrapper.style.cssText =
-      "padding: 10px; border: 1px solid #e1e5e9; border-radius: 6px; background: white;";
+    interactiveWrapper.className =
+      "p-3 border border-gray-200 dark:border-gray-700 rounded bg-white dark:bg-gray-800";
     interactiveWrapper.appendChild(interactiveStatus);
     interactiveWrapper.appendChild(controlsDiv);
     interactiveSection.appendChild(interactiveWrapper);
diff --git a/webui/src/web-components/demo/sketch-diff-range-picker.demo.ts b/webui/src/web-components/demo/sketch-diff-range-picker.demo.ts
index 0ce1358..f70f72f 100644
--- a/webui/src/web-components/demo/sketch-diff-range-picker.demo.ts
+++ b/webui/src/web-components/demo/sketch-diff-range-picker.demo.ts
@@ -30,14 +30,9 @@
     const rangePickerElement = document.createElement(
       "sketch-diff-range-picker",
     );
-    rangePickerElement.style.cssText = `
-      width: 100%;
-      max-width: 800px;
-      margin: 20px 0;
-      padding: 16px;
-      border: 1px solid #e0e0e0;
-      border-radius: 8px;
-      background: white;
+    rangePickerElement.className = `
+      w-full max-w-3xl my-5 p-4 border border-gray-300 dark:border-gray-600 
+      rounded-lg bg-white dark:bg-gray-800
     `;
 
     // Set up the git service
@@ -45,15 +40,9 @@
 
     // Create status display
     const statusDisplay = document.createElement("div");
-    statusDisplay.style.cssText = `
-      padding: 12px;
-      margin: 16px 0;
-      background: var(--demo-fixture-section-bg);
-      border-radius: 6px;
-      border: 1px solid #e9ecef;
-      font-family: monospace;
-      font-size: 14px;
-      line-height: 1.4;
+    statusDisplay.className = `
+      p-3 my-4 bg-gray-50 dark:bg-gray-800 rounded border 
+      border-gray-200 dark:border-gray-700 font-mono text-sm leading-relaxed
     `;
     statusDisplay.innerHTML = `
       <div><strong>Status:</strong> No range selected</div>
@@ -84,12 +73,9 @@
 
     // Add some demo instructions
     const instructionsDiv = document.createElement("div");
-    instructionsDiv.style.cssText = `
-      margin: 20px 0;
-      padding: 16px;
-      background: var(--demo-instruction-bg);
-      border-radius: 6px;
-      border-left: 4px solid #2196f3;
+    instructionsDiv.className = `
+      my-5 p-4 bg-blue-50 dark:bg-blue-900/20 rounded 
+      border-l-4 border-blue-500 dark:border-blue-400
     `;
     instructionsDiv.innerHTML = `
       <h3 style="margin: 0 0 8px 0; color: #1976d2;">Demo Instructions:</h3>
diff --git a/webui/src/web-components/demo/sketch-push-button.demo.ts b/webui/src/web-components/demo/sketch-push-button.demo.ts
index f7b83fd..4405a9e 100644
--- a/webui/src/web-components/demo/sketch-push-button.demo.ts
+++ b/webui/src/web-components/demo/sketch-push-button.demo.ts
@@ -12,18 +12,20 @@
   render() {
     return html`
       <div
-        class="p-4 bg-white rounded-lg shadow-sm border border-gray-200 max-w-md mx-auto"
+        class="p-4 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 max-w-md mx-auto"
       >
-        <h2 class="text-lg font-semibold mb-4">Push Button Demo</h2>
+        <h2 class="text-lg font-semibold mb-4 text-gray-900 dark:text-gray-100">
+          Push Button Demo
+        </h2>
 
         <div class="mb-4">
-          <p class="text-sm text-gray-600 mb-2">
+          <p class="text-sm text-gray-600 dark:text-gray-300 mb-2">
             Test the push button component:
           </p>
           <sketch-push-button></sketch-push-button>
         </div>
 
-        <div class="text-xs text-gray-500">
+        <div class="text-xs text-gray-500 dark:text-gray-400">
           <p>Click the push button to test:</p>
           <ul class="list-disc list-inside mt-1">
             <li>Modal opens with git information</li>
diff --git a/webui/src/web-components/demo/sketch-timeline-message.demo.ts b/webui/src/web-components/demo/sketch-timeline-message.demo.ts
index 68f60c4..a101101 100644
--- a/webui/src/web-components/demo/sketch-timeline-message.demo.ts
+++ b/webui/src/web-components/demo/sketch-timeline-message.demo.ts
@@ -45,8 +45,8 @@
       state = mockState,
     ) => {
       const wrapper = document.createElement("div");
-      wrapper.style.cssText =
-        "margin: 15px 0; padding: 15px; border: 1px solid #e1e5e9; border-radius: 6px; background: white;";
+      wrapper.className =
+        "my-4 p-4 border border-gray-200 dark:border-gray-700 rounded bg-white dark:bg-gray-800";
 
       const labelEl = document.createElement("h4");
       labelEl.textContent = label;
@@ -178,8 +178,8 @@
     interactiveMessage.open = true;
 
     const interactiveWrapper = document.createElement("div");
-    interactiveWrapper.style.cssText =
-      "padding: 15px; border: 1px solid #e1e5e9; border-radius: 6px; background: white;";
+    interactiveWrapper.className =
+      "p-4 border border-gray-200 dark:border-gray-700 rounded bg-white dark:bg-gray-800";
     interactiveWrapper.appendChild(interactiveMessage);
 
     // Control buttons for interactive demo
diff --git a/webui/src/web-components/demo/sketch-view-mode-select.demo.ts b/webui/src/web-components/demo/sketch-view-mode-select.demo.ts
index 3688b30..71354bc 100644
--- a/webui/src/web-components/demo/sketch-view-mode-select.demo.ts
+++ b/webui/src/web-components/demo/sketch-view-mode-select.demo.ts
@@ -50,13 +50,9 @@
     // Status display for basic selector
     const basicStatus = document.createElement("div");
     basicStatus.id = "basic-status";
-    basicStatus.style.cssText = `
-      margin-top: 15px;
-      padding: 10px;
-      background: #f6f8fa;
-      border-radius: 6px;
-      font-family: monospace;
-      font-size: 14px;
+    basicStatus.className = `
+      mt-4 p-3 bg-gray-50 dark:bg-gray-800 rounded font-mono text-sm 
+      text-gray-900 dark:text-gray-100
     `;
 
     const updateBasicStatus = () => {
@@ -86,11 +82,9 @@
 
     viewModeScenarios.forEach((scenario) => {
       const scenarioCard = document.createElement("div");
-      scenarioCard.style.cssText = `
-        padding: 15px;
-        border: 1px solid #d0d7de;
-        border-radius: 8px;
-        background: white;
+      scenarioCard.className = `
+        p-4 border border-gray-300 dark:border-gray-600 rounded-lg 
+        bg-white dark:bg-gray-800
       `;
 
       const scenarioTitle = document.createElement("h4");
@@ -134,7 +128,7 @@
     // Status display for interactive selector
     const interactiveStatus = document.createElement("div");
     interactiveStatus.id = "interactive-status";
-    interactiveStatus.style.cssText = basicStatus.style.cssText;
+    interactiveStatus.className = basicStatus.className;
 
     const updateInteractiveStatus = () => {
       interactiveStatus.innerHTML = `
@@ -159,11 +153,8 @@
 
     // Custom controls for interactive testing
     const customControls = document.createElement("div");
-    customControls.style.cssText = `
-      margin: 15px 0;
-      padding: 15px;
-      background: #f6f8fa;
-      border-radius: 6px;
+    customControls.className = `
+      my-4 p-4 bg-gray-50 dark:bg-gray-800 rounded
     `;
 
     const addLinesButton = demoUtils.createButton("Add +5 Lines", () => {
@@ -258,11 +249,8 @@
     containerExamples.forEach((example) => {
       // Create container wrapper
       const wrapper = document.createElement("div");
-      wrapper.style.cssText = `
-        border: 2px solid;
-        border-radius: 8px;
-        padding: 15px;
-        background: #f9f9f9;
+      wrapper.className = `
+        border-2 rounded-lg p-4 bg-gray-50 dark:bg-gray-800 ${example.borderColor}
       `;
       wrapper.className = example.borderColor;
 
@@ -278,12 +266,9 @@
       // Create constrained container for the component
       const componentContainer = document.createElement("div");
       componentContainer.className = "@container";
-      componentContainer.style.cssText = `
-        width: ${example.width};
-        border: 1px dashed #ccc;
-        padding: 10px;
-        background: white;
-        border-radius: 4px;
+      componentContainer.className = `
+        border border-dashed border-gray-400 dark:border-gray-600 p-3 
+        bg-white dark:bg-gray-800 rounded ${example.containerClass}
       `;
 
       // Create the component
@@ -317,13 +302,9 @@
     // Create interactive container
     const interactiveContainer = document.createElement("div");
     interactiveContainer.className = "@container";
-    interactiveContainer.style.cssText = `
-      border: 2px solid #007acc;
-      border-radius: 8px;
-      padding: 15px;
-      background: #f0f8ff;
-      transition: width 0.3s ease;
-      width: 700px;
+    interactiveContainer.className = `
+      @container border-2 border-blue-600 dark:border-blue-400 rounded-lg p-4 
+      bg-blue-50 dark:bg-blue-900/20 transition-all duration-300 w-[700px]
     `;
 
     // Create interactive component
diff --git a/webui/src/web-components/sketch-tool-card.ts b/webui/src/web-components/sketch-tool-card.ts
index c96d8e0..881285a 100644
--- a/webui/src/web-components/sketch-tool-card.ts
+++ b/webui/src/web-components/sketch-tool-card.ts
@@ -63,7 +63,7 @@
 // Shared utility function for creating Tailwind pre elements
 function createPreElement(content: string, additionalClasses: string = "") {
   return html`<pre
-    class="bg-gray-200 text-black p-2 rounded whitespace-pre-wrap break-words max-w-full w-full box-border overflow-wrap-break-word ${additionalClasses}"
+    class="bg-gray-200 dark:bg-gray-700 text-black dark:text-gray-100 p-2 rounded whitespace-pre-wrap break-words max-w-full w-full box-border overflow-wrap-break-word ${additionalClasses}"
   >
 ${content}</pre
   >`;
@@ -101,7 +101,7 @@
     >
       <div class="w-full relative">
         <pre
-          class="bg-gray-200 text-black p-2 rounded whitespace-pre-wrap break-words max-w-full w-full box-border overflow-wrap-break-word w-full mb-0 rounded-t rounded-b-none box-border"
+          class="bg-gray-200 dark:bg-gray-700 text-black dark:text-gray-100 p-2 rounded whitespace-pre-wrap break-words max-w-full w-full box-border overflow-wrap-break-word w-full mb-0 rounded-t rounded-b-none box-border"
         >
 ${backgroundIcon}${slowIcon}${inputData?.command}</pre
         >
@@ -211,19 +211,29 @@
 
     const coloredLines = lines.map((line) => {
       if (line.startsWith("+")) {
-        return html`<div class="text-green-600 bg-green-50">${line}</div>`;
+        return html`<div
+          class="text-green-600 dark:text-green-400 bg-green-50 dark:bg-green-900/20"
+        >
+          ${line}
+        </div>`;
       } else if (line.startsWith("-")) {
-        return html`<div class="text-red-600 bg-red-50">${line}</div>`;
+        return html`<div
+          class="text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20"
+        >
+          ${line}
+        </div>`;
       } else if (line.startsWith("@@")) {
         // prettier-ignore
-        return html`<div class="text-cyan-600 bg-cyan-50 font-semibold">${line}</div>`;
+        return html`<div class="text-cyan-600 dark:text-cyan-400 bg-cyan-50 dark:bg-cyan-900/20 font-semibold">${line}</div>`;
       } else {
-        return html`<div class="text-gray-800">${line}</div>`;
+        return html`<div class="text-gray-800 dark:text-gray-200">
+          ${line}
+        </div>`;
       }
     });
 
     return html`<pre
-      class="bg-gray-100 text-xs p-2 rounded whitespace-pre-wrap break-words max-w-full w-full box-border overflow-x-auto font-mono"
+      class="bg-gray-100 dark:bg-gray-800 text-xs p-2 rounded whitespace-pre-wrap break-words max-w-full w-full box-border overflow-x-auto font-mono text-gray-900 dark:text-gray-100"
     >
       ${coloredLines}
     </pre
@@ -285,7 +295,7 @@
     </span>`;
 
     const inputContent = html`<div
-      class="overflow-x-auto mb-1 font-mono px-2 py-1 bg-gray-200 rounded select-text cursor-text text-sm leading-relaxed"
+      class="overflow-x-auto mb-1 font-mono px-2 py-1 bg-gray-200 dark:bg-gray-700 rounded select-text cursor-text text-sm leading-relaxed text-gray-900 dark:text-gray-100"
     >
       <div class="markdown-content">
         ${unsafeHTML(renderMarkdown(thoughts))}