## 1. Drag-and-Drop Infrastructure - [x] 1.1 Add JS interop function for drag-and-drop file reading — a small JS function that listens for `dragover`/`drop` events on a given element, reads the dropped file as text, and invokes a .NET callback with the filename and content - [x] 1.2 Add the JS interop script to `wwwroot/index.html` or a separate `.js` file referenced there - [x] 1.3 Wire the drag-and-drop JS interop to the `.message-list` element in Chat.razor — register on `OnAfterRenderAsync`, dispose on component disposal ## 2. File Upload Button - [x] 2.1 Add `MudIconButton` with attachment icon next to the send button in the input area - [x] 2.2 Add hidden `InputFile` component accepting `.html` files, triggered by the icon button click - [x] 2.3 Handle `InputFile.OnChange` — read the selected file content as string, trigger extraction ## 3. Drop Zone Visual Feedback - [x] 3.1 Add `_isDragOver` boolean state to Chat.razor, toggled by dragenter/dragleave events from JS interop - [x] 3.2 Add CSS class `.drag-over` to `.message-list` when `_isDragOver` is true — highlighted border, subtle overlay with "Drop email here" text - [x] 3.3 Add `.drag-over` styles to Chat.razor.css ## 4. Extraction Mode and Routing - [x] 4.1 Add `_isExtractionMode` boolean and `_emailHtml` string fields to Chat.razor - [x] 4.2 When an email file is read (via drop or file picker): set `_isExtractionMode = true`, store email HTML in `_emailHtml`, add a user message showing "[Uploaded: filename.html]" - [x] 4.3 Create `SendExtractionMessage()` method — builds `ExtractionRequest` with `_emailHtml` and conversation messages, calls `ChatApiClient.SendExtractionStreamingAsync()`, streams response into assistant message (same pattern as `SendMessage()`) - [x] 4.4 Modify `SendMessage()` — if `_isExtractionMode`, build `ExtractionRequest` with `_emailHtml` + all messages and call the extraction endpoint instead of the chat endpoint - [x] 4.5 On file drop/upload: call `SendExtractionMessage()` for the initial extraction - [x] 4.6 Modify `NewChat()` to reset `_isExtractionMode = false` and `_emailHtml = ""` ## 5. Extraction Mode Indicator - [x] 5.1 Add a `MudChip` or small banner below the tab header showing "Extraction Mode" when `_isExtractionMode` is true - [x] 5.2 Style the indicator in Chat.razor.css ## 6. Guard Rails - [x] 6.1 Reject non-.html files in both drop handler and InputFile handler — show a snackbar or inline message - [x] 6.2 Disable drop zone and file picker during streaming (`_isStreaming` flag) ## 7. Build and Verify - [x] 7.1 Build the solution (`dotnet build`) and confirm no compilation errors - [x] 7.2 Run all tests (`dotnet test`) and confirm they pass