## What?
Track every IDLE watcher goroutine on the `IdleWatcher` via
`sync.WaitGroup` so `StopAllAndWait` catches lingering goroutines whose
map entry was already replaced. Add `StopAllAndWaitTimeout` for shutdown
paths that need a bounded wait, and switch the daemon shutdown from the
fire-and-forget `StopAll()` to the bounded variant so one stuck IMAP
connection cannot block the daemon.
## Why?
Closes #731 (filed by @andrinoff). The existing pattern in
`fetcher/idle.go:48-60` and `:72-75` does `close(existing.stop);
delete(w.watchers, account.ID)` and leaves the goroutine to tear down in
the background. If the IMAP connection is stuck (server stops responding
mid-IDLE, network hangs without RST), the goroutine never exits, the map
no longer holds the `done` channel, and `StopAllAndWait()` has no way to
see it. The original report's suggested fix was "use WaitGroup or ensure
goroutines terminate within timeout" - this PR does both.
The daemon side surfaces the problem: `daemon/daemon.go:129` previously
called `idleWatcher.StopAll()` and immediately continued to
`closeAllClients()`. If any underlying connection hung, the lingering
IDLE goroutines outlived the daemon's shutdown path with no log entry.
The new bounded-wait shutdown logs `idle watcher: stop timed out` when
goroutines don't exit within 5s, so operators see leaks instead of
silently losing them.
Two new tests cover both behaviors: replaced-goroutine tracking via
WaitGroup, and timeout-on-slow-exit returning `ErrStopTimeout`.
Fixes #731