webui: generate tailwind.css in esbuild.go, output to dist/

Move Tailwind CSS generation from npm script to esbuild.go build process
and output generated file to dist/tailwind.css instead of src/tailwind.css
to prevent tracking generated files in git.

Problems Solved:
- Generated CSS file was tracked in git causing unnecessary diffs
- Build process relied on manual npm script execution
- Generated CSS mixed with source files

Solution Architecture:
- Integrated Tailwind CSS generation into Go build process
- Moved output location to dist/ directory (already gitignored)
- Added automatic CSS generation during webui.Build()
- Moved @tailwindcss/cli from devDependencies to regular dependencies

Implementation Details:
- Added generateTailwindCSS() function to run tailwindcss CLI during build
- Modified Build() to call generateTailwindCSS() after npm ci
- Updated file copying logic to skip src/tailwind.css (no longer needed)
- Moved @tailwindcss/cli to regular dependencies to work with --omit dev
- Updated npm tailwind script to output to dist/tailwind.css
- Added src/tailwind.css to .gitignore to prevent accidental tracking

Files Modified:
- sketch/webui/esbuild.go: Added CSS generation and updated build process
- sketch/webui/.gitignore: Added src/tailwind.css exclusion
- sketch/webui/package.json: Moved @tailwindcss/cli to dependencies, updated script
- sketch/webui/src/tailwind.css: Removed from git tracking

The generated CSS is now properly separated from source files and
automatically created during the build process.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s3464450fc2c7851fk
diff --git a/webui/esbuild.go b/webui/esbuild.go
index 1c356ce..ee95943 100644
--- a/webui/esbuild.go
+++ b/webui/esbuild.go
@@ -121,6 +121,17 @@
 	return cacheDir, filepath.Join(cacheDir, "skui-"+hash+".zip"), nil
 }
 
+// generateTailwindCSS generates tailwind.css from global.css and outputs it to the specified directory
+func generateTailwindCSS(buildDir, outDir string) error {
+	// Run tailwindcss CLI to generate the CSS
+	cmd := exec.Command("npx", "tailwindcss", "-i", "./src/global.css", "-o", filepath.Join(outDir, "tailwind.css"))
+	cmd.Dir = buildDir
+	if out, err := cmd.CombinedOutput(); err != nil {
+		return fmt.Errorf("tailwindcss generation failed: %s: %v", out, err)
+	}
+	return nil
+}
+
 // copyMonacoAssets copies Monaco editor assets to the output directory
 func copyMonacoAssets(buildDir, outDir string) error {
 	// Create Monaco directories
@@ -202,6 +213,11 @@
 	if out, err := cmd.CombinedOutput(); err != nil {
 		return nil, fmt.Errorf("npm ci: %s: %v", out, err)
 	}
+
+	// Generate Tailwind CSS
+	if err := generateTailwindCSS(buildDir, tmpHashDir); err != nil {
+		return nil, fmt.Errorf("generate tailwind css: %w", err)
+	}
 	// Create all bundles
 	bundleTs := []string{
 		"src/web-components/sketch-app-shell.ts",
@@ -257,6 +273,10 @@
 		if strings.HasSuffix(path, "mockServiceWorker.js") {
 			return nil
 		}
+		// Skip src/tailwind.css as it will be generated
+		if path == "src/tailwind.css" {
+			return nil
+		}
 		if strings.HasSuffix(path, ".html") || strings.HasSuffix(path, ".css") || strings.HasSuffix(path, ".js") {
 			b, err := embedded.ReadFile(path)
 			if err != nil {