焕 Kelvin Chen ~/design

design system

One ink. One red.
Four rooms.

This page is the design system behind this site and its sibling apps — the code is the spec. Every token, component and motion pattern lives here, and works in all four rooms: try the room switches in the header. When a new component is needed anywhere, it gets designed on this page first.

restraint does the talking: chrome is monochrome, color lives only in photographs, data, and one hand-drawn red.

the spec opens in motion — when a loop exists, it beats the still

01 · rooms

Only the paper changes.

Every surface keeps the same bones and swaps only its light: paper for the personal site, night for the party screens and dark mode, porcelain for the dog, stone for the dashboards. A component that only uses room variables works in all four automatically — that's the test, and this whole page passes it.

--seal #c3272b

rooms are assignments, not prisons: the party app lets guests flip paper ⇄ night and remembers the choice. the one exception is the party TV — a giant screen in a dark room stays night, because its darkness is stagecraft, not preference.

02 · voices

Three voices, never a fourth.

content · Space Grotesk 700/400

Headlines carry the argument.

metadata · IBM Plex Mono

KICKERS · CAPTIONS · DATA · STATUS — the quiet voice that annotates everything

hanzi display · Songti

English leads. The system's entire public hanzi inventory is seven characters — three names and four card seals: 焕 · 暖暖 · 随想 · 造 · 动 · 暖 · 聚. A fixed set, not a pattern: concept names stay English in public copy, and full bilingual text lives only in /notes prose. Body text stays quiet, medium-weight ink for emphasis, links as thin underlines.

scale is the accent color: a 72px headline against 11px mono does what a bright hue would — without the hue. fonts are self-hosted woff2, zero CDN.

03 · the red

One red, four doors.

Vermilion #c3272b — the red-pen ink teachers grade with — is the only color the interface is allowed. It appears through exactly four doors, always as a hand-drawn stroke, never as a geometric block. Everything else is ink, paper, gray.

door 1

The marks

One gesture only: the brush swash under the name. Signature, not logo.

焕
door 2

Alive signals

Live pulses, form errors, destructive confirms, the newest data point, first place. Things that need attention right now.

running · morning brief
door 3

Selection

Select any text on this page — the red belongs to whatever is being read.

go ahead, drag across this line.

door 4

Her collar

Yumi is the one member of the house the design system doesn't apply to.

the collar

