Every surface so far had a user. The board doesn't — it has an audience. It hangs on a wall, nobody ever touches it, and it's read from chairs five meters away by people who are bored, anxious, or both. Ask this series' opening question — who uses this, in what physical situation? — and the answer dismantles almost every web-design habit you own. This is the deepest reframe of the redesign, and the part where our own design system learns when to step aside: the board is not a web page. It's signage.

Follow along: git checkout polish-06 in the companion repo — the commit message is the prompt.

The prompt

Verbatim, from the commit "The board: signage, not a web page":

The board hangs on a wall and is read from chairs 5 meters away by
people who are bored, anxious, or both. Design it like signage: its
own permanent dark palette (a TV should not follow an OS theme), every
size in vmin so it scales with the physical screen, the serving name
enormous, up next capped at five with a '+N more'. Add a real clock —
waiting rooms run on it. And remove the little 'live' dot: plumbing
status is for staff; show something only when it's WRONG (a
reconnecting pill).

Model pick: Opus, high effort — the one part of the four-surface tour that earns it. Parts 4 and 5 refined what their surfaces looked like; this part had to rethink what the surface is. "What IS this thing?" questions are exactly where the expensive model pays for itself, and the vmin idea below is what came back.

A TV doesn't have an OS theme

Part 2 made a rule and kept it everywhere: every color is a token, and dark mode is a token redefinition under prefers-color-scheme. The board deliberately breaks that rule — and the CSS explains itself:

/* ---------- the board (signage) ----------
   A TV on a wall is not a web page. Its own fixed dark palette — the room's
   lighting doesn't follow anyone's OS theme — sized to be read from chairs. */
.board {
    width: 100%; min-height: 100dvh;
    display: flex; flex-direction: column; align-items: center;
    background: #0E1B1E; color: #E9F2F1;
    padding: 3vmin 4vmin;
}

Hard-coded hex, no tokens. Why? prefers-color-scheme reports the OS setting of the little PC plugged into the TV's HDMI port — a machine nobody looks at, expressing a preference nobody chose. The board's palette is decided by the room: a dark screen with light text is calm on a wall, doesn't glow like a shop sign at 8 a.m., and gives the called name maximum contrast. That's a physical-world constraint, and physical constraints outrank system preferences. There's a design-system lesson in this that's bigger than the board: a token system earns trust not by applying itself everywhere, but by knowing where its writ ends. Rules that can't bend get quietly abandoned; rules with explicit, documented exceptions get kept.

Think in vmin: design that scales with the screen

The second reframe is the part's centerpiece. A web page sizes text in rem — anchored to a reading distance of half a meter. But the same board markup might run on a 32-inch TV in a small practice or a 65-inch panel in a big one, and it's read from across a room. So every size on the board is in vmin — a percentage of the screen's smaller dimension. The design stops being "16px body text" and becomes "the serving name takes 13% of the screen" — a proportion, not a pixel count. Buy a bigger TV and the design scales itself; the layout is tied to the physical object it hangs on:

.board-name {
    font-size: 13vmin; font-weight: 700; line-height: 1.05;
    color: #63C7CC; margin: 0;
}
.board-list { font-size: 5vmin; font-weight: 700; line-height: 1.6; }
.board-label { font-size: 2.2vmin; text-transform: uppercase; letter-spacing: 0.14em; }
.board-clock { font-family: var(--mono); font-size: 2.6vmin; font-variant-numeric: tabular-nums; }

On a 55-inch TV, 13vmin makes the called name roughly nine centimeters tall — readable from the far chairs, which is the only spec that matters. The hierarchy is exactly three steps: one enormous name, five medium names, whisper-quiet labels. Nothing else earns space on the wall.

The waiting-room board before the redesign: an ordinary light-themed web page with the app's sidebar navigation and login links, small Now Serving text, and a green live status dotBefore
The redesigned board: a permanent dark teal palette with the ClinicLive brand and a live clock at the top, NOW SERVING as a quiet label above an enormous cyan patient name, and a numbered up-next list in large typeAfter
The before/after of the whole series. Left: a web page that happens to be on a TV — navigation, login links, browser-sized text. Right: signage.

