Colours: "if the intent is to have them all different colors than
lets have them all different colors." The locked eight only give five
safe as full text (blue fails contrast, black's invisible on black),
so the other three get their own treatments instead of sharing plain
ink: Watch gets blue as a swatch-only accent (the button cap's colour,
not the label), Activity gets an ordered-dither swatch (the other
legal way to mark something without a ninth colour), and Settings
alone keeps plain ink deliberately, as the one page with no live
status of its own.
Accessibility (items 1 and 3 from the design review, item 2 skipped
per request — the header's download figure stays live and unmuted):
- Added a skip-link, off-screen until focused, jumping past the
8-item top nav straight to each page's #main-content.
- Renamed the nav's aria-label from "Fastext" (meaningless without
the visual teletext context) to "Page navigation".
Plain ink for Watch/Requests/Activity/Settings read as flat and
unfinished, not deliberate — user feedback: "the new colors are
awful and basically the same color." Requests gets magenta
(--pending) back: not an arbitrary reuse, it's the same colour a
request already carries once approved elsewhere in the app, and
Requests genuinely is "waiting on a human." That's the real ceiling
though — the locked eight teletext colours leave exactly five legible
as text on black (blue fails contrast, black is invisible on black),
so Watch/Activity/Settings still share plain ink rather than a sixth
colour that doesn't exist in this palette.
From a frontend-design skill review of all pages, after last session's
chrome changes (top nav, all-tabs nav, header download row):
- The top/closing fastext nav now mutes the entry matching the current
page (.fastext-here) instead of rendering a link to the page you're
already on.
- Colour in fastext is reserved for the four entries that still carry
a real keyboard shortcut (r/g/y/c); the other four render in plain
ink instead of reusing k-red/k-green/k-yellow/k-cyan for a
destination they don't semantically mean (e.g. Requests no longer
shows in the app's own off-air red).
- Discover's badge slot meant "critic score" on its RT tiles and
"release year" on its new search tiles at the same time. Search
results (Library and Discover) now fold year/held-state into the
sub-line instead, leaving the badge exclusively for critic score.
- System's Transmission rows now carry a small ↗ glyph, since they
silently changed from in-app navigation to opening each service's
own UI in a new tab with no visual cue.
- SABnzbd polling drops from 5s to 20s on pages that only show the
header's download figure (everywhere but System/Activity, which
keep 5s for their own live figures) — a number idle 95% of the time
doesn't need second-level freshness sitewide.
- DESIGN.md's fastext description, now-current per this session's nav
changes.
Adds a live download figure next to the header clock, present on
every page (not just Activity/System). It's populated by the same
/api/sabnzbd poll those pages already use, extended to run
unconditionally and to fill in a new #head-dl span — never a
server-rendered fetch, so an unreachable SABnzbd can't add latency to
pages that don't otherwise touch it. Quiet ink at "0 IN QUEUE" when
idle, live cyan with a speed reading once something's moving.
- Fastext colour keys now lead every page but the index, since they're
the only nav those pages carry; the index keeps them as its closing
row since its own body is already the full nav.
- Settings page was missing page="settings" in its render_template
call, so its header silently fell back to "P100 Index".
- Library's search form posted a q param the route never read; it now
filters the cached Sonarr/Radarr lists and shows matching tiles.
- Discover gained a search bar that queries Ombi (already in front of
TMDB/TVDB) and lets you add a result straight to Radarr/Sonarr,
showing "Held" instead of a button for anything already in library.
- Fixed the Add button's success check, which read d.ok against a
response that actually sets d.success — it reported FAILED even
when the add worked.
Applies the fix round from the finish-reviewer's disposition on commit
4b19cbd, in one batch:
- System's disk table is unreadable below 560px: horizontal-scrolling a
6-column table hid the usage bar and the temperature, the two
readings that matter most (discipline 3 — one shared ruler — was
unauditable as a result). Added a disk_row() macro and a phone-only
.tt-disk-rows reflow (name + full 20-cell bar + temp on one line,
device/free/total beneath), CSS-toggled against the existing table
at the same breakpoint.
- Contrast failure on the highest-severity state: white text on the
red .tt-field.crit/.tt-toast.error/.tt-btn.armed reversals measured
4.0:1, under the 4.5:1 floor. Switched to black text (5.25:1),
matching the black-on-yellow .warn pattern already in use — and
fixed a second instance of the same bug: .tt-field.crit had no
.tt-field-meta override, unlike .warn.
- Two type families where the direction contract names one blocky
monospace: unified on a single self-hosted face (Space Mono, one
weight, no bold) for both body and the double-height row.
- FIRST VIEWPORT proportion: an unpromised 6-item Just Added grid was
competing with NOW SHOWING for the fold instead of the contract's
"lower two-thirds in double-height cyan." Cut to a fixed 3-item,
fixed-3-column row, which also fixes the orphaned-tile grid defect
as a side effect (a fixed count can't leave a lone tile beside empty
tracks).
- Three flat mid-grey fills contradicted discipline 1 (no in-between
tone): .tt-tile-art, .tt-btn:disabled, and .tt-err pre all painted a
solid --ink-dimmer background. Centralized the dither .tt-tile-art
already used correctly into a shared --dither-mid generator and
applied it to all three.
- Google Fonts dependency on a LAN-only home server: a dropped webfont
request was a silent identity change, not a graceful fallback.
Self-hosted Space Mono under static/fonts/ via @font-face; dropped
the <link> tags from _shell.html and login.html.
- Deliberately deferred: "pages differ in stock" (discipline 5) still
fires on only one band service-wide. Every other finding was a
bounded fix to existing code; this one asks for a new mechanism (an
aggregate status band on P100) rather than a correction, so it's
flagged for a follow-up rather than rushed into this batch.
Recaptured desktop.png, mobile.png, desktop-system.png and
mobile-system.png (the four files the reviewer's findings cited)
through the same true-390px iframe method as the prior round, and
returned them for the fix round's verdict pass.
Known follow-up: DESIGN.md's typography section (written by the
documenter before this batch) still names the old two-family pairing
and needs a re-run now that the font system changed under it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBw1QodG8ZMYHrGeQfqyDS
Replaces the neutral dark card-based theme with "Page 100": teletext's
locked eight colours at full saturation on pure black, numbered pages
reachable by typing the number (or the r/g/y/c fastext keys), and no
borders, boxes, or radius anywhere — grouping is carried by full-bleed
colour fields and row weight instead.
Chosen via the impeccable skill's replacement-world flow: seven visual
candidates derived from the audience's own world, a mandatory roll
assigned Ceefax/US-cable-guide teletext, six catalog challengers weighed
against it, and the user locked the assigned direction on the decision
page (seed aab4510e).
- New templates for all nine pages (home/watch/library/discover/
requests/system/activity/login/settings) behind a shared _shell.html
carrying the direction contract and _macros.html for the row/bar/tile
vocabulary; deletes the old single-page dashboard.html and its
dedicated stylesheets/script.
- static/css/base.css + teletext.css: the locked palette, a two-height
type scale (Chivo Mono / DotGothic16), and the five disciplines the
system is held to (no in-between tone, no enclosure, one shared bar
ruler, trend only where real history exists, pages weighted by state).
- static/js/service.js: header clock, page-number jump, fastext keys,
two-tap arm/confirm add, guarded live polling — replaces dashboard.js.
- app.py: nav_items now carry page numbers; fastext defaults added to
the page-chrome context processor; version bumped to 2.0.0.
- DESIGN.md + .impeccable/design.json regenerated from the built world
by the documenter pass; PRODUCT.md and CLAUDE.md updated to describe
the new system in place of the retired one.
- Fixed a live bug found along the way: settings.html called
url_for('dashboard'), an endpoint removed earlier in the branch, which
would have 500'd the Settings page.
- Fixed a One-Ruler violation the finish review's recapture request
surfaced: --bar-cells disagreed with the bar() macro's hardcoded cell
count below the 760px breakpoint, so a fill could land mid-cell on a
phone. Removed the mobile override; the ruler is now 20 cells at every
width, matching the macro unconditionally.
Passed two inspection rounds (desktop + true-390px mobile, via an
iframe harness since macOS Chrome clamps --window-size) and a finish
review; QA screenshots and interview logs are gitignored as scratch,
not shipped in the repo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBw1QodG8ZMYHrGeQfqyDS