webui: add ESLint and eslint-typescript

I've historically found this stuff worthwhile, so let's swallow the pill.

Fortunately, sketch was happy to oblige.

- Install ESLint, @eslint/js, and typescript-eslint packages
- Configure eslint.config.mjs with recommended TypeScript ESLint rules
- Add browser globals support for DOM and web APIs
- Integrate ESLint into npm test workflow via package.json scripts
- Update Makefile to run lint checks as part of test suite
- Fix 249+ linting issues including:
  * Remove unused imports and variables (with _ prefix convention)
  * Fix case declaration issues with eslint-disable blocks
  * Remove unnecessary escape characters
  * Address prefer-const violations
  * Handle unused function parameters appropriately
- Configure ignore patterns to exclude dist/ and node_modules/
- Set rules to allow explicit 'any' types temporarily
- Convert warnings for ts-ignore, async promise executors, and unsafe optional chaining

Results:
- ESLint now runs successfully with 0 errors and only 6 warnings
- TypeScript compilation continues to work correctly
- Linting integrated into test workflow for continuous quality enforcement
- Codebase follows consistent ESLint TypeScript recommended practices

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: sd7b538be0a28d294k
diff --git a/webui/src/web-components/sketch-timeline.ts b/webui/src/web-components/sketch-timeline.ts
index b0edb42..b0e6d4c 100644
--- a/webui/src/web-components/sketch-timeline.ts
+++ b/webui/src/web-components/sketch-timeline.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
 import { html } from "lit";
 import { PropertyValues } from "lit";
 import { repeat } from "lit/directives/repeat.js";
@@ -679,7 +680,7 @@
     }
   }
 
-  private _handleScroll(event) {
+  private _handleScroll(_event) {
     if (!this.scrollContainer.value) return;
 
     const container = this.scrollContainer.value;
@@ -898,13 +899,13 @@
               ? repeat(
                   this.visibleMessages,
                   this.messageKey,
-                  (message, index) => {
+                  (message, _index) => {
                     // Find the previous message in the full filtered messages array
                     const filteredMessages = this.filteredMessages;
                     const messageIndex = filteredMessages.findIndex(
                       (m) => m === message,
                     );
-                    let previousMessage =
+                    const previousMessage =
                       messageIndex > 0
                         ? filteredMessages[messageIndex - 1]
                         : undefined;