Redesign Media Centre as a teletext broadcast information service
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
This commit is contained in:
parent
9a277b9031
commit
4b19cbdfb2
25 changed files with 3002 additions and 2343 deletions
|
|
@ -1,75 +1,151 @@
|
|||
/* ═══════════════════════════════════════════════════════
|
||||
Media Centre — shared design tokens + base reset.
|
||||
MEDIA CENTRE — "Page 100"
|
||||
|
||||
Single source of truth for the palette. Loaded by
|
||||
dashboard.html, login.html and settings.html; page-specific
|
||||
rules live in dashboard.css / login.css / settings.css.
|
||||
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.
|
||||
|
||||
To reshade the whole app, change the four hues below —
|
||||
every dim/border variant is derived from them via color-mix.
|
||||
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 {
|
||||
/* ── Surfaces ── */
|
||||
--bg: #141416;
|
||||
--surface: #1a1a1d;
|
||||
--surface-2: #202024;
|
||||
--border: #2c2c31;
|
||||
--border-lt: #38383f;
|
||||
/* ── 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;
|
||||
|
||||
/* ── Text (all ≥ 4.5:1 on every surface above) ── */
|
||||
--text: #edecf1;
|
||||
--text-2: #a8a7b0;
|
||||
--text-3: #7c7b84;
|
||||
/* ── 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 */
|
||||
|
||||
/* ── Accent + semantics (the four source hues) ── */
|
||||
--accent: #7c86ff;
|
||||
--ok: #68b98a;
|
||||
--warn: #d0a75a;
|
||||
--danger: #dc5b52;
|
||||
/* ── 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));
|
||||
|
||||
/* ── Derived tints — never hardcode these as literals ── */
|
||||
--accent-dim: color-mix(in srgb, var(--accent) 14%, transparent);
|
||||
--ok-dim: color-mix(in srgb, var(--ok) 14%, transparent);
|
||||
--warn-dim: color-mix(in srgb, var(--warn) 14%, transparent);
|
||||
--danger-dim: color-mix(in srgb, var(--danger) 14%, transparent);
|
||||
--danger-border: color-mix(in srgb, var(--danger) 35%, transparent);
|
||||
/* ── 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;
|
||||
|
||||
/* ── Type scale (6 steps, no one-offs) ── */
|
||||
--fs-xs: 0.75rem; /* 12px — smallest permitted */
|
||||
--fs-sm: 0.8125rem; /* 13px */
|
||||
--fs-base: 0.9375rem; /* 15px */
|
||||
--fs-lg: 1.125rem; /* 18px */
|
||||
--fs-xl: 1.5rem; /* 24px */
|
||||
--fs-2xl: 2rem; /* 32px */
|
||||
--font: 'Chivo Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
--font-dh: 'DotGothic16', 'Chivo Mono', ui-monospace, Menlo, monospace;
|
||||
|
||||
/* ── Spacing / shape ── */
|
||||
--gap: 1rem;
|
||||
--gap-lg: 1.5rem;
|
||||
--radius: 10px;
|
||||
--radius-sm: 7px;
|
||||
--tap: 44px; /* minimum touch target */
|
||||
--row-h: 4.25rem; /* paired Requests / Indexers row height */
|
||||
/* ── 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;
|
||||
|
||||
--font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
|
||||
--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
/* ── 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(--bg);
|
||||
color: var(--text);
|
||||
background: var(--tt-black);
|
||||
color: var(--ink);
|
||||
font-family: var(--font);
|
||||
font-size: var(--fs-base);
|
||||
line-height: 1.5;
|
||||
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;
|
||||
}
|
||||
|
||||
a { color: var(--accent); }
|
||||
/* 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: 2px solid var(--accent);
|
||||
outline-offset: 2px;
|
||||
border-radius: 4px;
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue