diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2bdd584..1ea5264 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,10 +37,10 @@ The long form, with what was wrong before and how it was found, is in
Download latest dialogs (save, download, cancel). The icons are Font Awesome Free, embedded as
SVG: only the ones used, no font to download, and nothing fetched from anyone else. They
replace font characters such as ⟳ ⤓ ↗, which came out thin and tiny and differed from font to
- font. Keep is a flag everywhere, as it was in the original.
-- A file's state and type are icons: a check when it is downloaded, a warning when it failed
- (the error is in the tooltip), and nothing while it waits; audio, video, image, PDF, torrent
- and other files each have their own. The DOWNLOADED and PENDING labels are gone.
+ font. Keep is a flag everywhere, as it was in the original, and mark unread is an envelope.
+- A file's type is an icon (audio, video, image, PDF, torrent, other), green once it is
+ downloaded and red when the download failed, with the details in its tooltip. One icon per
+ row keeps the column lined up. The DOWNLOADED and PENDING labels are gone.
### Security
diff --git a/tests/ui/app.spec.js b/tests/ui/app.spec.js
index 03ca1b9..bfd5ef7 100644
--- a/tests/ui/app.spec.js
+++ b/tests/ui/app.spec.js
@@ -87,7 +87,7 @@ test('the three panes are there and the item text lands in the bottom one', asyn
// Only the downloaded one gets a player, and max_new_per_check is 1, so find it by
// its chip rather than assuming which episode the daemon happened to fetch.
- const downloaded = page.locator('.ep', { has: page.locator('[title="Downloaded"]') }).first();
+ const downloaded = page.locator('.ep', { has: page.locator('.kind.here') }).first();
await downloaded.click();
await expect(page.locator('#files audio')).toBeVisible();
await expect(page.locator('#files .encbox [title="Save to this computer"]')).toBeVisible();
@@ -110,9 +110,8 @@ test('a downloaded file that is not audio gets no player', async ({ page }) => {
await expect(page.locator('#detail .dt')).toHaveText('An Article');
await expect(page.locator('#files audio')).toHaveCount(0);
- // What it is and that it is here, as icons with the words in their tooltips.
- await expect(page.locator('#files .encbox [title="image"]')).toBeVisible();
- await expect(page.locator('#files .encbox [title="Downloaded"]')).toBeVisible();
+ // What it is and that it is here: one icon, green, with the words in its tooltip.
+ await expect(page.locator('#files .encbox .kind.here')).toHaveAttribute('title', 'image, downloaded');
// Still offered as a file, just not as an episode: viewable and keepable.
await expect(page.locator('#files [title="Save to this computer"]')).toBeVisible();
const view = page.locator('#files a[title="View in a new tab"]');
@@ -131,7 +130,7 @@ test('an item with several enclosures lists them all', async ({ page }) => {
await row.click();
// The Files pane lists every one: the audio and the image.
await expect(page.locator('#files .encbox')).toHaveCount(2);
- await expect(page.locator('#files .encbox').nth(1).locator('[title="image"]')).toBeVisible();
+ await expect(page.locator('#files .encbox').nth(1).locator('.kind[title^="image"]')).toBeVisible();
});
test('the filter tabs change what is listed', async ({ page }) => {
@@ -674,7 +673,7 @@ test('a deleted file looks as if it was never downloaded', async ({ page }) => {
await page.locator('#files button[data-a="del"]').click();
// No "reaped", no chip at all: just the way to get it again.
- await expect(row.locator('[title="Downloaded"]')).toHaveCount(0);
+ await expect(row.locator('.kind.here')).toHaveCount(0);
await expect(row).not.toContainText(/reaped/i);
await row.click();
await expect(page.locator('#files')).not.toContainText(/reaped/i);
diff --git a/web/index.html b/web/index.html
index 467e734..bb9acea 100644
--- a/web/index.html
+++ b/web/index.html
@@ -238,11 +238,11 @@ a.btn{text-decoration:none;color:inherit}
.btn.ico{padding:4px 9px;min-width:32px;font-size:14px;line-height:1.25;text-align:center}
/* An icon (Font Awesome, embedded as SVG) in the button's own colour. */
.i{display:inline-block;width:16px;height:16px;vertical-align:-3px;flex:none;fill:currentColor}
-/* A file's state and type, as icons in place of the old DOWNLOADED / PENDING / audio chips. */
-.fst,.kind{display:inline-grid;place-items:center}
-.fst{color:var(--good)}
-.fst.bad{color:var(--bad)}
-.kind{color:var(--dim)}
+/* A file's type as an icon, in place of the old DOWNLOADED / PENDING / audio chips: green once
+ it is here, red when the download failed. */
+.kind{display:inline-grid;place-items:center;color:var(--dim)}
+.kind.here{color:var(--good)}
+.kind.bad{color:var(--bad)}
.fhead .art .i{width:22px;height:22px}
.toolbar{
display:flex;gap:10px;align-items:center;margin-bottom:12px;flex-wrap:wrap;
@@ -503,8 +503,10 @@ input[type=range]::-moz-range-thumb{width:12px;height:12px;border:0;border-radiu
:root[data-theme="classic"] .ep.sel .st,
:root[data-theme="classic"] .ep.sel .fl,
:root[data-theme="classic"] .ep.sel .file,
-:root[data-theme="classic"] .ep.sel .fst,
:root[data-theme="classic"] .ep.sel .kind{color:#fff}
+/* Green and red stay green and red on the blue, just lighter so they read. */
+:root[data-theme="classic"] .ep.sel .kind.here{color:#a6f3a6}
+:root[data-theme="classic"] .ep.sel .kind.bad{color:#ffb8ad}
/* Lists were white in the original; the pale blue-grey belongs to the source list alone. */
:root[data-theme="classic"] .childrow{background:#fff}
:root[data-theme="classic"] .dt{background:linear-gradient(#80aae6,#3f78cf);color:#fff;padding:6px 12px;border-radius:4px}
@@ -616,9 +618,7 @@ const ICON={
directory:fa('0 0 448 512','