Give Activity a genuine ninth colour: --tt-orange
All checks were successful
Deploy / deploy (push) Successful in 24s

Requested directly: "can we make activity orange". The locked eight
palette had already run out at six legible text colours (Watch's blue
was the last one, and it's already a contrast exception); a dithered
swatch alone read as unfinished, and dithering the word itself
rendered as illegible static — tried and reverted this session.

--tt-orange (#ff8000) is defined in base.css right after the locked
eight, clearly marked as a deliberate, acknowledged one-off exception
to "eight colours, no ninth" rather than a secretly-smuggled-in tint.
Same flat text+swatch treatment as every other fastext key. Updated
CLAUDE.md's discipline 1 and DESIGN.md's Locked Eight Rule to name the
exception explicitly, so it reads as a documented decision next time
someone audits the palette, not a bug.
This commit is contained in:
Barely Removable 2026-08-30 09:52:19 -07:00
parent 9fba4f210e
commit 517559a460
5 changed files with 55 additions and 39 deletions

View file

@ -66,7 +66,12 @@ the user's Unraid home server. Server-side project directory is still named
than a variation:
1. **No in-between tone.** There are eight colours (the teletext
primaries). A mid-grey is an ordered dither of two of them, never a
ninth colour.
ninth colour — except `--tt-orange`, the one deliberate, acknowledged
break in `base.css`, added when the fastext nav ran out of legible
colours for its eighth destination (Activity) and dithering the
word itself proved illegible. Treat a *second* ninth colour showing
up as the regression this discipline warns about; this one is a
one-time, explained exception, not a precedent.
2. **No enclosure.** Nothing is surrounded by a border or a box. There is
zero `border-radius` in the codebase. Grouping is a coloured field row
(`.tt-field`), indentation, and weight. This is the single thing the
@ -106,23 +111,27 @@ the user's Unraid home server. Server-side project directory is still named
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. Every
destination gets its own distinct mark. Six get a flat colour, text
and swatch both: Index/Library/Discover/System keep their `r`/`g`/
`y`/`c` shortcut; Requests gets magenta/`--pending` with no
shortcut (a deliberate fit — Requests already is "waiting on a
human" everywhere else magenta appears); Watch gets blue (`.k-blue`)
with no shortcut. Blue is a known exception to the app's own 4.5:1
destination gets its own distinct flat colour, text and swatch
both: Index/Library/Discover/System keep their `r`/`g`/`y`/`c`
shortcut; Requests gets magenta/`--pending` with no shortcut (a
deliberate fit — Requests already is "waiting on a human"
everywhere else magenta appears); Watch gets blue (`.k-blue`) with
no shortcut. Blue is a known exception to the app's own 4.5:1
text-contrast bar (it clears ~2.4:1 on black) — kept anyway, at the
visitor's request, over the alternative of a swatch-only accent
that read as unfinished next to six fully-coloured neighbours.
Activity gets an ordered-dither swatch (`.k-dither`, same mechanism
as `--dither-mid`) instead of a flat colour — the one other legal
way to get a distinct mark without a ninth hue. 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.
that read as unfinished next to its fully-coloured neighbours.
Activity gets `--tt-orange` (`.k-orange`) — a genuine ninth colour,
the one destination that breaks "eight colours, no ninth"
outright, defined and explained in `base.css` right after the
locked eight. It's there because the palette ran out at six
(dithering a swatch alone read as unfinished, and dithering the
word itself renders illegible) and the visitor wanted every
destination to look different, not merely as different as eight
colours allow. Settings alone keeps plain ink — 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

View file

@ -181,7 +181,7 @@ Teletext had exactly eight colours, at full saturation, and the product's semant
### Named Rules
**The Locked Eight Rule.** Eight colours exist. Adding a ninth hue, or desaturating one of the eight to make it sit more politely, is a regression rather than a variation. If a new state needs a colour, it takes one of the eight and inherits that colour's meaning.
**The Locked Eight Rule.** Eight colours exist. Adding a ninth hue, or desaturating one of the eight to make it sit more politely, is a regression rather than a variation. If a new state needs a colour, it takes one of the eight and inherits that colour's meaning. **One acknowledged exception:** `--tt-orange` in `base.css`, added for the fastext nav's eighth destination once the locked eight ran out of colours legible as text on black — a one-time, explained break, not a precedent for a second.
**The Dither Rule.** A mid-tone is an ordered dither of two of the eight at cell scale — a checkerboard or a repeating gradient stepped at `--dither-size: 2px` or at `--bar-cell-w` — exactly how a 16-colour screen faked a gradient. It is never a ninth colour smuggled into the palette. The two derived greys are the sanctioned exception, and they derive from white by `color-mix`, not by hand.

32
app.py
View file

@ -1304,20 +1304,22 @@ def service_urls():
# Every destination, for the top of every page but the index, each
# with its own distinct treatment. Order matches nav_items. Six of the
# eight get a flat colour, text and swatch both: the four with a real
# keyboard shortcut (r/g/y/c), plus magenta for Requests (the same
# --pending magenta a request already shows once approved elsewhere —
# Requests IS "waiting on a human") and blue for Watch. Blue is ~2.4:1
# contrast on black, well under the 4.5:1 every other body text here
# clears — a known, deliberate exception, not an oversight; it's set
# this way because coloured-icon-only for Watch read as unfinished
# next to six fully-coloured neighbours. Activity gets an ordered
# dither swatch instead of a flat colour, the one other legal way to
# get a distinct mark out of this palette without smuggling in a ninth
# hue. Settings alone keeps plain ink — deliberately, as the one page
# with no live status of its own, so it's the one that gets no colour
# rather than an arbitrary leftover.
# with its own distinct colour. Order matches nav_items. The four
# with a real keyboard shortcut (r/g/y/c) keep their original colours;
# Requests gets magenta (the same --pending magenta a request already
# shows once approved elsewhere — Requests IS "waiting on a human");
# Watch gets blue, ~2.4:1 contrast on black versus the 4.5:1 every
# other body text here clears — a known, deliberate exception, kept
# anyway because a swatch-only accent read as unfinished next to six
# fully-coloured neighbours. That's every colour the locked eight
# palette has to give (black's invisible on black); Activity's colour,
# --tt-orange, is a genuine ninth on top of it — a dithered swatch
# alone read as unfinished, and dithering the word itself renders
# illegible, so it's a deliberate, acknowledged break from "eight
# colours, no ninth" rather than a fix that stays inside it. Settings
# alone keeps plain ink — deliberately, as the one page with no live
# status of its own, so it's the one that gets no colour rather than
# an arbitrary leftover.
FULL_FASTEXT = [
("k-red", "r", "100", "Index", "/"),
("k-blue", "", "101", "Watch", "/watch"),
@ -1325,7 +1327,7 @@ FULL_FASTEXT = [
("k-yellow", "y", "103", "Discover", "/discover"),
("k-magenta", "", "104", "Requests", "/requests"),
("k-cyan", "c", "105", "System", "/system"),
("k-dither", "", "106", "Activity", "/activity"),
("k-orange", "", "106", "Activity", "/activity"),
("", "", "900", "Settings", "/settings"),
]

View file

@ -61,6 +61,14 @@
--tt-cyan: #00ffff;
--tt-white: #ffffff;
/* A deliberate, acknowledged ninth: the fastext nav has eight
destinations and only five of the locked eight read as legible
text on black once red/green/yellow/cyan/magenta/blue are already
spoken for (Activity ran out — a dithered swatch alone read as
unfinished, and dithering the word itself was tried and found
illegible). Not "one of the eight" — used nowhere else. */
--tt-orange: #ff8000;
/* ── Roles ─────────────────────────────────────────────
Each colour means one thing across all nine pages. */
--ink: var(--tt-white); /* body text */

View file

@ -533,9 +533,7 @@ a.tt-row:focus-visible .tt-row-sub { color: var(--tt-black); }
text-overflow: ellipsis;
}
/* 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. */
coloured button on the remote. */
.fastext a > span, .fastext-here > span {
min-width: 0;
overflow: hidden;
@ -564,10 +562,9 @@ a.tt-row:focus-visible .tt-row-sub { color: var(--tt-black); }
other body text in this app clears — but the word carries the
colour like every other key here, at the visitor's request. */
.fastext .k-blue { color: 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); }
/* --tt-orange is a genuine ninth colour, not one of the locked eight —
see its definition in base.css for why the palette ran out here. */
.fastext .k-orange { color: var(--tt-orange); }
.fastext a:hover, .fastext a:focus-visible {
background: currentColor;
outline: none;