two content exemptions, because color belongs to content: photographs keep theirs (hushed — see 05), and data keeps its semantics (gains in muted sage #4e8a6e, losses in vermilion — numbers only, never chrome).

04 · marks

Signature, not logo.

No invented pictorial logo, ever. The identity is typographic and photographic: the name with a red brush-stroke under it, a red dot, or simply a real photo — the avatar is the icon.

焕
the swash — footer signature,
og corner, headline keywords
the dot means alive — a signal,
never a signature (door 2 owns it)
Yumi, whisper-graded, blooming on hover
the photo — avatars, QR centers.
a face beats any icon
焕← at rest: ~14px, 40% opacity
the quiet rule — marks whisper.
never let one grow back into a logo

retired, on purpose: a square seal stamp (too official) · a neat circle around the name (too formal) · a casual double-loop scribble (tried it, didn't love it) · any cartoon or geometric logo (someone else's pen) · a red dot as the header mark (to the whole internet a red dot says "notification" — and here it already says "live"). The graveyard stays public — rejected ideas are how the system learned what it is.

05 · photography

Color rests at a whisper.

Photos carry all of the site's warmth, so they follow one law: at rest they wear a hushed grade — 60% saturation with a faint warm cast — that pins every picture into the same album. Hover (or scroll past center, on touch) and the color blooms back to full. Two tokens, --photo-rest / --photo-alive, and no component may hand-write its own filter.

Coachella sunset at rest grade
at rest — the whisper
A demo night, hover to bloom
hover me — the bloom
Jumping on an empty road, full color
alive — full color, earned
hover to play — a loop rests as a poster, moves when you ask

motion-first law: when a slot has both a still and a loop, the loop wins — poster and reduced-motion fallbacks always in place.

frames are rounded rectangles (20px outer / 12px inner) — the old organic blobs are retired. video loops: muted, playsinline, ~0.5MB, poster fallback, lazy off-screen. an earlier version rested photos at pure black & white; it fought the warm paper and read cold, so the whisper replaced it — chosen from a five-grade darkroom lineup.

06 · no emoji

Emoji are someone else's pen.

Interface chrome uses zero color emoji: they're cartoons drawn by a platform vendor, they carry their own hues, and they render differently on every device. Three substitutes, one per pen:

Type does it

Most emoji can simply be deleted — the mono voice was already enough.

🎉 THAT'S A WRAP → THAT'S A WRAP

⚠️ error → ⚠︎ error (text-form dingbat, U+FE0E)

✅ done ×3 → ✓ done ×3

The gray pen draws it

When a picture is genuinely needed — empty states, theme badges, reaction controls — a 2px line doodle in the current ink.

the doodle set grows as needed — shuttlecock, paw, megaphone, cake, crown, heart, fire, laugh, party, clap, wow, camera, speaker on/off, signpost so far. 2026-09-30: signpost added for the 404 page (§09 Reading). 2026-08-05: the last eight came from party's reaction tray + mute controls (Step 6d) — ported verbatim except clap, which shipped in party as an abstract impact burst and got a real redesign pass here first (two angled mitten shapes crossing at the wrist, impact lines above) so the canonical version actually reads as hands clapping.

The red pen celebrates

Ceremony comes from the system, not a party-popper glyph: first place gets a vermilion rank, warnings get the red hairline, big moments get big type and motion.

  • 1team otter
  • 2noodle

the one exemption: emoji typed by guests and users render as-is — that's their voice, not our chrome.

07 · the stage

Backgrounds can live — behind glass.

A stage is a layer of living media between the paper and the chrome — a video loop, a photo wall, a slow generative drift. Hosts own what plays on stage; the system owns the proscenium: every stage wears the whisper grade, a room-colored veil, and the grain — non-negotiable, so anyone's media automatically belongs.

that's a wrap

Thanks for coming!

1team otter · 420 pts

video stage — live in the party app: the host uploads the loop, the TV wears it. also the post-emoji ceremony: big type and one red rank, no party-popper glyph

photo stage — two frames, 26s crossfade drift

breathing paper — the zero-asset fallback

  • video already wired into the party app: the host uploads a loop in the control room (≤4MB, straight to media storage); the TV wears it on the lobby and farewell only — the moment a question opens, the stage clears. Guest phones never render it.
  • photo Ken Burns crossfade; the party farewell can play the night's own guest photos — zero new assets, maximum personal
  • scroll hero-only: film at the top, the page pulls the curtain as you read; never a whole-page video
  • ownership hosts own the stage, the system owns the frame — the veil, the grade and the grain aren't host-configurable, so anyone's media lands on-brand
  • tempo stages move at ≥26s — they're weather, not actors; micro-interactions stay ≤300ms

08 · motion

The page moves because you do.

Everything you touch answers within 300ms; everything that moves on its own is scroll-driven or slower than 26 seconds. A ~40-line JS engine feeds scroll progress to CSS custom properties, because pure CSS scroll timelines silently fail in half the browsers out there. No JS, or reduced motion? The page is already in its final, fully readable state. Zero dependencies, no WebGL.

magnetic — leans toward the pointer, breathes on hover
drawn underlinelinks draw themselves
pointer tilt ±6°
3D for photos and toys, never text
3,500+ orders
count-up on first view
badminton host
pills float

one stage, five reflexes — bring a pointer and play. everything answers within 300ms.

scroll-reveal

Cards stand up

rotateX(22°) → 0 as they enter; older browsers get a one-shot rise instead of a scrub.

the headline above

Ink fills as you scroll

Scroll up and down — the section title floods from gray to ink, left to right.

the big one

Stacking photo cards

The homepage opener: four real photos stack one over the last, each developing as it arrives. See it live →

card wording reveals together with its photo — text never sits static while the image performs. big scroll stories are always vertical and always carried by photography: a giant-logo zoom and an ink-bottle pour were both built, both rejected.

09 · components

The working parts.

Forms, data, feedback, navigation, party hardware, prose — every interactive part of every surface, in one place. All of it passes the room test; flip the header switches while you play.

Forms

● that email needs a full address — red only shows up while it matters

focus = the border turns ink, no colored halos. tab through — every stop is visible.

Data

holdingweightday
NVDA31.2%▲ 2.4%
TSM18.7%▼ 1.1%

ink line, faint grid — the newest point is red because it's alive (door 2).

Feedback

no photos yet — go enjoy the party, upload later

one toast at a time, ink on paper inverted. dialogs are native; destructive buttons wear the red hairline. empty states teach, they don't say "empty".

Navigation & party

Mono labels, an ink underline that moves — the current page is always the ink one.
team 1
team 2
team 3
team 4

corrected 2026-08-05 — this used to (incorrectly) say "texture, not color." Checked against the real party source: teams are solid hex colors, a fixed 8-color palette assigned in order (2–8 teams), rendered as a swatch. Team color is the third content exemption (alongside photos and data semantics) — a guest's team is their own identity, not a chrome color, but it stays on the swatch/badge only, never a card background or button.

Prose

notes · №2 · a specimen paragraph

Body text stays quiet at 15–16px with a tall line. Medium ink carries emphasis, inline code sits on a panel, and the divider refuses to be a full-width line:

···

Quotes get a 2px ink bar and a little more voice. 双语是两种声部,不是翻译。

Reading

the parts every long page shares. skip link — the first thing a keyboard lands on, hidden until then (shown here in its focused state). focus — one global 2px ink ring, no colored halos. progress — the 2px red hairline under the header on notes; red door 2, it's live. page changes — a .2s cross-fade with the header held still, off under reduced motion.

pager — older on the left, newer on the right, one column on phones. whole half is the link; the title underline thickens on hover. no red: moving between notes isn't a result.

404 Nothing lives here.

no page at this address — the notes are at /notes; everything else starts at home

page-scale empty state — the 404. the signpost doodle, one sentence that says where to go instead. no joke, no dog: the home page already has enough of both.

10 · the voice

Write like a person.

plainone humane sentence beats three clever ones. empty states teach ("no photos yet — go enjoy the party") instead of announcing emptiness.

specificdecorative copy mines real details, never values-speak. "vibe coding past midnight" made the marquee; the six core values did not — true isn't the same as usable.

english leadsheadlines must stand alone in English; hanzi arrive as single-character seals (造 · 动 · 暖 · 聚) or names (暖暖) — footnotes, not the melody.

no thirdsthe same word or joke doesn't appear a third time on one page. one supervisor joke per page is plenty.

anchoredfloating captions must belong to their image — no joke gets parked on an unrelated photo just because it's funny.

dry humorthe mono voice keeps its spec-sheet deadpan: power draw: one espresso · latency: replies < 24h

11 · the rules

Eight rules derive everything.

rule 1chrome is monochrome; content keeps color (photos, data semantics)

rule 2red passes through four doors only, always as a hand-drawn stroke

rule 3three type voices, never a fourth

rule 4separation is a hairline; shadow means lift, never decoration

rule 5radius: 12–20px outside, 6–10px inside, pills fully round

rule 6everything touchable answers ≤300ms; every animation respects reduced-motion

rule 7components use room variables only — pass that, and all four rooms come free

rule 8new components are born on this page first. if it isn't here, it doesn't exist yet — design it here, prove it in four rooms, then ship it

12 · decisions

The system remembers its arguments.

A design system is a pile of decisions, and half of its value is the rejects. Kept public on purpose:

  • 2026-06The warm orange era ends. Cream paper and #f47d31 had run the site since the start — proven, friendly, and increasingly everyone's default.
  • 2026-07-03Five palette rounds. Crimson, magenta, marigold, brass, midnight, oxblood, electric azure — all built, all rejected. The lesson: the answer wasn't a hue, it was restraint.
  • 2026-07-03Ink and the red pen, ratified. Monochrome ink, one hand-drawn red, four rooms. A square seal stamp and two circle marks were tried and retired the same day — the red pen won.
  • 2026-07-03Two openers die. A giant-glyph zoom (logo as protagonist) and an ink-bottle pour (drawn props, diagram energy). The stacking photo cards ship instead — photography carries the big moments.
  • 2026-07-03The whisper replaces black & white. Pure grayscale fought the warm paper; a five-grade darkroom lineup settled it at 60% saturation with a warm cast. Same day: the emoji ban.
  • 2026-07-04The stage layer. Living backgrounds, host-owned content behind a system-owned proscenium. Marks learn to whisper — signature, not logo. Party rooms become switchable; the TV alone stays night.
  • 2026-07-05This page goes live. The lab becomes public — the spec, the components, and the graveyard, all in view-source.
  • 2026-07-05The hanzi diet, and motion first. The three-pens metaphor retires to the internal docs; the public hanzi inventory is fixed at seven characters — three names, four seals. And when a slot has both a still and a loop, the loop wins: video is a first-class element now.
  • 2026-07-05The dot retires as a mark. One shape, one meaning: a red dot already says "live" here — and to everyone else it says "notification". The swash is the only signature now; even the favicon is a brush stroke.
  • 2026-07-06Filter, never on the video. Three loops on this page (and three more on /nuannuan) sat frozen — WebKit doesn't repaint a `<video>` that carries a CSS filter directly, even while it's technically still playing. Fix: filter the wrapper, never the tag. Now a checklist line, so it doesn't happen a second time.
  • 2026-07-06Then a second, quieter bug in the same spot. This section's own hero loop still wouldn't play — in Chrome only, Safari was fine. The tell: the stage demo below it (scroll-revealed) played, the hero (a fixed opacity-0-to-1 entrance) didn't. Chrome appears to decide autoplay eligibility the instant a video attaches — one that's still invisible mid-fade seems to get skipped for good. Fix: autoplay video never gets an opacity-fade entrance again, plus a couple of delayed retries as a backstop.
  • 2026-08-05Red gets a fifth door. A round of external research (CrowdVolt/Love+Money/brandtoolk.it/The Raw Materials) plus an Opus checkpoint review before any of it shipped, then a second Opus review before ratifying anything. Found that the system was already making red fills in places nobody had flagged (the party countdown, first-place ranks) — the rule said stroke-never-block, what it meant was never-a-surface-treatment. §1 now has a fifth door: a full-strength fill for one singular, one-time result — never on hover, never repeated across peers. Ratified under it: the scoring/podium reveal. Rejected under it, rebuilt in ink instead: the block-flood card and the scroll-drama tiles — a hover state and a decorative pattern both fail "the one result" test. Also corrected: §6's party section wrongly claimed teams use texture, not color — checked the real source, teams are solid hex from a fixed 8-color palette; that's now documented as content, not chrome. Also dropped: the split-pill button (zero real call sites anywhere).
  • 2026-08-05Amber retired from data semantics. The hub's tri-state metric card (good/warn/bad) had quietly grown a third color, `--amber`, undocumented anywhere. Resolved: `t-warn` is plain full-weight ink, not a third hue — the system's whole thesis is that absence of color already reads as neutral, so "fine, but look" doesn't need its own color to say so. Data semantics stay two-valued: sage or seal, never a third.
  • 2026-09-30Borrowed from a neighbor. An audit of thedaviddias.com, for the small things: a skip link, one global focus ring, page-to-page cross-fades, a reading hairline and a pager on notes, a real 404, RSS, fallback fonts sized to match so nothing jumps on load. Left on his site on purpose: tab-title games, triple-click facts, sound effects, a Konami mode, a back-to-top button — charming there, noise here.

13 · ratified, mixed surfaces

Decided 2026-08-05, against a full Opus checkpoint review.

Redrawn against rules 1–8 and checked twice: once before any of it shipped, once more before ratifying. Everything below is now canon (rule 8 satisfied); each card's .cand-for tag says which surface(s) it's for. This section is a holding shelf by history, not by meaning — the cross-surface pieces (photo deck, per-word reveal, ink-blot, scroll drama, block-flood) belong conceptually in §08 motion / §09 components above, and party's two TV-only pieces belong with the rest of party hardware in §14 below; they haven't been physically moved yet, only decided. Move them on the next real edit pass rather than reading their location here as their permanent home.

Photo deck public · party TV

Already named in the system as "photo deck 展开" — listed, never built. Hover fans real photos open on a shared perspective, each shallower than the last.

7-Eleven Mobile
hover to open
(fine pointer only — same gate as pointer-tilt)

Per-word heading reveal public

Each word masked at the baseline, rising into place on a stagger — gives section breaks a family resemblance without competing with the hero, which already owns scramble + typing. Fixed 2026-08-05: the first build fired on a flat setTimeout, so on a real page every heading below the fold would already be "revealed" before you scrolled to it. Fixed again 2026-08-05: IntersectionObserver-gated wasn't enough either — it still only fired once on first view, so if that first crossing happened mid-scroll the reveal was already over by the time you actually looked. Now it replays every time the heading re-enters view, matching the "↻ replay" button below it. Never on the hero itself.

Section breaks arrive.

Loading curtain public · hub

A full-viewport overlay in the exact background color; a 1px hairline grows, then the whole thing fades. Function, not ornament — nothing today covers "the page is arriving." Shown at demo scale; replays automatically whenever this card scrolls into view.

report loaded

fixed 2026-08-05: a curtain that only JS can remove is a worse failure than no curtain — DS rule 6 requires no-JS to be a complete, readable page. Two safety nets, both required when this ships for real: a <noscript> rule that force-hides it (shown above), and a hard timeout in JS (~3s) that dismisses it regardless of load state, so a slow/failed data fetch can't leave the curtain stuck.

Ink-blot button public

The honest replacement for the ripple already cut — hover-duration and positionally meaningful instead of a 300ms flash. Fill is --ink only, text flips to paper. Fixed 2026-08-05: the pointer-only version left keyboard users with zero feedback — :focus-visible now fills the blot from center. Try tabbing to the button below.

Ruled baseline hub

The rule half only — text-align-last:justify was rejected (it fights Space Grotesk's tuned tracking, and a second underline would compete with the swash). On a report page this reads as ledger paper.

Holdings, this week

Self-drawing section rule hub

Same baseline as .ruled above, but it draws in every time the section scrolls into view instead of sitting pre-drawn — a report page with several section heads gets a small sense of arrival per section, not just once on load. Built defensively (2026-08-05): unlike the marks' self-draw above (which starts hidden and needs a <noscript> rule to force it visible), this one starts already drawn in plain CSS — JS opts a heading into the hidden-then-reveal animation by adding .js-draw right before it starts observing. No JS, slow JS, or a failed observer all just leave the rule sitting there finished, satisfying rule 6 with no fallback CSS required. Fixed 2026-08-05: used to fire once and unobserve, so scrolling back to it later showed nothing happening — now it re-draws on every entry, same convention as the per-word reveal above; reduced-motion drops straight to the drawn end state.

Holdings, this week

Overflow poster type + justify-fill party TV only

The one surface bold is earned: a fixed frame, an unpredictable-length string. The band stays ink — never a colored band.

ROUND 2

justify-fill earns its keep here — "ROUND " plus a number that's never more than two digits is a genuinely fixed, bounded frame; text-align-last:justify stretching it edge to edge is exactly the point.

Amended 2026-08-05 — the party-name headline (tv.html) does NOT use justify-fill, and that's a considered call, not an oversight. .party-name sits in a flex-centered scene with no natural fixed-width frame to justify against, and justify-fill has no built-in ceiling. Type a short name below ("YUMI", "HI") and watch the left box stretch its letter-spacing into something absurd — over-stretch on the common case, since most real party names are short, not a rare edge case. Shipped instead: clamp(28px, 6.4vw, 88px) for viewport-responsive base sizing, a JS fitPartyName() that shrinks in 2px steps to a 22px floor while scrollWidth > clientWidth, and overflow:hidden + text-overflow:ellipsis as the hard backstop below that floor. Same input drives both boxes:

BIRTHDAY PARTY

justify-fill — always edge to edge, no ceiling

BIRTHDAY PARTY

clamp + shrink-to-fit — sizes down, ellipsis is the floor

Command palette hub

Rerouted from the public site, where it would be theater — 24 report pages plus an index is where Cmd+K earns itself. Icons and a thumbnail grid dropped: no invented iconography.

2026-08 · Red gets a fifth door, and it's a fill. Turned out the system was already making red blocks in places nobody had flagged — an urgent countdown, a missed target — the rule said stroke-never-block; what it actually meant was never-a-surface-treatment. Now it says that: a fill is allowed when it's the one thing that won or failed, once per screen, never on hover, never repeated across peers. Door 5, DESIGN_SYSTEM.md §1. Under that rule: the scoreboard's winner flood ratifies as-is (a real single outcome, the same class of thing the shipped countdown does); the block-flood card and the scroll-drama tiles don't qualify — a hover state and a decorative pattern aren't "the one result" — so both got rebuilt in ink instead (see their cards below).

Block-flood card public · party

Whole card floods on hover instead of tinting an edge. Rebuilt ink, not red (2026-08-05): the original floods with a DIFFERENT hue per card — the variety carries it. One hue doesn't preserve that idea, it just spends the whole color budget on the most frequent interaction on the page, and a hover flood is ambient feedback rather than a signal — the same "confirms a click" failure mode as the ripple already cut. Rebuilt as an ink flood: same scale, same drama, and it's really the existing ink-blot gesture scaled up to card size.

AG
agency
TK
toolkit
+V
ventures

Scoring effects party TV

Ratified as-is under door 5 (§1) — bars race in with an overshoot bounce, rank numbers pop, and first place floods its whole row red. This is the door-5 case in its purest form: one screen, one winner, once. It's also scope creep on a rule that already existed — canon already gave first place a red rank number (door 2); this just extends "the rank number" to "the rank number's whole row," same meaning, bigger gesture. Fixed 2026-08-05: used to auto-play once, 600ms after page load — so on a real scroll it had already finished by the time you reached it. Now it plays every time the board scrolls into view, same as the "↻ replay" button.

1team otter
420
2noodle
286
3side quest
217

Scroll drama public

A word scales/tilts and a grid of tiles rotates off ONE scroll position, simultaneously — not one card fading in politely. Scroll the page to feel it. Fixed 2026-08-05: the "on" tiles used to flood red, chosen by i % 5 === 0 — pure decoration with no meaning, which fails rule 1 (chrome is monochrome) before it's even a rule-2 question. Now ink at 70% on panel2 — reads just as strong, no longer competing with the word for attention.

BLOCKY

Verdict block — "what this week asks" hub

Replaces the one-line attention strip, which gave a count and then truncated the first finding to 72 characters — so a reader told "3 urgent" still had to hunt the whole page for which three, and the page's own answer was to restate them at the bottom under "Also flagged", where nothing is read. Every finding states itself in full, once, at the top; then the ≤3 things to do, each carrying the same issue-key as the Triage card it maps to, so the list and the board are one object seen twice. Hard constraint (DS §11): everything here is computed by the grader, never written by the prose pass — the block has to render identically on a week when that pass never fires. A one-word verdict was explicitly rejected for this reason.

urgent
One goal at zero this week: Reading
urgent
Nothing closed out. 4 items pending, 19d since the last one landed.
watch
2 scheduled jobs not ok: example-sync, example-check

Chapter — a fold that keeps its number hub

A page with nineteen sections at one visual rank has no hierarchy, only order. Chapters give it three layers. The rule that makes folding safe: a closed chapter must still show its own headline number and say what is inside — otherwise collapse reads as deletion (DS §11 rule 2). Native <details>, so no-JS and reduced-motion both terminate on a complete, readable page. Try them: the numbers stay put when closed.

Work 工作4shipped
Delivered, slipped and blocked items — each a sub-part here, not a peer of the scorecard above.
Commitments 承诺2overdue
Two dated promises past their date with no close-out. Open by default because the number is non-zero.
Evidence 佐证31items
Day-by-day, commits, momentum. Reachable, not resident.

Status meter — a zero is drawn empty hub

The one that mattered most. This meter used to floor its width at 2% with a min-width:3px fill tinted --seal, so a goal that was touched zero times rendered a small vermilion stub: a bar drawn where there was no quantity at all. Now the track renders and no fill element is emitted. The shortfall is visible as the distance it isn't filled, the number stays at full weight, and seal stays on the number where §1 already sanctions it (跌朱只贴数字). The consumer trackers this pattern came from withhold red because they need you back tomorrow; a private accountability page has the opposite contract, so the red stays on the number and only leaves the bar. 2nd week is a computed consecutive-zero streak, not prose.

Garden 园艺
5 sessions logged
5✓ ok
Reading 阅读
nothing finished
0✕ none· 2nd week

Foldable 中文 companion hub

The house rule is a companion line under the English, never a language swap — English stays load-bearing (settled in daily-reports 117b794, and §11 does not reopen it). What §11 adds: when the Chinese ships as full parallel paragraphs rather than a line, it roughly doubles the tallest block on the page, so it must be foldable and folded by default. The preference persists, and must be re-applied after any re-render — a page whose history picker silently resets the reader's choice is worse than one that never offered it.

Reading's zero is the one that repeats: this is the second week in a row at zero, with four books started and none finished.

阅读的零是这周唯一重复的一项:连续第二周为零,开了四本书,一本都没读完。

14 · party hardware

Party's stage, built the way it's actually shaped.

Rule 8, taken seriously: the party TV prototype had a real podium reveal, countdown, and QR-code lobby chip that never made it into this page — meaning by the letter of rule 8 they didn't exist yet. Built here for real, in a container-type:inline-size frame so the sizing is relative to the 16:9 stage, not to this page's width (the source prototype used raw vw, which is correct on an actual TV and wrong here — fixed with cqw).

leaderboard · all rounds

2noodle286 pts
2
1team otter420 pts
1
3side quest217 pts
3

1st place is door 5 (§1) — a single, one-time, full-strength fill for the outcome that won. 2nd/3rd stay ink. Real structure from tv.html's staged 3rd→2nd→1st reveal, not an invented layout.

countdown · urgent (≤5s)
4
real class: .countdown.urgent — text color + pulse in the actual product; the filled circle here is this page's convention for "a number that needs a shape," not a claim that the shipped countdown looks exactly like this
lobby QR + code
K 7 H 2 X 9

Farewell photo deck party TV only

The wrap screen's photo backdrop is the night's own photo-reactions, fanned open on a timer instead of on :hover — a TV has no pointer. Diverges from §13's Photo deck card on purpose (2026-08-05): the first build reused that card's rotateX tilt at full-bleed scale and lost — a 3D-tilted stack either collapsed to zero height (three position:absolute layers give their parent nothing to size itself by) or, once sized, sat in the same central real estate the podium above occupies and glitched through it. Shipped instead: full-bleed, not a floating card, and each layer receives inward like nested frames at the screen's own edges rather than tilting in 3D, so the reveal never competes with center-screen chrome. Still wears all three stage-layer pieces — whisper grade, veil, grain (DS §4.5). Real structure from tv.html's #farewell-deck-layer.

at rest this reads as one full-screen photo — the fan (auto, every 32s+ live; on demand here) is the only tell it's a deck, unlike §13's card above which is hover-only.

saved

Remove this guest?

Unassign keeps their points with the team; kick deletes them. House rules.