Three follow-up fixes after browser testing:
1. Clicking a source whose results are already cached was closing the
results dropdown. The outside-click handler treated the icon click
as "outside" because the icon row lives above the input wrapper, not
inside it. The icon click handler now calls stopPropagation so the
document handler never runs. Also added an `#enh-source-row`
whitelist to the search-page outside-click handler as a second
layer of defense.
2. The icon chips used generic emojis (🎵, 🍎, 🎶, etc.) which don't
convey brand identity. SOURCE_LABELS now carries a `logo` URL per
source (mirroring the existing constants in core.js): the real
Spotify / Apple Music / Deezer / Discogs / MusicBrainz / Hydrabase /
Soulseek brand logos render as <img> inside the chip. Music Videos
stays on emoji since the codebase has no YouTube-specific logo
constant. renderSourceRow (Search page) and _gsSourceRowHtml (global
widget) both honor the new field; loading state still overrides
with an hourglass.
3. When Soulseek was selected, the icon row appeared clipped at the
top of the page. Caused by the flex parent (.downloads-main-panel)
compressing the row when .search-section.active competes for space
with flex-grow:1. Added `flex-shrink: 0` + explicit `overflow-y: visible`
on both .enh-source-row and .gsearch-source-row so the row keeps
its natural height even under layout pressure. Logo <img> elements
got explicit 22x22 / 18x18 containers so they render at chip scale
without the inline font-size hack.