The Bewerben button wasn't flipping to "läuft…" until the next HTMX
poll because the DB row with finished_at=NULL was being inserted
inside the background thread — which had barely started by the time
the route already returned the re-rendered partial.
Split the work: _kick_apply now runs db.start_application() on the
request thread so the row exists before the response hits the wire.
Only the long-running Playwright call + finish_application are
offloaded to a worker via asyncio.create_task + to_thread. The new
_finish_apply_background re-reads prefs when it lands so circuit-
breaker state is current.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>