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
151 lines
6.9 KiB
CSS
151 lines
6.9 KiB
CSS
/* ═══════════════════════════════════════════════════════
|
|
MEDIA CENTRE — "Page 100"
|
|
|
|
A broadcast information service, not a dashboard. The world
|
|
is teletext (Ceefax, and the cable guide channel that did the
|
|
same job in America): a locked eight-colour palette on pure
|
|
black, one blocky monospace at exactly two heights, a strict
|
|
character-cell grid, and grouping carried by colour fields and
|
|
row weight — never by a border, never by a box.
|
|
|
|
Five disciplines this world is held to. Breaking one is a
|
|
regression, not a variation:
|
|
|
|
1. NO IN-BETWEEN TONE. There are eight colours. A mid-grey is
|
|
an ordered dither of two of them (--dither-*), never a
|
|
ninth colour smuggled into the palette.
|
|
2. NO ENCLOSURE. Nothing is ever surrounded by a border or a
|
|
box. Grouping is a coloured field row, indentation, and
|
|
weight. This is the exact reflex the old design was built
|
|
on and the main thing this world refuses.
|
|
3. ONE RULER. Every bar, meter and percentage on every page
|
|
shares one scale (--bar-cells), so 60% on the array and
|
|
60% on an indexer are the same width and compare directly.
|
|
4. EVERY READING CARRIES ITS DIRECTION. A value shows where
|
|
it is heading, so a disk becoming a problem is visible
|
|
before it is one.
|
|
5. PAGES DIFFER IN STOCK. A page holding critical state is
|
|
set heavier than a quiet one. Uniform texture across seven
|
|
pages is a failure.
|
|
═══════════════════════════════════════════════════════ */
|
|
|
|
:root {
|
|
/* ── The locked eight ──────────────────────────────────
|
|
Teletext had exactly these, at full saturation, and the
|
|
product's semantics were already the same semantics:
|
|
green runs, yellow works, red is off air. Do not soften
|
|
them; the emissive-on-black scene is what they are for. */
|
|
--tt-black: #000000;
|
|
--tt-red: #ff0000;
|
|
--tt-green: #00ff00;
|
|
--tt-yellow: #ffff00;
|
|
--tt-blue: #0000ff;
|
|
--tt-magenta: #ff00ff;
|
|
--tt-cyan: #00ffff;
|
|
--tt-white: #ffffff;
|
|
|
|
/* ── Roles ─────────────────────────────────────────────
|
|
Each colour means one thing across all nine pages. */
|
|
--ink: var(--tt-white); /* body text */
|
|
--voice: var(--tt-yellow); /* the service speaking: mastheads, page numbers */
|
|
--live: var(--tt-cyan); /* live values, now showing */
|
|
--ok: var(--tt-green); /* running, healthy, available */
|
|
--alert: var(--tt-red); /* off air, failed, danger */
|
|
--pending: var(--tt-magenta); /* requested, waiting on a human */
|
|
--field: var(--tt-blue); /* the only "background" colour — header fields */
|
|
|
|
/* ── Dither ────────────────────────────────────────────
|
|
The only legal way to make a tone that isn't one of the
|
|
eight. A checkerboard of the colour against black at cell
|
|
scale, exactly how a 16-colour screen faked a gradient.
|
|
Used for inactive bar cells and secondary text grounds. */
|
|
--dither-size: 2px;
|
|
/* --ink-dim is the ONLY dimmed value allowed to carry text: at 58% it
|
|
clears 4.5:1 on black. --ink-dimmer is for graphics only — bar
|
|
troughs, the dither field, the separator — because at 30% it does
|
|
not, and secondary text set in it was failing contrast outright. */
|
|
--ink-dim: color-mix(in srgb, var(--tt-white) 58%, var(--tt-black));
|
|
--ink-dimmer: color-mix(in srgb, var(--tt-white) 30%, var(--tt-black));
|
|
|
|
/* ── Type: one face, exactly two heights ───────────────
|
|
Teletext's entire scale. Emphasis comes from colour and
|
|
from doubling the height, never from a weight ramp and
|
|
never from a third size. */
|
|
--fs: 0.9375rem; /* 15px — the single body size */
|
|
--fs2: 1.875rem; /* 30px — double height, the only other size */
|
|
--lh: 1.45;
|
|
--row: calc(var(--fs) * var(--lh)); /* one character row */
|
|
--cell: 1ch;
|
|
|
|
--font: 'Chivo Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
--font-dh: 'DotGothic16', 'Chivo Mono', ui-monospace, Menlo, monospace;
|
|
|
|
/* ── Measure ───────────────────────────────────────────
|
|
A teletext page was 40 columns. A screen this wide gets
|
|
double that, so density survives without the grid dying. */
|
|
--page-cols: 92ch;
|
|
--gutter: 1.5rem;
|
|
|
|
/* ── The one ruler (discipline 3) ──────────────────────
|
|
Every bar on every page is this many cells wide, so any
|
|
two percentages anywhere in the service are comparable. */
|
|
--bar-cells: 20;
|
|
--bar-cell-w: 0.62em;
|
|
|
|
--tap: 44px;
|
|
}
|
|
|
|
*, *::before, *::after { box-sizing: border-box; }
|
|
|
|
html { background: var(--tt-black); }
|
|
|
|
body {
|
|
margin: 0;
|
|
background: var(--tt-black);
|
|
color: var(--ink);
|
|
font-family: var(--font);
|
|
font-size: var(--fs);
|
|
line-height: var(--lh);
|
|
font-variant-numeric: tabular-nums;
|
|
/* Teletext never anti-aliased into a soft grey edge. Keep the
|
|
letterforms crisp rather than letting the browser blend them
|
|
toward tones the palette does not contain. */
|
|
-webkit-font-smoothing: antialiased;
|
|
text-rendering: optimizeSpeed;
|
|
}
|
|
|
|
/* Phosphor bloom. Applied only where the world is speaking loudly —
|
|
double-height rows and status glyphs — because bloom under a dense
|
|
table of figures costs more legibility than it buys character. */
|
|
.bloom {
|
|
text-shadow: 0 0 0.4em color-mix(in srgb, currentColor 55%, transparent);
|
|
}
|
|
|
|
a { color: var(--live); text-decoration: none; }
|
|
a:hover { color: var(--tt-black); background: var(--live); }
|
|
|
|
/* Focus is a reversed cell, the way a teletext menu row selected
|
|
itself. No outline ring — a ring is an enclosure. */
|
|
:focus-visible {
|
|
outline: none;
|
|
background: var(--voice);
|
|
color: var(--tt-black);
|
|
}
|
|
|
|
::selection { background: var(--live); color: var(--tt-black); }
|
|
|
|
/* Browser furniture, themed to the palette rather than left at the
|
|
defaults that belong to no design system. */
|
|
* { scrollbar-color: var(--ink-dimmer) var(--tt-black); scrollbar-width: thin; }
|
|
::-webkit-scrollbar { width: 10px; height: 10px; }
|
|
::-webkit-scrollbar-track { background: var(--tt-black); }
|
|
::-webkit-scrollbar-thumb { background: var(--ink-dimmer); }
|
|
::-webkit-scrollbar-thumb:hover { background: var(--ink-dim); }
|
|
::-webkit-scrollbar-corner { background: var(--tt-black); }
|
|
input { caret-color: var(--voice); }
|
|
|
|
.visually-hidden {
|
|
position: absolute; width: 1px; height: 1px;
|
|
padding: 0; margin: -1px; overflow: hidden;
|
|
clip: rect(0 0 0 0); white-space: nowrap; border: 0;
|
|
}
|