Decision log — detail pages flat language
Status: Reference · Scope: every owner ruling that produced the flat detail-page language (docs/twomore_design_system/wireframes/detail-flat-language.jsx). The wireframe board shows only the shipped final state; this log keeps the "why," including the two rejected options each FINAL ruling reverses.
| Date | Ruling | Outcome | Where it lives in code |
|---|---|---|---|
| 2026-09-05 | Section boundary: a hairline between every peer row, including a section's first | Rejected — a section edge read as just one more row, no distinct "new group" signal | superseded by packages/ui/src/fact-row-visual.ts, list-row-visual.ts |
| 2026-09-06 | Section boundary: whitespace-only (32px gap + a heavier title, no line) | Rejected — read as crammed on device once 6–12 blocks stacked | superseded by packages/ui/src/flat-column-defaults.ts |
| 2026-09-06 (FINAL) | Divider law — dividers separate SECTIONS only; peers inside a section are spacing-only (12px padding); a divider between peers is allowed only when each peer is itself a multi-component block | Decided, shipped | packages/ui/src/flat-column.tsx, flat-column-defaults.ts, fact-row-visual.ts, row-list.tsx |
| 2026-09-06(c) | Section-divider seam value | Retuned 20/1/20 → 24/1/24 under the seam ladder | packages/ui/src/flat-column-defaults.ts (FLAT_COLUMN_DEFAULT_GAP = '$6') |
| 2026-09-05 | Media-hero title placement: white text over a photo scrim vs. title below the photo on the canvas | Decided — below the photo; a scrim can't guarantee contrast, and the failure mode was the tinted-ground + chrome-hero combination, not the hero alone | packages/ui/src/media-hero.tsx |
| 2026-09-05 | Where tint survives on an otherwise flat page | Decided — Well · Callout · Banner · empty state · shelf tile · input background only; the stat strip stays hairline-only, not tinted | packages/ui/src/well.tsx, callout.tsx, banner.tsx, stat-strip.tsx |
| 2026-09-05 | DetailShell canvas rollout: flip the tinted→flat default everywhere at once vs. opt in screen by screen | Decided — opt in via ground="canvas", flip the default once all 11 screens are converted | packages/ui/src/detail-shell.tsx |
| 2026-09-06(b) | ActionIconRow anatomy: space-between + content-sized items vs. equal-ratio flex:1 cells with a full-cell pressed state | Decided — equal-ratio cells (re-grounded to match the already-shipped component) | packages/ui/src/action-icon-row.tsx |
| 2026-09-06(b) | Hero titleBadge slot — one entity-state badge trailing the title, separate from the badges row | Shipped, then retired by the one-badge-home ruling below (2026-09-06(g)) | packages/ui/src/media-hero.tsx, type-hero.tsx |
| 2026-09-06 | Venue verification badge / "confirmed only" filter | Decided — no unverified/verified badge or filter anywhere; "verified" renders only on an owner-verified venue | packages/app/src/domain/venue-trust.ts (deriveVenueTrustTier) |
| 2026-09-06 | Affordance law — every tappable element shows exactly one resting cue (chevron, button chrome, $primary link ink, or a state layer + chevron/glyph) | Decided | packages/ui/src/pressable.tsx, list-row.tsx, well.tsx; lint @twomore/pressable-needs-affordance |
| 2026-09-06(c) | Spacing & alignment system — one 6-rung seam ladder (XS4/S8/M12/L16/XL24/XXL48, one token per relationship) + two alignment rails (TEXT 16, FULL-BLEED 0), replacing ad hoc per-screen values | Adopted and built | packages/ui/src/seams.ts, flat-column.tsx, bottom-cta-band.tsx, section-header-metrics.ts, stat-strip.tsx |
| 2026-09-06(e) | Middle-dot (·) joins inside meta/sub text | Decided — removed; hero meta is string | string[] (one fact per line), a second fact rides as a trailing badge instead of being joined into the label | packages/ui/src/media-hero.tsx, type-hero.tsx, fact-row.tsx, list-row.tsx |
| 2026-09-06(e) | Meta-text grammar — one color/weight tier per slot (primary meta = cardBody/$textSecondary; secondary/sub/eyebrow = cardMeta/$textTertiary; caption = smaller cardBody) | Decided | packages/ui/src/text.tsx, tokens.ts |
| 2026-09-06(e) | Graphics-lead law — avatars/logos/thumbnails render left and top, never as a trailing or bottom-right overlay | Decided — TypeHero gained a leading slot; the club member-faces cluster moved to FlatColumn's lead row | packages/ui/src/type-hero.tsx, media-hero.tsx, flat-column.tsx |
| 2026-09-06(f) | Palette — OKLCH-defined ladders (one fixed hue, ~even L steps, a designed not-reversed dark-gray scale, dark primary promoted to its tone-80 step) vs. the previous ramp (a gray700 hue/chroma kink, dark gray as a literal reversal of light, dark-primary-button APCA 52) | Adopted, live | packages/ui/src/tokens.ts, packages/app/src/config/themes/classic-grass.theme.ts |
| 2026-09-06(g) | One badge home — a hero used to scatter badges across three homes (media status overlay, titleBadge, badges row); collapse to Option A (one row, fixed order state → verification → category, directly under the title) vs. Option B (inline trailing the title) | Decided — Option A shipped; titleBadge and the media status overlay retired | packages/ui/src/media-hero.tsx, type-hero.tsx |
| 2026-09-06(h) | Hero composition — every hero opens with SEAM.hero(16) under the chrome/media band (never the generic SEAM.chrome/12), the eyebrow spans the rail above the identity row, and a leading graphic top-aligns with the title line | Decided | packages/ui/src/type-hero.tsx, media-hero.tsx |
| 2026-09-07 | Two grammars (cards for browsing, flat for detail) vs. one grammar keyed on content shape — flat sections for every detail page AND every homogeneous list; object cards only for session/club/venue collections; one canvas ground | Decided — one grammar; the club-ops screens, the guest review flow and the venue finder's non-card chrome all go flat | docs/canon/components.md (Canvas law), /wireframes/club-ops, /wireframes/guest-roster, /wireframes/venue-finder |
| 2026-09-07 | Canvas migration order for the still-tinted list/settings shells: big-bang vs. by nav tree vs. by migration risk (shell then chrome, flat-row screens first) | Decided — by risk, on the condition that every migrated screen honours the group-spread law (equal cells, fixed gap, centered content) and the seam ladder | /wireframes/canvas-migration (decision record), packages/ui/src/cell-row.tsx, stat-strip.tsx |
| 2026-09-07 | Session-card bookmark: on the participation (meter) row vs. the strip band's right pole | Ruled off the meter row; the strip right pole answer was then overtaken the same day by the owner's "we are moving away from top strips" (next row) | packages/app/src/domain/session-strip.ts, session-strip-ui.tsx |
| 2026-09-07(b) | Session summary card top strip — the owner: "we are moving away from top strips for session summary cards". No earlier ruling retires it (v6 band shipped 2026-07-28). Proposal drawn: state word + tone on the closing row, my standing badges beside the meter, bookmark in the tile's top-right corner (corners law on the tile) | Proposal on /wireframes/session-card, awaiting the owner's confirmation before the card, the detail-screen band and the strip-map board change | session-card-v2.tsx, session-strip-ui.tsx, domain/session-strip.ts |
| 2026-09-07 | Club summary card corners law (tier top-left, alarm top-right; discover top-right reserved) | Confirmed as the established member card; the iteration-23 alternatives are retired from the board | packages/features/clubs/src/shared/club-card.tsx |
| 2026-09-07(b) | Discover club card — the owner: same corners law (tier top-left, recruitment stat top-right) plus a bottom terms-chip row (join policy · dues); replaces the four-way terms-zone question | Drawn (D23-E); the terms row sits under the identity chips — placement to confirm, then build | club-card.tsx, club-photo-seam.tsx |
| 2026-09-07(b) | Club detail tabs — the home tab stands; 일정 · 채팅 · 랭킹 · 멤버 · 회비 panes rework to the flat layout | Drawn on /wireframes/club-detail-redesign; build after the drawings are approved | club-detail/sessions-pane.tsx, members-pane.tsx, dues-pane.tsx, ranking-tab.tsx |
| 2026-09-07(b) | Review boards — options A/B/C vs. one recommended path per board | Decided — every proposal board opens with one FlPath block; the phones are the path | docs/twomore_design_system/wireframes/_kit.jsx (FlPath) |
| 2026-09-07(c) | Session card bookmark — tile corner vs. right of the weather on the venue line | Owner: right of the weather; drawn in WFSessionCardV3 (kit), used by the session-card and club-detail boards | proposal — session-card-v2.tsx once confirmed |
| 2026-09-07(c) | Discover club card corners — recruitment STATUS (N명 모집 중) top-right; the member/capacity chip stays on the seam; terms chips as the bottom row | Owner direction, drawn (D23-E) | club-card.tsx, club-photo-seam.tsx once confirmed |
| 2026-09-07(c) | Club detail — all six tabs flat, no session cards with top strips inside the detail page | Confirmed; the redesign board's next-session card is the no-strip card, the 일정 tab is compact rows | club-detail/* panes |
| 2026-09-07(c) | Venue finder streamlining (near-me default, zero-query state, kind-aware facets with counts, card v3) | Approved — build queue (held until Codex's venue branch is reconciled, since it touches the same finder files) | /wireframes/venue-finder (approved lane) |
| 2026-09-07(c) | Board hygiene, found by screenshotting the built boards with the local headless Chromium — the "misaligned hero" was a caption wrapper's text-align:center leaking into every phone on the guest board; the club-detail redesign rendered no phones at all (a board without an anatomy sheet hid its states); the tier-range badge wrapped onto two lines in a three-chip row | Fixed at the source: WFPhone owns text-align:left; anatomy-less boards show every state; the badge never wraps. Screenshot verification is now part of the board loop | docs/twomore_design_system/wireframes/_kit.jsx, scripts/build-wireframes.mjs |
| 2026-09-07(d) | Guest review detail → a GUEST PROFILE page: identity-only hero (no 게스트 chip, no dates as meta), a participation strip (참석 · 노쇼 · 첫 참석 · 최근 참석), a qualification checklist for admittance, and visit-history rows; members keep the member profile page | Owner direction, drawn on /wireframes/guest-roster phone (b) | join-review-detail-screen.tsx once approved |
| 2026-09-08(a) | Club summary card seam: the member faces + capacity cluster sits at the seam's RIGHT end, the flag alone on the left ("it's supposed to be at the end") — reverses 2026-09-06's beside-the-flag placement; two reversals, the corners law stands | Final — corners law | packages/features/clubs/src/shared/club-photo-seam.tsx (CLUSTER_RIGHT_INSET), kit WFClubCard |
| 2026-09-08(b) | Session state word: no lead icon beside the status text; the live pulse is the only glyph | Final | session-strip-ui.tsx (SessionStateInline) |
| 2026-09-08(c) | Session card closing row: attention + standing chips render as badges (SessionStripChipBadge); the countdown sub is omitted when the lead already names the moment (곧 시작, 우천 예보, live); LIVE is the one state that keeps a top strip band | Final | session-card-v2.tsx, session-strip-ui.tsx, kit WFSessionCardV3/WFSessionStateWord |
| 2026-09-08(d) | Bookmark is visible on every session card (outline unsaved, filled saved) right of the weather, and it is the toggle; the detail header keeps its own | Final | session-card-v2.tsx + SessionSaveButton variant="card" |
| 2026-09-07(d) | Spacing and alignment on every component — owner repeated the rule; boards now carry a build-time rhythm check (space-between + off-ladder px values, RHYTHM=1 for the list) and are screenshot-verified before deploy | Standing rule | scripts/build-wireframes.mjs |
| 2026-09-08(e) | Compaction rulings (audit §3, boards /wireframes/compaction-*) — D1 YES: CollapsingTopBar on EVERY detail page with a graphical hero (title reveals on scroll); the hero must not restate the session title (drop it from the session model's hero, sessionTitle stays a list-card derivation only) and the flat one-fact-per-row metadata under hero titles is rejected → research/reuse a compact IDENTITY pattern and apply it to every hero; detail-page side spacing must match club detail's rail. D2 KEEP the StatStrip as the numbers row, each detail page choosing its key facts (no restatement elsewhere). D3 key badges live BESIDE the title, never below; the header live dot stays. D4 NO — 정보 stays expanded. D11 YES rules once per session; open: a visual anchor at the top of live pages. D12 NO collapse; each detail page gets its own pass. D5/D6 keep the three full screens AND the 홈 schedule block (alternative would be auto-posting/pinning upcoming meets in the feed). D10 NO — title left + bell right symmetry stays. D8 YES merge the two scope controls. D7 YES merge ELO/reliability, heatmap stays OPEN, trend card = delta. D9 YES attendance once + reliability into the ELO sheet; profile meta (클럽, 구력) become badges, with a merged club-logo+name badge. | owner |
Superseded boards
Six *-detail-redesign wireframes (drawn 2026-08-30/31 into the club-detail place-surface format — one-card heroes, card-boxed sections on a $card canvas) predate the Canvas law (owner, 2026-09-02) and are superseded by the flat-language board; their role-density findings (participant/host/guest slots) still stand.