Give destruction its own colour, take ember back

The stylesheet asserted twice that --ember only ever means "new chapter" while
spending it on eight things, including "Nothing new." — the heat signal firing
on its own negation.

Add a --danger token (a duller oxblood, tuned per theme) and move remove hover,
the open remove cell, the confirm wash and the login error onto it. Text-input
focus follows the .searchbar idiom and turns --paper, so a valid number field
no longer paints itself red. Drop .empty.hot. Ember now survives on the is-new
group, the Updated tab and the brand, which the law comment now says out loud.

Contrast, both themes: --danger on --ink 4.82 dark / 6.65 light, --danger-ink
on the solid button 4.94 / 7.30, --danger-soft on the wash 9.00 / 7.98.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 19:05:35 +07:00
parent c36b7326af
commit bef1469413
2 changed files with 29 additions and 15 deletions
+28 -14
View File
@@ -74,6 +74,12 @@
--ember-wash: #1a1211; /* ember-tinted surface */
--ember-ink: #150907; /* text on solid ember */
--ember-soft: #eda798; /* text on ember wash */
/* Destruction is hot but not ember: a duller oxblood, so a remove confirm is
never mistaken across the room for an unread chapter. */
--danger: #cf5c4d;
--danger-wash: #211311;
--danger-ink: #150808;
--danger-soft: #e2aaa1;
--brass: #b8912f; /* favourite — a second, cooler metal */
--trash: #977671; /* remove, resting — icons need 3:1, not 4.5:1 */
@@ -120,6 +126,10 @@
--ember-wash: #fbeee9;
--ember-ink: #fff;
--ember-soft: #8d2c17;
--danger: #97362a;
--danger-wash: #fbe9e5;
--danger-ink: #fff;
--danger-soft: #7c2c22;
--brass: #8a681c;
--trash: #8c6558;
@@ -155,8 +165,11 @@ button { cursor: pointer; }
@keyframes barSlide { from { transform: translateX(-100%) } to { transform: translateX(320%) } }
@keyframes sheetIn { from { opacity: 0; transform: translateY(-4px) } to { opacity: 1; transform: none } }
/* Transient system states pulse in grey: ember stays reserved for "new
chapter" so a tired glance never misreads a busy bar as unread heat. */
/* The law: ember means "new chapter", and nothing else on a list screen —
busy, error and destruction all stay off it, so a tired glance never
misreads a system state as unread heat. The one exception is the brand
itself (the wordmark, and the login screen, which shows no series at all).
Destruction has its own token, --danger. */
@keyframes mutePulse { 0%, 100% { opacity: .35 } 50% { opacity: 1 } }
/* One measured column, edges drawn rather than boxed. */
@@ -447,12 +460,12 @@ button { cursor: pointer; }
.actions .on { color: var(--brass); }
.actions .restore { color: var(--paper); }
.actions .remove { color: var(--trash); }
.actions .remove:hover { color: var(--ember); }
.actions .remove:hover { color: var(--danger); }
.actions .open { background: var(--hover); color: var(--paper); }
/* Lifecycle cells already sit on --ash, which is what --hover resolves to, so
an open one needs the next step up to stay legible as the panel's owner. */
.actions .lifecycle.open { background: var(--rule); }
.actions .remove.open { background: var(--ember-wash); color: var(--ember); }
.actions .remove.open { background: var(--danger-wash); color: var(--danger); }
.is-dim .actions > * { color: var(--mute-2); }
/* Three clusters by consequence: navigate (play) | organize (favourite,
@@ -493,7 +506,9 @@ button { cursor: pointer; }
font: 500 17px var(--font-mono);
outline: none;
}
.chapter-form input:focus { border-color: var(--ember); }
/* Focus follows the .searchbar idiom — paper, not heat: a red border on a
valid number field reads as "invalid". */
.chapter-form input:focus { border-color: var(--paper); }
.chapter-form input::-webkit-outer-spin-button,
.chapter-form input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.chapter-form button {
@@ -511,9 +526,9 @@ button { cursor: pointer; }
justify-content: space-between;
gap: 12px;
padding: 14px;
background: var(--ember-wash);
background: var(--danger-wash);
}
.confirm-row span { font: 400 17px var(--font-display); color: var(--ember-soft); }
.confirm-row span { font: 400 17px var(--font-display); color: var(--danger-soft); }
.confirm-row div { display: flex; gap: 8px; }
.confirm-row button {
height: 40px;
@@ -526,12 +541,12 @@ button { cursor: pointer; }
.confirm-row button:hover { color: var(--paper); }
.confirm-row .danger-solid {
border: none;
background: var(--ember);
color: var(--ember-ink);
background: var(--danger);
color: var(--danger-ink);
font-weight: 600;
}
/* Archive and finish are reversible, so their confirm asks in grey — only the
irreversible remove gets the ember wash. */
irreversible remove gets the danger wash. */
.confirm-row.calm { background: var(--ash); }
.confirm-row.calm span { color: var(--paper-dim); }
.confirm-row .go {
@@ -568,7 +583,7 @@ button { cursor: pointer; }
}
/* Busy: a grey hairline slides across the top of the sheet — deliberately not
ember, which only ever means "new chapter". */
ember, which on a list screen only ever means "new chapter". */
.card.htmx-request { overflow: hidden; }
.card.htmx-request .actions { pointer-events: none; opacity: .5; }
.card.htmx-request::before {
@@ -590,7 +605,6 @@ button { cursor: pointer; }
padding: 40px 20px 48px;
}
.empty strong { font: 400 20px var(--font-display); color: var(--paper); }
.empty.hot strong { color: var(--ember); }
.empty .clear-search {
align-self: flex-start;
margin-top: 4px;
@@ -653,12 +667,12 @@ button { cursor: pointer; }
letter-spacing: .16em;
outline: none;
}
.login-card input:focus { border-bottom-color: var(--ember); }
.login-card input:focus { border-bottom-color: var(--paper); }
.login-card .error {
margin: 0;
min-height: 20px;
font: 400 13px/1.4 var(--font-body);
color: var(--ember);
color: var(--danger);
}
.login-card button {
height: 54px;
+1 -1
View File
@@ -11,7 +11,7 @@
{{else if eq .Tab "fav"}}
<div class="empty"><strong>No favourites yet.</strong><p>Star a series to pin it here.</p></div>
{{else if eq .Tab "new"}}
<div class="empty hot"><strong>Nothing new.</strong><p>Every series is caught up to its latest chapter.</p></div>
<div class="empty"><strong>Nothing new.</strong><p>Every series is caught up to its latest chapter.</p></div>
{{else if eq .Tab "archived"}}
<div class="empty"><strong>Nothing archived.</strong><p>Shelve a series to park it here — it keeps getting checked for new chapters.</p></div>
{{else if eq .Tab "finished"}}