Instant feedback when canceling estimate generation

Cancel button now responds immediately with a brief placeholder instead of waiting for the server, preventing confusing error states mid-cancel.

Bug Fixes

Clicking Cancel on an estimate now instantly unmounts the progress card and shows a brief "Cancelling estimate…" placeholder while the server-side cleanup completes. Previously, the cancel would await the entire round-trip before updating the UI, so the realtime subscription would often flip the run to CANCELED and flash a red "Generation failed" state — confusing since you just clicked Cancel.

We also improved error messages to tell you why generation failed: "AI worker did not pick up the job" for timeout, "generation timed out" for long waits, and "generation was canceled" for manual cancellations. Finally, estimate jobs now have a 90-second queue TTL instead of the default 10 minutes, so stalled jobs fail faster and don't clutter the queue.