Five names, then "+N more"

A queue of fourteen rendered in 2vmin type helps nobody — it just shrinks everyone's name to fit a list no one can read. The board caps up-next at five, because five is who needs to start listening; everyone deeper in the queue needs a number, not a nameplate:

<ol class="board-list">
    @foreach (var item in _snapshot.Waiting.Take(5))
    {
        <li @key="item.AppointmentId">@item.DisplayName</li>
    }
</ol>
@if (_snapshot.Waiting.Count > 5)
{
    <p class="board-empty">+ @(_snapshot.Waiting.Count - 5) more</p>
}

(Those @key attributes on the name and the list items are quiet scaffolding: when Part 9 adds motion, Blazor will re-create keyed elements as the queue changes, and CSS entry animations will hook exactly here.) The names themselves are still first-name-plus-initial only — the privacy masking from the production series that keeps a public wall from becoming a patient roster.

A real clock

Waiting rooms run on the clock: I arrived at 9:40, it's 9:58 now, my slot was 9:45. Every person in those chairs is doing that arithmetic, so the board supplies the input — a live clock, top right, in tabular mono so it doesn't wobble as it ticks:

// a wall clock that actually ticks
_clock = new System.Timers.Timer(TimeSpan.FromSeconds(20));
_clock.Elapsed += (_, _) => _ = InvokeAsync(StateHasChanged);
_clock.Start();

A 20-second timer, not a one-second one — a wall clock needs to be right to the minute, and re-rendering a TV screen sixty times a minute to animate seconds nobody displays would be motion for motion's sake.

Status only when something is wrong

The production-series board had a little "● live" dot — and in Part 7 of that series it earned its keep, because we were building the real-time plumbing and needed to watch it work. But on signage it's backwards: a permanent green dot is the developer reassuring themselves, in public, forever. Patients don't need to know the board is connected; they need to know when it isn't. So the dot is gone, and status appears only in failure:

@if (!_connected)
{
    <div class="board-status">reconnecting…</div>
}

A small amber pill, bottom corner, that exists only while the truth requires it. Signage shows state, not plumbing. And reconnection got one more piece of honesty:

_hub.Reconnected += async _ =>
{
    await _hub.InvokeAsync(nameof(ClinicLive.Hubs.QueueHub.JoinBoard));
    _snapshot = await Queue.GetSnapshotAsync();
    _connected = true;
    await InvokeAsync(StateHasChanged);
};

What the AI caught, this time: that snapshot re-query on Reconnected wasn't in the prompt — the AI added it on review, with the reasoning recorded in the commit: a board that was offline for a minute must catch up on the calls it missed, not wait politely for the next broadcast. The production series taught re-joining the group after reconnect (membership dies with the connection ID); the polish series adds re-fetching the state. A wall display's contract isn't "receives events" — it's "is currently true."

The meter: the Opus part of the tour, and priced like it — about fifty cents for the reframe, the vmin system and the review conversation, bringing the Polish running total to ≈ $2.50. The most-seen screen in the whole clinic, redesigned for the price of the waiting room's parking meter.

Checkpoint: open /board full-screen on your biggest monitor and take five steps back. The serving name reads easily; the up-next list shows at most five plus a "+N more"; the clock is right. Check someone in at the kiosk — the name appears at 13vmin. Kill the server: the amber "reconnecting…" pill appears. Restart it: the pill vanishes and the board shows the current queue — including anything that changed while it was offline.

Signage optimizes for distance, calm, and one glance. Now walk the ten steps from the wall to the reception desk and watch every one of those rules flip: the person at that screen reads it all day, is paid to act on it, and wants more information per glance, not less. The final discipline of the four is the pro tool: Part 7: density with dignity.