diff --git a/CLAUDE.md b/CLAUDE.md index 147a29d..7ca377d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -105,18 +105,22 @@ the user's Unraid home server. Server-side project directory is still named under the header on every page but the index — those pages carry no other nav, so it needs no scroll to reach. The index overrides it with `HOME_FASTEXT`, the original four-entry row, as its own closing - line, since its body already lists every destination once. The - original four (Index/Library/Discover/System) keep their `r`/`g`/ - `y`/`c` keyboard shortcut and colour; Requests also gets a colour - (magenta, `--pending`) without a shortcut — a deliberate fit, not - an arbitrary fifth pick, since Requests already is "waiting on a - human" everywhere else magenta appears. That's the ceiling: the - locked eight colours leave exactly five that read as legible text - on black (blue fails contrast there, black is invisible), so Watch/ - Activity/Settings share plain ink rather than a sixth colour that - doesn't exist in this palette. Whichever entry matches the current - page renders as a `.fastext-here` span instead of a link — a page - linking to itself did nothing, so it isn't offered as a click. + line, since its body already lists every destination once. Every + destination gets its own distinct mark — the locked eight colours + only give five that read as legible text on black, so getting to + eight took three treatments: five flat colours as text+swatch + (Index/Library/Discover/System keep their `r`/`g`/`y`/`c` shortcut; + Requests gets magenta/`--pending` with no shortcut — a deliberate + fit, since Requests already is "waiting on a human" everywhere else + magenta appears); Watch gets blue as a swatch-only accent (`.k-blue` + — blue fails contrast as body text, so only the small cell carries + it, not the row's own label); Activity gets an ordered-dither swatch + (`.k-dither`, same mechanism as `--dither-mid`) rather than a flat + colour. Settings alone keeps plain ink with no swatch treatment — + deliberately, as the one page with no live status of its own. + Whichever entry matches the current page renders as a + `.fastext-here` span instead of a link — a page linking to itself + did nothing, so it isn't offered as a click. - **Nothing is clipped, hidden, or sticky.** All seven page numbers and every fastext entry stay visible at every width, reflowing to another row rather than scrolling, truncating, or folding into a menu. No diff --git a/app.py b/app.py index 69ef6e2..0a0ada4 100644 --- a/app.py +++ b/app.py @@ -1303,24 +1303,34 @@ def service_urls(): } -# Every destination, for the top of every page but the index. Order -# matches nav_items. The locked eight teletext colours leave exactly -# five that read as text on black without inventing a ninth tone or -# borrowing a colour that already means something else here: the four -# with a real keyboard shortcut (r/g/y/c), plus magenta for Requests — -# not arbitrary, it's the same --pending magenta a request already -# shows once approved elsewhere, and Requests IS "waiting on a human". -# Blue fails contrast as text and black is invisible on black, so the -# three destinations left over (Watch/Activity/Settings) share plain -# ink rather than a sixth colour that doesn't exist in this palette. +# Every destination, for the top of every page but the index, each +# with its own distinct treatment. Order matches nav_items. The +# locked eight teletext colours only give five that read as full- +# saturation text on black (blue fails contrast there), so getting all +# eight distinct without inventing a ninth colour takes three +# treatments, not one: +# - Five flat colours, text and swatch both: the four with a real +# keyboard shortcut (r/g/y/c), plus magenta for Requests — not +# arbitrary, it's the same --pending magenta a request already +# shows once approved elsewhere, and Requests IS "waiting on a +# human". +# - Blue as a swatch-only accent (Watch): legible as a small solid +# cell — "the physical coloured button on the remote" — but not as +# the row's own text colour, where it fails contrast. +# - An ordered dither swatch (Activity): the one other legal way to +# get a distinct mark out of this palette per base.css's own first +# discipline, without smuggling in a ninth hue. +# Settings keeps plain ink deliberately — the one purely administrative +# destination with no live status of its own, so it's the one page +# that gets no colour at all rather than an arbitrary last one. FULL_FASTEXT = [ ("k-red", "r", "100", "Index", "/"), - ("", "", "101", "Watch", "/watch"), + ("k-blue", "", "101", "Watch", "/watch"), ("k-green", "g", "102", "Library", "/library"), ("k-yellow", "y", "103", "Discover", "/discover"), ("k-magenta", "", "104", "Requests", "/requests"), ("k-cyan", "c", "105", "System", "/system"), - ("", "", "106", "Activity", "/activity"), + ("k-dither", "", "106", "Activity", "/activity"), ("", "", "900", "Settings", "/settings"), ] diff --git a/static/css/teletext.css b/static/css/teletext.css index dcf0d0c..4687654 100644 --- a/static/css/teletext.css +++ b/static/css/teletext.css @@ -8,6 +8,26 @@ RULER (every bar is --bar-cells wide, no exceptions). ═══════════════════════════════════════════════════════ */ +/* ── Skip-link ────────────────────────────────────────── + Off-screen until it receives focus, then it's a plain field row + like any other — a solid colour ground, no border — sitting above + everything else so tabbing past it reaches the header next. */ +.skip-link { + position: absolute; + top: -999px; + left: 0; + z-index: 1; + padding: 0.5em 1ch; + background: var(--field); + color: var(--ink); + text-transform: uppercase; + letter-spacing: 0.16em; +} +.skip-link:focus { + top: 0; + outline: none; +} + /* ── Header row ───────────────────────────────────────── Teletext's top line, unchanged for forty years: the page number you are on, who is transmitting, and the clock. It @@ -512,8 +532,10 @@ a.tt-row:focus-visible .tt-row-sub { color: var(--tt-black); } overflow: hidden; text-overflow: ellipsis; } -/* The key's colour is carried by a solid cell at its head — the - physical coloured button on the remote. */ +/* The key's identity is carried by a cell at its head — the physical + coloured button on the remote. Solid for most; k-blue and k-dither + override its background below, since a flat swatch can't carry + every one of the eight destinations without repeating a colour. */ .fastext a > span, .fastext-here > span { min-width: 0; overflow: hidden; @@ -538,6 +560,15 @@ a.tt-row:focus-visible .tt-row-sub { color: var(--tt-black); } .fastext .k-yellow { color: var(--voice); } .fastext .k-cyan { color: var(--live); } .fastext .k-magenta { color: var(--pending); } +/* Blue fails contrast as body text on black, so it marks the swatch + only — the button cap's colour, not the printed label — while the + row's own text stays legible ink. */ +.fastext .k-blue::before { background: var(--field); } +.fastext .k-blue:hover, .fastext .k-blue:focus-visible { background: var(--field); } +/* The one other legal way to get a distinct mark out of eight colours + without a ninth: an ordered dither, same mechanism as --dither-mid, + in place of a flat swatch. */ +.fastext .k-dither::before { background: var(--dither-mid); } .fastext a:hover, .fastext a:focus-visible { background: currentColor; outline: none; diff --git a/templates/_shell.html b/templates/_shell.html index a9aaa3a..50c21c3 100644 --- a/templates/_shell.html +++ b/templates/_shell.html @@ -17,6 +17,12 @@ +{#- Skip-link: every page but the index now opens with a full nav + block before any real content — a keyboard or screen-reader visitor + would otherwise tab through all eight destinations on every single + visit. Off-screen until focused, then it's the first thing tabbing + into the page reaches. -#} +