* refactor(playback): extract fadeOut helper
Used by playAlbum.ts today; about to be reused for the radio delete
fade-out so it lives in its own module instead of being copy-pasted.
* fix(player): disable Repeat button while a radio stream is active
Matches the Prev / Next buttons that already gate on isRadio — repeat
has no meaning for a live stream, and the live tooltip plus accent
colour suggested it was interactive.
* fix(radio): fade out before deleting the playing station
Mirrors the 700 ms fade-out playAlbum uses on track changes — beats
the abrupt cut when the deleted station is the one currently on air.
* fix(radio): add Play/Stop tooltip to the cover-overlay button
Cast / X icon now describes itself, matching the favourite and delete
buttons that already had tooltips.
* fix(radio): use Square stop icon on the active card
The play-overlay and delete buttons both used X, making it ambiguous
which click stopped the stream and which deleted the station. Stop
gets a filled Square; delete keeps its X.
* fix(radio): cancel auto-reconnect when the user pauses a stream
Closes#779.
Root cause: a 'stalled' event during a paused stream still scheduled a
4 s reconnect timer that called play(), and the timer was not cancelled
on pauseRadio(). On macOS WKWebView the underlying TCP socket droops
roughly a minute after pause, the browser fires 'stalled', and the
stream resumes against the user's intent. The store's isPlaying flag
stays false because nothing on the reconnect path syncs it, so the
play/pause button stops matching reality.
Fix: skip the schedule when radioAudio.paused, re-check inside the
timer callback (covers a pause within the 4 s window), and clear any
pending timer in pauseRadio().
* docs: changelog for radio card polish + paused-stream fix (#786)
Each src/locales/<lang>.ts (~1800 LOC) becomes a folder src/locales/<lang>/
with one module per i18n namespace (44 each) plus an index.ts barrel that
reassembles <lang>Translation in the original key order.
Mechanical, script-driven split with a JSON round-trip check: every
locale object is byte-identical to its pre-split form. i18n.ts is
unchanged — './locales/<lang>' now resolves to the folder index.
The per-namespace settings.ts files land ~440-460 LOC; a single i18n
namespace is the natural, non-arbitrary split unit for a flat string
table, so they are intentionally left whole.