diff --git a/backend/static/filter.js b/backend/static/filter.js index 2902d02..0bf9d8a 100644 --- a/backend/static/filter.js +++ b/backend/static/filter.js @@ -20,8 +20,11 @@ })(); function setActiveTab(el) { - el.parentElement.querySelectorAll("[role=tab]").forEach(function (t) { - t.classList.toggle("active", t === el); + el.parentElement.querySelectorAll("a").forEach(function (t) { + var on = t === el; + t.classList.toggle("active", on); + if (on) t.setAttribute("aria-current", "page"); + else t.removeAttribute("aria-current"); }); } diff --git a/backend/static/style.css b/backend/static/style.css index d5477fa..9d2ebaa 100644 --- a/backend/static/style.css +++ b/backend/static/style.css @@ -64,7 +64,9 @@ --paper-hot: #f0d3cb; /* title of a series with a new chapter */ --paper-dim: #ddd5cb; /* resting title */ --mute: #8d857c; /* secondary text, idle icons */ - --mute-2: #5a5450; /* labels, hints */ + /* Every mute-2 use is 10px mono, so it has to clear 4.5:1 on --ink even + though it reads as the quietest step. */ + --mute-2: #877f76; /* labels, hints */ --faint: #3a3733; /* meta separators */ --faint-2: #57504b; /* cover monogram */ @@ -73,7 +75,11 @@ --ember-ink: #150907; /* text on solid ember */ --ember-soft: #eda798; /* text on ember wash */ --brass: #b8912f; /* favourite — a second, cooler metal */ - --trash: #6b5450; /* remove, resting */ + --trash: #977671; /* remove, resting — icons need 3:1, not 4.5:1 */ + + /* Desktop cell borders for the two coloured action states. */ + --play-hot-line: #3a1d18; + --fav-line: #332b14; --asura: #7d93a5; --demonic: #a98a78; @@ -106,7 +112,7 @@ --paper-hot: #a33018; --paper-dim: #191715; --mute: #6b645d; - --mute-2: #857d75; + --mute-2: #6c655e; /* clears 4.5:1 on --ash too, not just --ink */ --faint: #c9c2ba; --faint-2: #a8a098; @@ -115,7 +121,10 @@ --ember-ink: #fff; --ember-soft: #8d2c17; --brass: #8a681c; - --trash: #a98276; + --trash: #8c6558; + + --play-hot-line: #f0cfc6; + --fav-line: #e3d3a4; --asura: #4f6b80; --demonic: #8a6a55; @@ -180,6 +189,7 @@ button { cursor: pointer; } .topbar form { margin: 0; } .ghost { + position: relative; padding: 0; border: none; border-bottom: 1px solid var(--field-line); @@ -190,6 +200,8 @@ button { cursor: pointer; } text-transform: uppercase; } .ghost:hover { color: var(--paper); border-bottom-color: var(--paper); } +/* The label is 15px tall by design; the thumb gets 44 without moving it. */ +.ghost::after { content: ""; position: absolute; inset: -15px -12px; } .chrome { display: flex; flex-direction: column; } @@ -202,6 +214,9 @@ button { cursor: pointer; } border-bottom: 1px solid var(--rule); color: var(--mute-2); } +/* The input drops its own outline, so the bar it sits in carries the focus + ring — same move the two other inputs make with their border. */ +.searchbar:focus-within { border-bottom-color: var(--paper); color: var(--paper); } .searchbar svg { width: 15px; height: 15px; flex: none; } .search { flex: 1; @@ -226,7 +241,7 @@ button { cursor: pointer; } border-bottom: 1px solid var(--rule); } .tabs::-webkit-scrollbar { display: none; } -.tabs [role="tab"] { +.tabs a { flex: none; display: flex; align-items: center; @@ -236,8 +251,8 @@ button { cursor: pointer; } font: 400 17px var(--font-display); white-space: nowrap; } -.tabs [role="tab"]:hover { color: var(--paper-dim); } -.tabs [role="tab"].active { +.tabs a:hover { color: var(--paper-dim); } +.tabs a.active { color: var(--paper); border-bottom: 2px solid var(--paper); margin-bottom: -1px; @@ -661,7 +676,7 @@ button { cursor: pointer; } border-bottom: 1px solid var(--rule); } .tabs { order: 1; flex: none; gap: 20px; padding: 0; border-bottom: none; } - .tabs [role="tab"] { padding: 10px 0 14px; font-size: 18px; } + .tabs a { padding: 10px 0 14px; font-size: 18px; } .searchbar { order: 2; flex: 1; margin: 0; border-bottom: none; } .recent h2, .recent-strip { padding-left: 32px; padding-right: 32px; } .recent-card, .recent-cover { width: 100px; } @@ -683,8 +698,8 @@ button { cursor: pointer; } than by the hairline the phone layout uses. */ .actions > .play + *, .actions > *:not(.lifecycle) + .lifecycle { margin-left: 10px; box-shadow: none; } - .is-new .actions .play { border-color: #3a1d18; } - .actions .on { border-color: #332b14; } + .is-new .actions .play { border-color: var(--play-hot-line); } + .actions .on { border-color: var(--fav-line); } /* Panels line up with the body text, i.e. past the cover and its gap. */ .chapter-form, .confirm-row, .error-inline { @@ -693,5 +708,8 @@ button { cursor: pointer; } } @media (prefers-reduced-motion: reduce) { - * { animation: none !important; transition: none !important; } + /* Pseudo-elements need naming explicitly — `*` does not match them, and the + busy bar and error dot are both ::before. Their static form still reads: + the bar stays drawn and .actions stays dimmed. */ + *, *::before, *::after { animation: none !important; transition: none !important; } } diff --git a/backend/templates/app.html b/backend/templates/app.html index a5df111..e4e9b80 100644 --- a/backend/templates/app.html +++ b/backend/templates/app.html @@ -8,7 +8,9 @@