Skip to content

Owner review 1, lane C: header chrome, overlays, photo bands, messaging, live scoring, rows and shelves (2026-10-11) ​

Status: Draft · Date: 2026-10-11 · Purpose: answer the owner's points 14, 15, 17, 18, 19, 8 and 23 from the first review of the flat v2 boards with current platform guidance (Apple HIG, Material 3), usability research (NN/g, Baymard, peer-reviewed icon studies), WCAG 2.2, and measured practice in real apps (Korean first, then global); then audit the library sections the owner did not comment on (§14 page components, §18.2 to §22.2). Every claim carries a URL; where a source does not publish a number this note says so; where sources disagree it says so and recommends. Reads: component library (§3, §5, §8, §14, §16 to §23), IA and flows (§2 IA-3 to IA-5 and IA-10, §6 rulings 3 to 5), the usability audit (U-05, U-09, U-12), canon components.md (header-right law, place-surface law), and the boards flat-v2-patterns, flat-v2-detail, flat-v2-list-a.

At a glance ​

#Owner pointAnswerSection
14Header text actionsThe owner is mostly right. Entries (관리, 초대 코드, 선택, 편집) leave the header for a registry icon, a labelled body entry or a three-row ⋯. Text stays only to leave or commit a mode (취소, 완료, 저장, 전체 선택) and is drawn as a button, because bare ink text is a weak signifier and the header text actions found in peers are pills (KakaoTalk, 배민, Airbnb), tinted compose text (네이버 카페) or a native tinted bar (TeamSnap), never bare ink.14
15When is an ActionSheetOne rule by what the person is doing: confirm → Dialog; choose a command for an object → one bottom list (today's ActionSheet, renamed MenuSheet; the anchored Menu survives only at 600 pt and up); choose a value or enter data → Sheet; read at length or run a flow → page.15
17Actions on the photoBack, plus at most two universal icons: share and save, with ⋯ only when it holds three rows. Circles 40 at ink α0.5, never text or pills. Place actions (길찾기, 전화, 가입, 참석) live in the body or the CTA band.17
18Message spacingThe bubble and composer spec already tracks the best open reference (Signal-iOS). Change five values: within-run 4 → 2, system lines 16 → 20, bubble max 264 → 306 for 1:1 (266 for groups), thread-to-composer gap 12, home inset 0 while the keyboard is up.18
19Live score controlsMake each team's own panel the control (5 of the 8 scorers that state a mechanism tap the team's own area, 3 map a swipe or crown direction, none uses a shared +1 button row). Full-screen recorder, panels at least 160 pt tall, a labelled 되돌리기, server as glyph plus word, a non-blocking 코트 체인지 banner, a confirm only at match end.19
8Session row leads with the courtAgree. 11 of 13 comparable lists lead with the title or venue (the two exceptions are one app, 플랩풋볼, whose time and venue are equally bold). Venue is L1 in mixed-venue lists; time is L2 in ink 500 (not secondary); level and format are L3 in discovery only. Where every row shares one court, the court moves to the list head and the time leads.8
23Horizontal lists on detailKeep the roster vertical but cap it at one row of four cells (a door replaces the last cell when there are more than four people). Horizontal shelves only for optional browse content (photos, next sessions), at most 5 + 전체 보기. That is the place-surface law already in canon, and it reconciles the "no horizontal scroll for my stuff" rule.23

How this note was built ​

  • Store frames. App Store frames come from the iTunes lookup API (https://itunes.apple.com/lookup?id=<id>&country=<kr|us>, field screenshotUrls), fetched 2026-10-11 for 49 apps; Appendix A lists the 33 that are cited, with id, version and release date. Frames are publisher-curated marketing screens, so they show the intended screen, not live behaviour. Sizes read from frames are in pt = px ÷ (phone screen width in px ÷ 390), error about ±2 pt; the measuring scripts and crops are in the lane scratch directory and are not committed. Play Store frames (Airbnb Android tablet layout, Kakao Map, 네이버지도, 배민, Tennis Math) come from the Play listing HTML; their frame numbers are positions in the listing's image list, where no. 1 is the app icon, so the first screenshot is no. 2. App Store frame numbers count screenshots only, from 1.
  • Web renders. Airbnb listing, 네이버 플레이스 and 카카오맵 place were rendered in headless Chrome at 390 × 844, 2×, iPhone user agent. They show the mobile web page, which can differ from the app; they are labelled "web".
  • Guidelines. Apple HIG pages are read from the JSON behind developer.apple.com (change-log dates quoted where they matter); Material 3 pages are rendered in headless Chrome and read as text; Seed (당근) and TDS (Toss) docs and the WCAG Understanding pages are read directly; NN/g and Baymard articles are read in full and sample sizes are quoted only where the article states them.
  • Not reachable. The BWF news page on the 3×15 change returned 403 to our fetcher (the 2027 date below is from a search summary and is marked unverified). No public documentation of Grand Slam or ITF chair-umpire tablet interfaces was found. "Tennis Math" exists only on Android. Apple Maps and iMessage are judged from Apple's iOS 26 newsroom images and support pages, not from a device.
  • Computed here (C). Contrast ratios use the WCAG relative-luminance formula; physical sizes assume a 460 ppi, 3× iPhone (1 pt = 0.165 mm, so 44 pt = 7.3 mm and 1 cm ≈ 60 pt).
  • Keys. [P] platform guideline, [R] research, [S] standard, [K] Korean app, [G] global app, [D] repo document, [C] computed here.

14. Header actions: icons or text? ​

Owner: "Shouldn't the top actions all render as icons? So only the actions that are unambiguous enough to be rendered in an icon should be rendered. The ones that are not should be rendered elsewhere."

What we have ​

  • Library §14 HeaderTextAction: ghost text 15/22·600 ink, pad 0 12 in a 44 target, at most one per side, left of any icon, label up to four syllables, never destructive. §3 Header allows two 24 icons; §17 H1 puts ⋯ rightmost; §16 P5 draws it over a MediaBand as white text on an ink α0.4 pill, 36 tall.
  • The shipped component is tinted: canon says it defaults to $brand600 and "the accent tint on the label IS the one resting affordance cue (no icon, no chevron)" (canon/components.md line 122). The v2 spec recolours it to ink, which removes the only cue it had.
  • The boards use it for 관리 (club hub, session host), 초대 코드 (클럽 tab), 선택 (알림 and list pages), 편집 → 완료 (프로필), plus a section command 모두 읽음. The edit-state swap 취소 / 완료 is already canon (line 121).
  • Why text exists: U-05 found officials could not find club management behind an unlabelled ⋯; U-09 found a bare key icon undecodable but kept "back, search, share, gear, chat, ⋯" as the universal set (usability audit U-05, U-09).

Evidence ​

Platform guidance

SourceFinding
HIG toolbars (updated Jun and Dec 2025)"Prefer simple, recognizable symbols for items instead of text, except for actions like edit that aren't well-represented by symbols." Back and Close: use the standard symbols, "don't use a text label that says Back or Close." "Use the .prominent style for key actions such as Done or Submit… Only specify one primary action, and put it on the trailing side." "Keep actions with text labels separate": a text-labelled action beside a symbol can read as one combined control, so insert fixed space. More menu: "Try to include all actions in the toolbar if possible, and only add this menu if you really need it."
HIG pull-down buttons"the ellipsis icon doesn't necessarily help them predict its contents"; "Avoid putting all of a view's actions in one pull-down button. A view's primary actions need to be easily discoverable"; "listing a minimum of three items can help the interaction feel worthwhile"; an Add button can "present a menu that lets people specify the item they want to add".
HIG buttonsHit region of at least 44 × 44 pt. "Consider using text when a short label communicates more clearly than an icon."
HIG standard iconsApple lists symbols for Done, Cancel, Delete, Undo, Add, More, Select (checkmark.circle), Share, Search, Filter and Account. It lists no settings, notification, message or bookmark symbol, so those four rest on market convention (the Korean peers below).
M3 app bars"1–2 essential actions." "App bars should only have one action, two if necessary. The primary action should alter or exit the entire page, like Send, Save, or Edit." "Avoid placing an overflow menu in the app bar when possible." Up to two icon buttons, "Put the most used actions on the left and least used on the right"; more actions go "in a toolbar". Transparent bar over content: "Make sure icon buttons have a container fill."
M3 icon buttons"common, easily understandable actions. Only use a few icon buttons at once." Toggle icons go outlined → filled, or heavier weight, so selection is never colour alone. Default container 40 dp.
앱인토스 navigation bar (Toss mini-apps)Right side: one accessory icon beside 더보기 and X; "모노톤 아이콘만"; "한 번에 표시할 수 있는 액세서리 버튼은 1개뿐". Text buttons are not mentioned.

Research

SourceFinding
NN/g, icon usability"a text label must be present alongside an icon to clarify its meaning in that particular context." Only home, print and the magnifier are near-universal; heart and star are often misread; "Obscure icon = wasted feature." The article gives no sample size.
NN/g, hidden navigation179 participants, 6 sites. Hidden navigation lost more than 20% of content discoverability; on mobile 57% used hidden navigation against 86% for combined navigation, and tasks were 15% slower.
NN/g, weak signifiers71 users, 9 sites, eye tracking. Weak-signifier versions took 22% more time and 25% more fixations. Weak means a ghost button or a link styled as static text.
Leung, McGrenere and Graf (2011)Adults 65+ against 20–39. Older participants "did have more problems using existing mobile device icons"; icons that were "semantically close meaning… familiar, labelled and concrete" helped. Labels improved initial usability but "did not help older adults more than younger ones".
Wu et al. (2022)15 adults aged 60–66, eye tracking. Icon plus text beat icon alone for every older adult, including those with mild cognitive impairment; flat icons without text were worst. Small sample, healthcare icons only (the authors' own limits).

Peers: every header text action found (headers read from store frames and web renders; none of the admin entries below is bare text)

App and screenLeadingTrailingText action in the header?Source
Toss 홈, 증권, 쇼핑, pushed pageslogo or "<"bell; search, ≡; search, person, cart; nonenoToss fr 1, 3 to 5
당근 홈, 커뮤니티, 알바, 부동산, 중고차, 당근페이, job postlocation, title or X; "<"search, bell, ≡; ✎, person; ♡, ≡; gear; share, reportno (one extended FAB "+ 글쓰기" carries the label)당근 fr 2 to 8, Play fr 6
KakaoTalk chat; 프로필; 친구 tabback circle; X; namesearch + ≡ in one pill; "프로필 편집" pill + ⋯ circle; search, add, gift, gearone: a pill over the profile photoKakaoTalk fr 1 to 6
배민 content pages; 장보기; delivery map"<"; title; Xhome, cart with count; coupon, search, cart; "문의하기" pillone: a white pill over the map배민 fr 3 to 7, Play fr 4 to 8
네이버 카페 home; cafe page; 중고거래; 글쓰기brand; back circle; "<"; Xpill, +, search, gear; chat, search, ≡ circles on the photo; ⋯; 임시저장 (grey) and 등록 (green) textone pair: coloured text in the compose stateNaver Cafe fr 1, 3, 4, 7
밴드 홈, 그룹, 일정logo; "<" title; titlesearch, mail, avatar; search, chat, gear; filternoBand fr 3, 4, 5
소모임 홈, 그룹; 테니스프렌즈 매치 상세location; "<" titlesearch, bell, send; ♡, share, ⋯; share, ⋯no소모임 fr 3, 4, 7, 8, 테니스프렌즈 fr 5
네이버지도 saved list; 네이버 플레이스 (web)sheet title; "<"rows ⋮; ☆ and avatarno; body pills 편집, 공유 / 길찾기, 공유, 전화, 알림받기Play fr 8, web render
카카오맵 theme map, ranking; place (web)back circle; "<"share, map circles on the photo; shareno; body pills 출발, 도착 beside icon circlesKakao Map fr 8, web render
Airbnb listing; message threadback circle; "<" avatarshare, ♡ circles on the photo; "Details" pillone: a grey pill in the thread headerPlay fr 6, 10
Meetup event, profile; Luma event, community, profileback circleshare + bookmark in one pill; ✎ + gear pill; share; search + ⋯ pill; message + ⋯ pillnoMeetup fr 4, 6, Luma fr 3, 4, 6
Eventbrite; Playtomic club; Booking hotel"<"share, ♡; share (♡ in the body); none (title bar)noEventbrite fr 2, Playtomic fr 5, Booking fr 3
쿠팡 product page"<"none (share and gift sit under the photo)noPlay fr 3
TeamSnap game (iOS native bar); Google Calendar event"Back" ; X"Edit" text; ✎, ⋯one: native iOS bar text, tintedTeamSnap fr 2, Google Calendar fr 3
Apple Maps place card (iOS 26)share× closeno; labelled pills Call, Website in the bodyApple newsroom

Reading of the table: of 15 rows (about 46 header states), five header text actions exist. KakaoTalk, 배민 and Airbnb draw theirs as pills, 네이버 카페 uses coloured text in a compose state, and TeamSnap uses the native tinted bar. None is bare ink text and none opens an admin tool. Where a peer needs a labelled place action it puts it in the body (네이버 and 카카오 place pages, Apple Maps), and admin entries are gear icons (밴드) or body entries. The icons in these headers are the same few glyphs: search, bell, chat, share, bookmark or heart, gear, plus, ⋯, back, close.

Reading ​

  1. The owner's instinct matches the platform and the market. Both guidelines cap the bar at one or two actions, prefer symbols for common actions, and keep text for Edit, Done and Cancel; the Korean apps the audience lives in use icons in headers.
  2. The usability research does not say "icons only" either. It says unlabelled and ambiguous icons fail (NN/g, Leung, Wu), and that hiding an entry costs discoverability (NN/g, 20% or more). The failure U-05 found was a ⋯ that hid an admin console, not the lack of a word in the header.
  3. Bare ink text is the weakest option. It has no container and no tint, so it reads as a label (NN/g's weak signifier, +22% time). The shipped component had a tint; the v2 recolour removed it. The owner's own wizard law ("top controls must look like buttons, not bare glyphs", library §21.1) already says this for the wizard header.

Recommendation ​

RuleStatement
H-1One closed registry of ten header glyphs, the owner's list: ‹ back, × close, 검색, 공유, 저장 (bookmark), 알림 (bell), 메시지, 설정 (gear), 추가 (+), 더보기 (⋯). Each has one spoken name that is also its tooltip (web) and coachmark text. A new glyph needs a ruling. Enforce with a lint on the header slot (as HeaderIconButton is already mandatory).
H-2At most two trailing icons; most used leftmost; ⋯ rightmost (M3: "Put the most used actions on the left"; canon already caps the bar at two glyphs).
H-3A ⋯ holds three or more rows, or it does not exist, and it is never the only route to something an official must find. (HIG pull-down: "a minimum of three items"; M3: avoid overflow in the app bar; canon line 121 already says a badge "never hides in a menu".) Today's boards draw two-row ⋯ menus (club hub: 공유 · 나가기); promote 공유 to an icon and move 나가기 into the sheet it belongs to.
H-4Header text means leaving or committing a mode, and it is a button. The set is 취소 · 완료 · 저장 · 건너뛰기 · 전체 선택. Shape: sm Button (36 tall), tonal for 취소, 전체 선택 and 건너뛰기; primary (ball) for 완료 and 저장, one per bar, trailing (HIG .prominent). Bare ink header text is retired; so is the P5 text pill over photos.
H-5Entering a mode or reaching a tool is never header text. It is (a) a registry glyph, (b) a row of a three-row ⋯, or (c) a labelled body entry: a Task Cell with a count Tag, a section command, or a CTA.
H-6Discoverability guard for officials (U-05). The gear carries the Header icon badge when anything is pending (§18.2); each club pane ends with its labelled tool Cell (IA-7); the officials' 할 일 section lists pending work; a Coachmark (§8) points at the gear once when a member becomes an official. Acceptance test: five newly appointed officials are asked to change the club's bank account; pass if at least four reach the 관리 sheet within 10 s unaided (five users find about 85% of problems). If two or more fail, the pre-approved fallback is a sm tonal 관리 pill, not bare text.

Where each current text action goes

TodayNew homeEvidence
관리, club hub (officials)Gear icon with badge in the header opening the 관리 sheet (content unchanged). Twins in the body: pane tool Cells (IA-7), 할 일 Task Cells. 클럽 나가기 moves to the sheet's last group.밴드 puts a gear in its group header; U-09 lists the gear as universal; M3 two icons; H-6 test
관리, session (host, officials)Same gear and badge; 일정 수정 stays the sheet's first row (D1). Pending applicants and 입금 확인 stay in the Notice stack.as above; IA-3
초대 코드, 클럽 tabThe header + opens a three-row sheet: 클럽 만들기 · 초대 코드로 가입 · 클럽 찾기. Empty state: two Buttons (탐색 leads, U-10). Non-empty list: a closing Cell "초대 코드로 가입".HIG pull-down: an Add button can present "a menu that lets people specify the item"; U-09 and U-10; the usual route is the tapped link, the code is the fallback
선택, 알림 and list pagesA ⋯ with 선택 · 모두 읽음 · 알림 설정 (three rows; the header becomes [⋯]). 모두 읽음 also stays as the 새 소식 band command (owner V2, 2026-07-31). Long-press stays an accelerator. Dues and fee reconcile screens need no entry: they open in select mode with the 확인 대기 rows ticked (ruling 12) and the CTA band carries the count.Apple's own Mail: "tap the More button in the upper-right corner, then tap Select" (Apple Support); Apple Photos instead keeps a labelled "Select" button (Apple Support), so Apple is split
편집 → 완료, 프로필편집 is the pencil already drawn on the identity Block (§4); in edit mode the header shows 취소 and 완료 as H-4 pills.HIG: Edit is the one action Apple keeps as text; our EDIT-PENCIL law makes the pencil the app's edit cue; HIG .prominent for Done
모두 읽음Stays a section command on 새 소식 (13/18·600, no chevron); raise to 15/22·600 so the command is not the smallest text on the page.owner V2 relocation (canon line 121); U-12 asked for card meta at 14
취소, 완료, 전체 선택 (select and edit)Stay text in meaning, become H-4 pills.HIG sheets: Cancel leading, Done trailing; the M3 contextual action bar is built from a close icon, a count title, actions and an overflow

What changes ​

  • Library: §14 HeaderTextAction retired (the wizard header's sm Button already is the pattern, §21.2); §3 Header gains the registry and H-2 to H-5; §17 H1 keeps its order rule; §16 P3 and P5 are superseded; §18.2 Header icon badge becomes the officials' pointer.
  • IA: IA-4 and ruling 4 ("Header text action (관리, 초대 코드, 완료)") are amended to H-4 and H-5; IA-5 stands.
  • Boards: flat-v2-patterns (HeaderTextAction specimen, its MediaBand pill variant), flat-v2-list-a (알림, 클럽 tab), flat-v2-detail (club hub, session, 프로필 edit), flat-v2-hub.
  • Code and canon: canon/components.md lines 121 to 122 rewritten; ClubJoinHeaderAction and the club-detail 관리 shortcut removed; a header-slot lint added; U-05 and U-09 get an addendum pointing here.
  • QA: the H-6 five-official test added to the usability checklist.

15. When does an ActionSheet appear, and when a Menu, a Dialog or a Sheet? ​

Owner: "When is action sheet rendered?"

What we have ​

  • Four overlays: ActionSheet (§14: bottom, title = the object's name, grouped Cells, destructive group last, cap 88%), Menu (§8: anchored under a header ⋯, 240 wide, at most five rows), Dialog (§8: centred, two buttons) and Sheet (ModalPanel: edit, filter, score, value pickers).
  • Rulings that already split them: D4 (a row ⋯ is always an ActionSheet; the Menu is for the header ⋯ only), H5 and forms D1 (a Choice ▾ opens a Sheet of radio Cells, never a Menu), §19.3 (the ActionSheet is the generic sheet for any object's actions, including a message's long-press and a comment's ⋯).
  • The anchored Menu is built on RN's native Modal because Tamagui's Popover "z-fights headers, flickers on mount, and drops touches on RN"; the Popover is lint-banned (canon/components.md line 123).
  • The owner's question shows the split is not legible: one component called an action sheet is used for many different triggers, and Apple uses the same name for something narrower.

Evidence ​

What each system calls these surfaces

JobApple HIGMaterial 3당근 Seed and Toss TDS
Commands behind a toolbar ⋯ or a long-pressPull-down button and menu; context menu ("a small number of frequently used actions"). pull-down, menus, contextMenu: "a temporary set of actions"; "Consider adapting menus into bottom sheets on small screens"; on large screens "a menu is often more appropriate than a bottom sheet" (menus)Seed Swipeable Menu Sheet (the older Menu Sheet is deprecated in its favour): a sheet-shaped component that offers choices related to the user's task ("사용자의 작업과 관련된 선택지를 제공하는 시트"), swipe-down to dismiss with a handle, an optional visible 닫기; its examples hold 3 to 5 items in one or two groups with a tone="critical" item last in a second group, and the page states no rule for it (Seed, older page); TDS Menu is an anchored dropdown (TDS)
A long list of actions on a phonenone; iOS action sheets are differentModal bottom sheet "as an alternative to inline menus or simple dialogs on mobile, especially when offering a long list of action items" (sheets); initial height capped at 50%TDS BottomSheet: shows extra detail without leaving the page, or prompts a specific action; tapping outside is recommended to cancel and close (TDS)
Clarifying choices after an intentional actionAction sheet: "Use an action sheet — not a menu — to provide choices related to an action… people expect a menu to appear when they choose to reveal it"; "Avoid letting an action sheet scroll"; no more than four buttons including Cancel; destructive buttons at the top (HIG)A basic dialog: at most two buttons, and it may hold a list of options (dialogs)TDS ConfirmDialog: two buttons, for confirmation before an important action runs ("주로 중요한 액션의 실행 전 확인이 필요할 때 사용해요") (TDS)
Confirm or informAlert: use sparingly; "Avoid displaying alerts for common, undoable actions"; up to three buttons (HIG)Dialog: "purposefully interruptive… used sparingly"; "a maximum of two actions"; use a snackbar for low and medium priority (M3, snackbar)Seed Alert Dialog: for when the user's confirmation is absolutely required ("사용자의 확인이 반드시 필요한 경우"); outside tap does not close it by default (Seed); TDS AlertDialog has one button
A scoped taskSheet: one at a time; swipe to dismiss; with unsaved changes "use an action sheet"; "For complex or prolonged user flows, consider alternatives to sheets" (HIG)Modal bottom sheet or full-screen dialog (compact only); discard confirmation is a basic dialogSeed and TDS BottomSheet with title, CTA, double CTA

Research

  • NN/g, bottom sheets: use for quick interactions, extra information, contextual controls and forks in the road; avoid for always-needed content, for lengthy or complex content, and for stacked sheets; give a visible Close, not only a grab handle; swipe-down can open the system panels instead; the claim that sheets improve reachability is "largely incorrect".
  • NN/g, confirmation dialogs: "Do not use confirmation dialogs for routine actions"; "go to great lengths to provide undo"; without identifying details "it's useless to ask users to confirm a request"; name the object and label buttons with the outcome.
  • NN/g, modals: appropriate for critical warnings, required information, complex workflows and low-commitment questions; avoid for non-essential content.

Observed. 네이버지도 shows a saved list as a bottom sheet with a grabber, labelled body pills 편집 and 공유, and a small ⋮ per row (Play fr 8); Apple Maps' place card is a sheet with a grabber, share and close at the top and labelled Call and Website pills (Apple newsroom); 배민's delivery tracker is a map with a bottom sheet (Play fr 8).

Where the sources disagree. HIG: a menu is what people expect when they tap "More", so a toolbar ⋯ should open a menu on iOS. M3 and the Korean systems: on a phone a bottom sheet is the better menu. We ship one codebase for iOS, Android and web, so M3's adaptive rule is the one that scales: the same list is a bottom sheet on compact windows and an anchored menu on wide ones. A second disagreement is where the destructive row goes: HIG puts destructive buttons at the top of an action sheet so they are noticed; Seed's examples put the critical item last, in its own group. We follow Seed and keep our current grammar (destructive group last, in danger ink, behind a gap), because every destructive row opens the S-1 Dialog: the order is not what protects the person, the confirmation is.

Recommendation ​

One rule: pick the surface by what the person is doing.

RuleThe person is…SurfaceWhy
S-1confirming a consequential actionDialog: centred, names the object and the consequence, at most two buttons (one acknowledgement only when it blocks). Undoable actions get a Toast with 되돌리기 instead.HIG alerts, NN/g confirmation, M3 dialogs and snackbars all say the same
S-2choosing a command for an object (from ⋯, gear, a row ⋯, a long-press, +)MenuSheet (today's ActionSheet): bottom, title = the object, groups of Cells 48, optional leading icon, destructive group last. At 600 pt and up the same rows render as the anchored Menu. On phones there is no anchored Menu.M3 adaptive rule; Seed's Swipeable Menu Sheet; 네이버지도's list sheet; one component for every object action; 48-high full-width rows suit the audience; no Popover workaround on phones
S-3choosing one value (Choice ▾, 정렬, month)Sheet of radio Cells (H5, D1: unchanged)a value picker is a form control, not a command
S-4entering or editing data (a field, a filter, a score)Sheet (Edit, Filter, ScoreEntry) with a footer pair; one sheet at a time; unsaved changes on dismiss ask a DialogHIG sheets; M3 full-screen dialog discard rule
S-5reading at length or running a multi-step flowPage or takeover: 약관 documents, wizards, searchNN/g: no sheets for lengthy content; HIG: alternatives for prolonged flows
S-6picking between consequences of an action just chosenMenuSheet with a question title, at most three rows plus 취소 (HIG: no more than four buttons including Cancel): 정기 일정 취소 → "이 일정만 / 이후 일정 모두". This is the one case Apple calls an action sheet.HIG action sheets; an M3 dialog caps the buttons at two
S-7being told what happenedToast (with 되돌리기 when reversible)M3 snackbar

Name: rename ActionSheet to MenuSheet. Seed names the same component Menu Sheet (now Swipeable Menu Sheet) and M3 uses a modal bottom sheet as a menu. Apple's "action sheet" is S-6 only, so the old name stays correct for one of its uses and misleads for the rest, which is what the owner's question found.

Trigger to surface, from our app

TriggerSurfaceRule
관리 gear on the club hub or the session pageMenuSheet (운영 group, then destructive group)S-2
⋯ on a club, session, venue or profileMenuSheet (three or more rows, H-3)S-2
⋯ on a post, a comment, a person rowMenuSheet (D4)S-2
long-press on a messageMenuSheet with the Reactions quick row firstS-2
+ on the 클럽 tabMenuSheet: 클럽 만들기 · 초대 코드로 가입 · 클럽 찾기S-2
일정 삭제, 일정 취소, 클럽 나가기, 로그아웃 (row of a MenuSheet)Dialog naming the object ("10월 14일 복식 일정을 취소할까요?")S-1
참석 취소 (the CTA band)Dialog (D2)S-1
정기 일정 취소MenuSheet with a question titleS-6
10월 ▾, 정렬 ▾Sheet of radio CellsS-3
필터FilterSheetS-4
a field's pencilEdit Sheet; dismissing with changes asks a DialogS-4
점수 입력ScoreEntry SheetS-4
이용약관 보기pushed document page (audit §22.2)S-5
입금 확인 saved, 참석 확정ToastS-7

Do not use a MenuSheet or Menu for one or two commands (HIG: "consider using alternative components… buttons"), and do not ask "Are you sure?" for anything a Toast with 되돌리기 can reverse.

What changes ​

  • Library: §8 Menu becomes the 600 pt and wider presentation of the MenuSheet; §14 ActionSheet is renamed and gets the S-2 and S-6 scope; §18.1 D4 now reads "a row ⋯ or a header ⋯ opens the MenuSheet on phones"; §17 H1 keeps ⋯ rightmost.
  • Code: HeaderActionsMenu picks its presentation from the existing window-size breakpoints (a sheet below 600 pt, the anchored dropdown above); canon line 123 is rewritten; the anchored dropdown's RN-Modal workaround is then needed only on wide windows.
  • Boards: the Menu and ActionSheet specimens on flat-v2-patterns; every ⋯ frame on flat-v2-detail and flat-v2-list-a is drawn as the sheet.

17. What goes on a photo or map band ​

Owner: "As for the mediaband, make sure you know which actions are rendered on the photo as icons in accordance with best practices."

What we have ​

  • §14 MediaBand: photo or map, full-bleed 240 including the status bar; top scrim ink α0.35 → 0 over 100; the header is transparent with white 24 glyphs on 36 ink α0.4 circles in 44 targets; past 140 of scroll the header turns white in 150 ms, glyphs ink, title fades in. Map variant: no Tag, a tap opens 장소 상세 (§19.2). Album overlay: neutral count Tag "1 / 12" bottom-right plus pager dots bottom-centre (§18.2). P5 puts a white text pill on the band for 관리.
  • Used by the club hub and preview, venues, and session detail when the venue has a map (IA-10, D3). Current headers: club hub [관리][⋯], session [관리][⋯] for hosts and [북마크][⋯] for everyone else (D1).

Evidence ​

What peers put on a photo or map header

App and screenOn the photo, left → rightLookOn scrollSource
Airbnb Android listing (tablet layout)← · share, ♡; photo counter "1/49" bottom-rightlight translucent circles, dark glyphs; counter on a dark translucent rounded rectanglenot shownPlay fr 10
Airbnb listing, mobile web (this lane's render)← · share, ♡; "1 / 28" bottom-rightcircles about 40 pt, light, dark glyphs; the content sheet has a 24 top radius over the photocontrols scroll away with the photo; no sticky bar at 300 or 600 pxweb render
Airbnb result tiles (Android)"Guest favorite" tag top-left; ♡ top-right of the tile photowhite heart on the photon/aPlay fr 3
Meetup event← · title "Event" · share + bookmark in one capsule (above the photo); event cards: share, bookmark on the photo cornerglass circle and capsule, dark glyphsnot shownMeetup fr 2, 4
Eventbrite event← · share, ♡ (header zone, above the photo); status Tag on the photo; sticky bottom CTAplain glyphs on whiteCTA stays pinnedEventbrite fr 2
Luma event, community← · share (cover); ← · search + ⋯ in one capsule (dark banner)translucent circle and capsulenot shownLuma fr 3, 4
Playtomic club← · share (plain white glyphs on the photo); ♡ sits in the body beside the club nameno containernot shownPlaytomic fr 5
Strava route (iOS)‹ · save (bookmark) over the map; the activity sits in a bottom sheet with a grabberdark translucent circles, white glyphsnot shownStrava fr 9
Strava workout (iOS)‹ · ⋯ over the figuredark translucent circlesnot shownStrava fr 4
당근 job post (Android)‹ · share, report on a white bar above the photo; page dots on the photo; sticky bottom ♡ · 전화문의 · 지원하기plain outlined glyphs, no containernot shownPlay fr 6
쿠팡 product page (Android)‹ only in the header; gift and share icons sit under the photo at the right, above the ratingplain glyphsnot shownPlay fr 3
네이버 카페 cafe page← circle · chat, search, ≡ circles (three on the right)glass circles on the covernot shownNaver Cafe fr 3
카카오맵 theme map← · share, map circles; pill "9개 모두 저장" and page dots at the bottomsmoke-grey translucent circles about 44 pt, white glyphsnot shownPlay fr 8
네이버 플레이스 (web)none on the photo: header on white (← · ☆, avatar); the photo strip below shows the next photo peeking; labelled pills 길찾기 · 공유 · 전화 · 알림받기 sit under the strippills in light blueheader staticweb render
카카오맵 place (web)none on the photo: four icon circles (call, save, share, pin) plus labelled pills 출발 · 도착 under the titlefilled blue pillsn/aweb render
Apple Maps place card (iOS 26)card header: share · title · × close; labelled pills Call, Website; icon row + ☆, thumbs-up, ⋯ and a labelled directions pillsystem glasssheet with grabberApple newsroom
Booking hotelsolid brand header (← and title) above the gallery; result cards keep ♡ on the text side of the cardsolidn/aBooking fr 2, 3
당근 (Seed design system, AppScreen)AppBar tone="transparent" with a gradient from the top of the screen including the status bargradient scrim, gradient=false hides it"Intersection Observer" switches the tone from transparent to layer when the image leaves the viewportSeed

Counts from the table: headers over a photo or map carry one to three trailing icons, most often two (Airbnb, 카카오맵, Meetup, Eventbrite, Luma community) or one (Luma event, Playtomic, Strava route); 네이버 카페 shows three. Two Korean commerce pages keep the photo clean: 당근's detail page puts share and report on a white bar above the photo, and 쿠팡's header holds only ‹ and moves share and gift under the photo. Where share and save both appear on a photo, share comes first (Airbnb, Meetup, Eventbrite); 소모임's plain white group header, which is not over a photo, reverses it and shows ♡, share, ⋯ (fr 7, 8). A ⋯ or ≡ is always last (소모임, Luma, 네이버 카페, Strava). Place-specific actions (directions, call, website) are labelled and in the body or the card, never on the photo (네이버 플레이스, 카카오맵, Apple Maps). 배민's store page is not in its store frames, so it is not counted.

Platform and research

  • M3 app bars: over content the bar may be transparent "on scroll" if icon buttons keep a container fill; use narrow icon buttons for Back. M3 icon buttons: "Use icons with a background to make them easy to see on any surface"; default container 40 dp.
  • HIG toolbars: "Prefer system-provided symbols without borders… the section provides a visible container"; group items "logically" with at most about three groups. iOS 26 apps (KakaoTalk, Meetup, Luma above) draw two glyphs in one capsule, consistent with that guidance.
  • Save on list thumbnails is split: Airbnb's 2020 test moved the heart off the thumbnail (GoodUI: no metrics, post-hoc explanations), yet the 2026 Android frames show it back on the photo; Booking, Eventbrite, 플랩풋볼 and 당근 keep it beside the text.
  • Contrast (C). White glyph on ink α0.4 over a pure white photo with our scrim: 3.15:1 at the circle's centre (y 72) and 2.81:1 at its lower edge (y 90). WCAG 1.4.11 needs 3:1 for icons (W3C). At α0.5 the worst case is 3.8:1; at α0.55, 4.5:1. White 15/22·600 text (the P5 pill) needs 4.5:1 (W3C), so it needs α0.6.

Recommendation ​

RuleStatement
M-1On a photo or map: ‹ at the left, at most two registry icons at the right, nothing else. No text, no pill, no Tag except the photo counter, no primary or place-specific action.
M-2Share first, then save; ⋯ only if it holds three rows. Share is promoted on every photo page. Order is most-used left, ⋯ right (H-2).
M-3Circles 40 in 44 targets, gap 8, ink α0.5 (was 36 and α0.4), white 24 glyphs, scrim unchanged. Under Reduce Transparency use α0.7. Keep separate circles (our grammar); a shared capsule is the iOS 26 alternative and is optional.
M-4Scroll behaviour stays as specified: transparent over the photo; after the photo's last 100 pt passes under the header it turns white in 150 ms, circles lose their fill, glyphs turn ink, the title fades in. This is what Seed documents and M3 recommends.
M-5Place actions are labelled and in the body. Venue: an action row 길찾기 · 공유 · 전화 under the title (Naver, Kakao, Apple). Club and session: the CTA band carries 가입 and 참석.
M-6Album overlay: the count Tag "1 / 12" only; drop the pager dots. NN/g: dots are "generally weak signifiers" (mobile carousels) and "a particularly poor cue on mobile devices" (carousel usability); Airbnb uses a counter alone.
M-7No save icon on list thumbnails. The row's one trailing element holds state or count (D6); the photo stays clean.

Per page

PageOn the photo, right (most used first)Not on the photo, and where it goes
Club hub, member[공유] [⋯ 신고 · 나가기 · (클럽 알림)]글쓰기 FAB; the 가입 state lives in the pane
Club hub, official[공유] [gear 관리 + badge]클럽 나가기 moves to the 관리 sheet's last group; tool Cells at the end of each pane (IA-7); 할 일 section
Club preview (non-member)[공유]가입 신청 in the CTA band with the dues helper; 신고 in the page's closing Cell
Venue[저장] [⋯ 지도 앱에서 열기 · 정보 제보 · 신고]action row 길찾기 · 공유 · 전화 under the title (labelled)
Session with a map bandmember [공유] [저장]; host or official [공유] [gear 관리 + badge]단톡방 열기, 호스트에게 문의, 신고 become 정보 Cells (labelled, reachable without a ⋯); CTA band carries 참석

What changes ​

  • Library: §14 MediaBand (circle 40, α0.5, M-1 to M-3), §18.2 album overlay (no dots), §16 P5 retired (with the text action), D1 reworded ("[공유][저장] for members, [공유][관리] for hosts, no ⋯"), D6 unchanged.
  • Boards: flat-v2-patterns MediaBand specimens and VARIANTS; flat-v2-detail session, club, venue frames (header glyphs and the moved Cells); flat-v2-hub club hub.
  • Code: SessionDetailHeaderRight and the club hub header lose their ⋯ for these roles; 정보 gains the three Cells.

18. Message bubbles, the composer and the keyboard ​

Owner: "let's make sure we properly configure spacing between messages and the keyboard actions. The same goes for helper texts and actions."

What we have ​

§14 MessageBubble + Composer: bubble max 264, pad 8 12, r18 with the sender-side corner 6 on the last bubble of a run, 15/22; mine ink with white text, theirs gray100; avatar 32 and a name 13/18·600 on the first bubble of a group run; runs within a minute stack at 4, new runs at 12; time 11/14·500 beside the last bubble; date and system lines centred 13/18·500 with 16 around. Composer: min 56 + home inset, attach IconButton 24 in 44, field gray100 r20 min 40 pad 8 16 growing to five lines, send a 36 ball circle in a 44 target; it rides the keyboard (KeyboardStickyView). §19.3 adds the reply-target row (44, one-line excerpt, × target 44); §16 adds the sending clock and the failed state ("전송 실패" plus a retry text action).

Evidence ​

No messaging app publishes a spacing spec, so the evidence is: open-source constants (Signal-iOS), one published design-system token set (Innovaccer), measurements of KakaoTalk's own App Store frame (±2 pt), and what the other apps visibly do.

AttributeSignal-iOS source (style, toolbar, quote)Innovaccer tokens (usage)KakaoTalk, measured from its frame (fr 1)Others observedOurs now
Bubble paddinghorizontal 12; vertical computed from the font, about 7 at 17 pt (C)12 × 8one-line bubble 34 tallAirbnb, WhatsApp, LINE: similar pill proportions8 × 12 (38 tall)
Gap inside a runcompactMessageSpacing 2not statednot measurable (frame has no same-sender pair)iMessage and WhatsApp stack tightly4
Gap between runsdefaultMessageSpacing 12not statedbubble to the next sender's bubble 35 including the name label—12
Sender labelnone (name sits in the bubble)—label 11 to 12 pt; 19 above its ink, 7 between label and bubble; avatar 34 aligned to the label's top, 6 to the bubbleiMessage group: a small grey name above the first bubble (Apple newsroom); Airbnb: the sender's name, a "Host" label and the time above the first bubble (Play fr 6)18 label + 4
System and date linessystemMessageSpacing 20——LINE: a centred "Today" chip (fr 1); WhatsApp: a centred notice pill (fr 2)16
Max bubble width at 390contentWidth − 24 − 8 − 12 = 314 (1:1); minus avatar 28 + 8 = 282 (group)not stated——264
Side gutters16 (1:1) or 12 (group) leading, 16 trailing—bubbles and avatar 7 to 10 from the screen edge; composer 10—rail 20
Timein the bubble footertimestamp on the first message of a group (under 5 minutes apart); metadata 4 from the bubbleoutside the bubble, bottom-aligned, 4.5 from its edge, about 11 ptWhatsApp: inside the bubble bottom-right with ticks; LINE: beside; Slack and Airbnb: next to the name11/14, beside, last bubble only
Delivery and readper-message statusstatus shown for the last message of a threadunread count (not in the frame)iMessage: "Read" or "Delivered" under the last sent message (Apple); Luma: "Delivered" under the last sent bubble (fr 5); WhatsApp: ticksnot specified
Composer height and fieldtoolbar 56, text box 40, radius 20 (height ÷ 2), min text view 35, max 98 (about four lines), buttons 40 to 48 wide—one rounded container 47 tall, side margin 10, inner circles 34controls on the bar, icons inside the field counted: LINE five, WhatsApp four, KakaoTalk three, Luma three, Slack two56 / 40 / r20 / five lines
Reply previewwrapper margins 6, preview radius 12, author footnote semibold, text up to two lines, cancel 24———44 row, one line

Notes on the table:

  • Our spec already matches the closest open reference where it is most specific: composer 56, field 40 with radius 20, 12 between runs, text inset 12. Applying Signal's width formula to our 350 column gives 306 (1:1) and 266 (group, avatar 32 + 8) (C), so 264 is right for groups and 42 narrow for 1:1.
  • Between different senders the spec gives 12 + 18 + 4 = 34, against 35 measured in KakaoTalk.
  • Airbnb's own thread draws the sent bubble in dark ink and the received bubble in light grey (Play fr 6), the same choice as ours.
  • Keyboard: Apple says to use the keyboard layout guide so the keyboard feels integrated and to place custom controls above it "thoughtfully" (HIG virtual keyboards). The repo's own note is that Android is pan and KeyboardController is activated per screen (addendum B9.4). The library does not say what happens to the home inset when the keyboard is up; left implicit, it leaves a 34 pt gap between composer and keyboard.
  • Attachments: KakaoTalk, LINE, WhatsApp and Slack all lead with a "+" (what opens behind it is not visible in the store frames). For this audience a labelled list beats an icon-only menu (Leung, Wu, §14).
  • No store frame shows a failed send; ours (a named state with a retry action) is more explicit than a bare marker and only lacks a second action (삭제).

Recommendation ​

All values in pt; the column is 350 at 390 with the 20 rail.

Thread

ItemValue
Bubblepad 8 × 12, r18, sender-side corner 6 on the last bubble of a run, 15/22 (unchanged)
Max width1:1 306; group 266 (Signal's formula on our column; was 264 for both)
Inside a run (same sender, same minute)2 (was 4); the corner 6 marks the run's end
Between runs12 (unchanged)
New sender in a group12 above the label, label 13/18·600 secondary (18), 4 to the bubble: 34 from the previous bubble
Avatar32, top aligned with the label's top, 8 to the bubble
Time11/14·500 secondary, 4 from the bubble edge, bottom-aligned with the last line, last bubble of a run only
Date and system linescentred 13/18·500 secondary, 20 above and below (was 16)
Thread top and bottomfirst item 12 below the header; 12 between the last bubble and the composer's top edge
Delivery state (if the product shows it)"읽음" or "전송됨" 11/14·500 secondary, right-aligned 4 under the last sent bubble of a 1:1 thread; none in groups

Composer

ItemValue
Barmin 56 = 8 + field 40 + 8, plus the home inset only when the keyboard is hidden; edge hairline on top while content scrolls under it
AttachIconButton, 24 glyph on the rail, 44 target (bleeds 12 into the margin); opens a MenuSheet with labelled rows (사진 · 카메라)
Fieldgray100, r20, min 40, 15/22, pad 9 × 16, gaps of 8 to attach and send; grows to five lines (128) then scrolls
Send36 ball circle with a 20 ink arrow, 44 target, right edge on the rail; always visible, 0.5 when empty (a fixed target; WhatsApp and KakaoTalk swap controls, which moves the target)
Reply-target row44 tall, inside the composer above the field; label "OOO님에게 답글" 13/18·600, excerpt 13/18·400 one line with an ellipsis, × 20 in a 44 target at the right; 8 between the row and the field; appears with focus over 250 ms
Keyboardcomposer in a KeyboardStickyView, flush on the keyboard (gap 0); home inset 0 while the keyboard is up; thread bottom inset = composer height + 12; on focus the thread scrolls to the newest message

Helper text and actions around the composer

ItemValue
Failed message"전송 실패" 11/14·600 danger, then 다시 보내기 and 삭제 as 13/18·600 text actions (44 targets by slop), right-aligned 4 under the bubble, 16 between them
Sending12 clock before the time; bubble at 0.6
New messages while scrolled up"새 메시지 3개" tonal pill, 36 tall, centred, 12 above the composer; shown when the thread is more than a screen from the bottom; a tap scrolls down
Offlinethe 350 × 48 strip under the header; the composer stays enabled and queued messages show "보내는 중"
System lines ("OOO님이 입장했어요")centred 13/18·500 secondary, 20 around, never a bubble

What changes ​

  • Library §14 MessageBubble + Composer: within-run 4 → 2; system lines 16 → 20; max width split 306 / 266; thread-bottom gap 12; home inset 0 under the keyboard; attach opens a labelled MenuSheet; failed state gains 삭제; delivery line specified or explicitly omitted.
  • Board: the MessageBubble specimen and the DM frames on flat-v2-detail (spacing rulers, keyboard-up frame, failed and jump-pill frames).
  • Code: the DM compose bar and thread (packages/features/messaging/src/dm-thread/) read these values from one constants file, not per-component literals.

19. LiveScore: controls that explain themselves ​

Owner: "the controls for adjusting the scores aren't clear enough. Make them more intuitive."

What we have ​

  • §14 LiveScore: an ink Block 350 × 144 with two team rows (names 15/22·600 white α0.85), set scores 24/32·700 in 32 columns, the current game points (0 / 15 / 30 / 40 / AD) in ball, a 6 ball dot before the server; host controls below: two lg tonal Buttons "팀 A 포인트" and "팀 B 포인트" plus an undo IconButton; participants see it read-only. §16 P4 says numerals are instant; the §14 row says "150 ms numeral cross-fade" (a conflict, listed in the audit).
  • What ships today is different: live scoring stores games in the current set only (update_live_match_score; match-formats.md "Live-scoring's deliberate ship-now scope"), and the live card opens a ScoreEditSheet of ±1 steppers (6 to 4 is 10 taps, IA flow 7). The LiveScore block therefore designs a point-level recorder the data model does not yet have; the labels "포인트" and the 0/15/30/40 display need the engine decision first.
  • Problems with the current design: the team is named by an abstract letter, the buttons sit away from the numbers they change, the undo is an unlabelled icon, the server is a 6 px colour-only dot, and nothing says what happens at a game, set or match boundary.

Evidence ​

How manual scorers take a point. (Descriptions are from the stores' own text; frames from the store listings. Sizes read from frames are approximate: the phone's inner width is estimated, ±10%.)

AppA point is added byUndoServerBoundariesSource
MatchTrack (iOS)tapping the winner's own tile; two side-by-side tiles each about half the width and 1.4 × as tall as wide (about 175 × 245 pt) with the name and a numeral; "hit the game score of the player that won the point"full-width labelled Undo (about 230 × 75 pt)small green dot beside the name (colour only)Fault, Let, Ace buttons (about 110 × 75) under the tilesfr 1, text
Tennis Scorecard (iOS, Watch)− and + circles on the team's own full-width coloured panel (about 300 × 258 pt, name, 76 pt numeral); the circles are about 33 ptthe − circle; Edit Scoreplayer glyph under the numeralan End of Game 7 sheet: Change Ends, Serving Next, Next Game, Edit Score; the store text promises "server switches to side changes"fr 1, 3
테니스점수판 (KR, 2026)swipe left = 내 점수, swipe right = 상대 점수long-press ("롱탭 수정")ball icon at the server's side of the name line코트 체인지 alert, serve order, tie-break tint and label; "한국 동호인 환경에 최적화", games without sets; dark, "야외 코트에서도 시인성이 뛰어난 고대비"fr 1 to 5
Ralli (KR)Apple Watch: rotate the Digital Crown up = 내 점수, down = 상대 점수; phone: two colour halves 나 / 상대취소 pill (tap)—formats 4, 5 or 6 games, No-AD and No-Tiebreak toggles; Live Activityfr 1, 2
민턴보드 (KR, badminton)tap the board = +1; numerals fill the screen−1점 corner label; reset asks a dialog—auto winner, 21 or 25 preset, deuce and cap handled, colour change near match point, 코트 교체 button, screen kept awake, landscapefr 1 to 4, text
Side Out (pickleball)swipe up or downundo and redo by swipegreen indicator plus the service box (1 or 2)three-number score "4-4-1", voice announcements "4-2-1"fr 1, 5
DataTennis"Simple Mode — tap the point winner for fast scorekeeping""Undo — correct input mistakes instantly"—optional detail per pointtext
Tennis Math (Android)two tall "Point won" tiles, one under each player's name; then Ace, Fault, Winner, Forced or Unforced error tiles"advanced undo/redo", "fix score while tracking"ball icon beside the server's namescore log line per pointPlay fr 7 to 9
Smashpoint, Tennis Umpire App, Tennis Score Keeper by WIDlarge Ace, Winner, Error buttons; a serve toggle; "one tap scores a point" on the Watchfull-width Undo (Smashpoint), Undo in the top bar (Umpire), watch undoserve toggle chipschoose depth first ("Points", "Serve & Points", "Point Outcomes")Smashpoint fr 5, Umpire fr 2, WID text

Reading: of the eight apps that state how a point is added, five tap the team's own area (MatchTrack, Tennis Scorecard, 민턴보드, DataTennis, Tennis Math) and three map a gesture direction to a team (테니스점수판 and Side Out by swipe, Ralli's watch by crown); the three gesture apps are built for one-handed or wrist use. None puts the two teams' scoring in one shared row of "+1" buttons. The nearest is Tennis Umpire's rally screen: two columns of identical outcome buttons (Net, Winner, Unforced Error, Point Won) whose owners the frame does not label (fr 3). Undo is a labelled button in five apps (MatchTrack, Ralli, Smashpoint, Tennis Umpire, 민턴보드's "−1점"), a gesture in two (테니스점수판's long-press; Side Out's swipe, whose frame also shows a small "Undo" label), a per-team − control in Tennis Scorecard, and every app offers one. The server is shown with a glyph or a word in five apps (Tennis Scorecard, 테니스점수판, Tennis Math, Racketly's "SERVING" (fr 1), 피클볼 점수's "Server 2 · Left" (fr 1)) and by a plain green dot in two (MatchTrack; Side Out, which adds the service-box number). SwingVision is not a model for manual entry: it scores automatically from a camera (store text).

Rules that define the transitions. ITF Rules of Tennis 2026: points Love, 15, 30, 40, then Deuce and Advantage (Rule 5); a tie-break counts 0, 1, 2… to seven with a two-point margin; the first server serves one point, then each side serves two; players change ends at the end of the first, third and every later odd game and after every six tie-break points (Rule 10); Appendix VI adds the No-Ad deciding point (the receiver chooses the side), short sets to four games, and a 10-point match tie-break in place of the final set. USA Pickleball 2026 rulebook 6.B.2: in doubles the score is called as three numbers (serving team, receiving team, server number), starting "zero – zero – two"; points are won only by the serving team in side-out scoring, games are to 11 win by 2 (summary). BWF: rally scoring to 21 today (secondary sources); a search summary of BWF's April 2026 news item reports an approved 3×15 system from 4 January 2027, which this lane could not verify (the page returned 403), so the target must be configuration, not a constant. No public documentation of Grand Slam or ITF umpire tablets was found.

Standards and research on target size and outdoor use

  • HIG buttons: hit region at least 44 × 44 pt. M3 switch spec and the M3 menu rules use 48 dp targets. WCAG 2.5.8: 24 × 24 CSS px minimum, to help people with hand tremor and people who use one hand.
  • NN/g: a 1 cm × 1 cm minimum (Parhi, Karlson and Bederson 2006), fingertips 1.6 to 2 cm wide, thumb impact 2.5 cm, and it recommends bigger targets for users in motion and for seniors. At 460 ppi, 1 cm is about 60 pt, so 44 pt (7.3 mm) is below it (C).
  • Hoober: 49% of 780 observed touch users held the phone one-handed (2013; the author's 2017 note says to ignore his reach diagrams).
  • HIG haptics: use notification, impact and selection haptics "to complement" visuals, keep them short, make them optional. HIG undo and redo: let people undo repeatedly, describe what will be undone, show the result; add dedicated undo buttons only when necessary and then use the standard symbol in a toolbar. (Our audience and five of the scorers above argue for a word on the button; the standard glyph can sit inside it.) NN/g: do not confirm routine actions; provide undo.
  • Korean club context: Ralli offers 4, 5 or 6 games, No-AD and No-Tiebreak toggles, 테니스점수판 scores "without sets", and the repo's format registry already has SET1-S:6/TB7 style codes (match-formats.md).

Recommendation ​

RuleStatement
L-1Two surfaces. The page Block stays a read-only glance for everyone. The host's controls move into a full-screen 점수 기록 mode opened from the Block (it carries the eyebrow "점수 기록 ›" and is pressable for the host only). Every point-level scorer in the evidence is a dedicated screen; a 144-high block cannot hold targets of 1 cm and a labelled undo, and a match board with eight courts cannot hold eight sets of buttons.
L-2The team's own panel is the control. Two stacked panels, full width (350), each filling half of the remaining height: at least 160 tall (26 mm), about 245 on an 844-high phone (58 mm wide), ink #15181A r16 pad 20, 12 apart; the whole panel is one target. Content: the team's names 17/24·600 white (two lines, never cut), the current game point 72/80·700 tabular, and the server mark. No "+" glyph is needed, but a caption under the score strip says once "포인트를 딴 팀을 눌러요" until the first tap (hidden after three matches).
L-3Name the team with its real names, not A and B. Panel names read "김민준 · 박서준". The spoken name is "김민준, 박서준 팀, 득점 기록, 지금 15". The word for the action is 득점, not "포인트 +1" (a tap moves 15 to 30, it does not add 1).
L-4Undo is a labelled button, 되돌리기, lg tonal (52 tall, 140 wide, the standard undo glyph 20 before the word) at the bottom left, 12 below the panels and apart from them so a fast tap on a panel never lands on it. Beside it a 13/18 secondary line says what it reverts: "마지막: 김민준 · 박서준 득점 → 30". Each press reverts one point, without limit within the match. It is disabled (0.5) when there is nothing to undo.
L-5Show the server as a glyph and a word. A 16 ball glyph and "서브" 13/18·600 on the serving panel's name line; for pickleball add the server number and side ("서버 2 · 왼쪽"). The 6 px dot is retired.
L-6Feedback. Haptic impact (light) on every point; notification (success) at a game won; both optional in settings. A 150 ms 2 px ball ring on the scored panel confirms which team got it; the numeral itself changes instantly (P4). A polite live region announces "김민준, 박서준 팀 15 대 0".
L-7Boundaries do not block, except the last. Game won: the panels settle and the score strip updates. 코트 체인지 (after odd games, after every six tie-break points) and 서브 교대 appear as a non-blocking banner above the panels for 3 s, with no extra haptic (ITF Rule 10). Tie-break: the panel eyebrow reads "타이브레이크" and the numerals count 0, 1, 2. No-Ad deuce: eyebrow "결승 포인트". Match decided: a Dialog ("경기를 끝낼까요?", the final score, [수정] [경기 종료]) because finishing changes ratings and the existing 동의 flow follows.
L-8Outdoor and one-handed. Keep the screen awake while recording (민턴보드 does); high-contrast ink with white numerals (about 18:1, C); no thin strokes or colour-only team identity (names and position carry it); portrait with panels reachable by the thumb; the header holds only × and ⋯ (코트 체인지 · 서브 바꾸기 · 점수 직접 수정 · 경기 종료).
L-9Read-only participant view. The Block and the Live row only; under the Block a 13/18 secondary line "호스트가 점수를 기록하고 있어요". Controls are not drawn, not disabled.
L-10The format drives the rules. Games to N, No-Ad, tie-break length and match tie-breaks come from the match-format registry, not from constants (BWF's 21 may become 15; Korean club formats are games, not sets).

If the recorder mode is deferred (minimum change): make the two team rows of the Block the buttons (each 350 × 72 inside a Block of about 190), remove the two lg Buttons, and put a labelled 되돌리기 text button under the Block. This already answers the owner's complaint; it does not meet the 1 cm target on its own.

What changes ​

  • Library §14 LiveScore split into LiveScore (read-only Block) and ScoreRecorder (new); §16 P4 and the §14 row reconciled to "numerals instant, ring flash 150 ms"; the 6 px serve dot retired.
  • Product decision first: points or games. Today the engine stores games per set; a point recorder needs point state (0/15/30/40/AD, serve, tie-break counter) in update_live_match_score or a new RPC, and the undo needs the point history. If points stay out of scope, the same layout works at game level with the word 게임 for 득점, the panels showing games, and the 0 / 15 / 30 / 40 display dropped.
  • Dependencies: screen-awake needs expo-keep-awake (a native module; check it is in the current binary before promising an OTA) and haptics follow the existing outcome-only haptics rule.
  • Boards: a ScoreRecorder frame set (portrait, tie-break, No-Ad, banner, match-end Dialog, 130% and 200% text) and the revised LiveScore Block on flat-v2-patterns and flat-v2-detail (경기 보드, 스코어카드).

8. MediaRow for sessions: the court leads ​

Owner: "I think for sessions, we should make the court title the main information, not the hours."

What we have ​

  • §5 MediaRow (80): thumb 56 r8; L1 17/24·600 ink = the start time (tabular); L2 15/22·400 secondary = the venue; trailing: a count or one Tag. The earlier list spec's compact 홈 row (72) is the same with a 48 tile, time 16/24·600 over venue 13/18·500 secondary, and its discovery row (96) adds an L3 복식 · NTRP 3.0–4.0 (list-surfaces-spec §2). Lane I of that spec chose time first because, of its four day-grouped or date-filtered peers, "three lead the text with time/date", and "venue names repeat down a day, times never do" (lane I item 5); §4.3 there records the place-first order as a stated fallback, "owner prefers place-first", with every other rule unchanged.
  • A naming note: sessionTitle() returns the format and event type ("복식", "복식 번개"), not the venue (packages/app/src/presentation/utils/session-title.ts). The venue is the place title the list card and the detail hero already lead with (canon/sessions.md: "place title + ONE titleBadge"). The row's L1 is therefore the venue field and sessionTitle() belongs on L3.

Evidence ​

What leads a row in event, pickup and calendar lists (store frames; heaviest text and first line)

App and listOrder, top to bottomHeaviest textHow the date or time is shownSource
플랩풋볼 home (day-filtered)time (bold, blue when 확정임박) → venue (bold, slightly larger) → level, 6vs6, seatsco-equal, time firstday strip above; time is line 1fr 2
플랩풋볼 map sheetbold time column "19:00" beside bold "더베이스 · 5구장" → statusco-equaltime column at the leftfr 3
소모임 정모 (day strip)photo with time overlaid ("오늘 오후 6:30") → title → place and attendees "15명 참석중(15/16)"titleoverlay on the photo; day strip abovefr 4
테니스프렌즈 매치small venue label → venue title (bold) → "4/9(목) 11:00~13:00" → tags; 마감 Tag and 1/3 at the rightvenue titleone plain line under the titlefr 4
문토kicker → title → "소셜링 · 성동구 · 내일(토) 오후 1:00" → host and counttitleinside the meta linefr 4
밴드 일정date card header "8월 18일 (화)" → title → "Today 오전 8:00 - 오후 7:00" → place → Tagtitlecard header, then a coloured linefr 4
Meetupphoto → title → "Tue, Jun 10, 2025 · 11:30 AM EDT · Central Park" (grey) → host → "107 going"titleone grey meta linefr 2
Luma Discover and communityhost label → title → clock glyph and "Today, 8:00 PM"; community list: day headers "Tomorrow / Friday" → title → a clock glyph and "6:30 PM" with the addresstitleglyph plus time under the title; day headersfr 2, 3
Eventbritetitle (bold, two lines) → "Fri, Aug 1 · 7pm · East of Eden Club, San Francisco…" (grey) → "From $39"titleone grey meta linefr 1
Playtomic classes and tournamentstitle ("Private class") → "Thursday 14 May - 20:00" (grey) → sport and duration → coach → club and "Booked"; a tournament card puts the eyebrow "THU · 20 JAN · 20:00" above its titletitleone grey line under the title, or an eyebrowfr 2
TeamSnap game"vs. Net Knights" → "Saturday, May 17, 2025 / 11:00 AM – 1:00 PM"titlelines under the titlefr 2
Google Calendar agendadate in the left rail; event chip with title and the time under ittitleleft date railfr 1
네이버 캘린더 day listtime rail at the left ("오후 2:00 / 오후 3:00") → bold title → placetitle (time in a rail)a left railfr 3

Counts: 11 of 13 lists lead with the title or venue; the two exceptions are both 플랩풋볼, the closest category peer, whose first line is the time and whose second line (the venue) is equally bold. Time is not the heaviest text anywhere else. Where the time does not lead it sits on the line directly under the title (테니스프렌즈, 문토, 밴드, Meetup, Luma, Eventbrite, Playtomic's class card, TeamSnap, Google Calendar), as a small eyebrow above the title (Playtomic's tournament card), in a left time rail (네이버 캘린더) or as a photo overlay (소모임). The date itself is carried by a day strip, a day header, a date rail or a card header, so a row repeats only the time.

Lane I counted 플랩풋볼, Greenlight and 밴드 as time or date led. Re-read by weight: 플랩풋볼 co-leads (time first, venue equally bold) and 밴드's card puts the date in a header above a bold title; the generic event apps (Meetup, Luma, Eventbrite) and every calendar lead with the title.

Related evidence: NN/g found users "typically see about 2 words for most list items" (80 participants, 20 links: first 2 words), so the left edge of line 1 must carry the distinguishing words: a venue name does that in a discovery list; where every row is at the same court it does not. Peers handle that case by naming the venue once: Playtomic's club page has the club as its title and lists a day strip, duration chips and time chips beneath (fr 5). 당근's 모임 tab shows no event rows in its store frames.

Recommendation ​

One hierarchy for every session list; only the day prefix and the trailing element change.

LineContentType
L1venue or court name (one line, ellipsis allowed: places may crop, names may not)17/24·600 ink (16/24 in the compact row)
L2time range, tabular, 19:00–21:00 through the one range formatter; the day word ("오늘", "내일", "토요일") is prefixed only when the list is not grouped by day15/22·500 ink $text (13/18·500 compact); no longer secondary
L3discovery only: 복식 · NTRP 3.0–4.0 (sessionTitle() and the level) as MetaSegments13/18·500 secondary
Trailing6/8 15/22·700 tabular, or one Tag (live, 참석 / 예비 / 호스트, 마감 임박); no bookmarkunchanged
ContextRow
번개 찾기 (discovery, by day)thumb stays 56 (C4); L1 venue, L2 내일 19:00–21:00 when ungrouped or 19:00–21:00 under a day header, L3 format and level; the row grows from 80 to 96 with L3
내 경기 (my schedule)day headers; L1 venue, L2 time; no L3 (the person already joined); trailing state Tag
Club 일정day headers; L1 venue, L2 time; L3 only for 번개. Refinement for lane I's repeated-venue point: when every row is at the same court (a one-court club, or a venue page's session list) the court is named once in the list head and L1 becomes the time range 17/24·600, L2 sessionTitle() and level 15/22·500 secondary, no thumb (a text row of 68). If the owner prefers one grammar, keep the venue on L1 and accept the repeat
홈 under the day Blockcompact: tile 48; L1 venue 16/24·600, L2 time 13/18·500 ink; trailing 6/8; row 72. The Block above already states the next day

Why venue first and not the time: (1) 11 of 13 peers; (2) the thumb is the venue's own photo or map tile, so the name beside it completes one identity (the list spec's "photos carry identity"); (3) the detail hero is already venue-led, so list and hero agree; (4) the day header carries the date. The cost: a column of times no longer aligns down the left edge. Mitigation: chronology is the sort order, L2 stays ink 500, and the day header is always visible (sticky). A time-rail layout (Naver, Google) was considered and rejected: it needs a second left column next to the thumb.

What changes ​

  • Library §5 MediaRow (L1 and L2 swapped, L2 ink 500, L3 discovery only; a single-venue variant that leads with the time); the compact row in the list spec; §18 D-rows that mention "time (L1)".
  • Boards: flat-v2-list-a (번개 찾기, 내 경기, club 일정, 홈) and the MediaRow specimens on flat-v2-components.
  • Code: SessionCardV2 projections read L1 from the venue name and L3 from sessionTitle(); the spoken name keeps the full sentence ("오늘 오후 7시부터 9시까지, 올림픽공원 테니스장, 6명 중 8명").

23. Horizontal lists on detail pages ​

Owner: "why don't we make lists (like the participant list) into horizontally scrollable lists so that we can keep the vertical page clean and organized."

What we have ​

  • Session detail (IA-3, D3): Notice stack, hero, then the 참석 roster as a 4-up grid in two rows (216 tall) with dashed empty slots and a "+N" door, then 경기 rows, then 정보 Cells (six × 48), then the CTA band. The fold test is that the roster's head and first row sit above the band.
  • Canon already has a rule for exactly this question, the place-surface law (2026-08-22): browsing surfaces scroll vertically, always; a place surface (a page that IS a thing, such as club home) may compose bounded horizontal preview shelves (at most five items) with a 더보기 escape into a vertical page, and "A shelf may NEVER be the sole path to content". The old "no horizontal scroll for my stuff" rule is "this law's browsing-surface half" (canon/components.md line 135).
  • Platform cost already on record: on iOS 26 the content-area swipe-back cancels touches in the content, a rightward drag on a horizontal control is the same direction, and every screen that hosts one must set fullScreenGestureEnabled: false; the interaction with horizontally scrolling tabs is unverified (addendum B9.3).

Evidence ​

How apps show who is coming (store frames)

App and screenParticipant displayHorizontal scroll?Source
플랩풋볼 match detailteam tabs 레드 · 블루 · 옐로우, then a 3 × 2 grid of player cards (number, level, name)nofr 4
Spond eventcounts "25 attending, 15 unanswered, 5 declined", a recipients screen with tabs Attending · Waiting list · Not answered · Declined, "Send reminder to unanswered"no (vertical lists by status)fr 1, 3
TeamSnap gameavailability list grouped Going (4) · Maybe (1) · Not Going (2), with a status icon and a note per personnofr 4
Playtomic open matchone row of four slots (avatar, name, level) with a "+ Available" slotnofr 4
소모임 정기모임avatar row and "참석 12/50 (38자리 남음)"nofr 6
Eventbrite, Meetup, 밴드avatar stack and "7 friends going", "107 going", "28명 참석"noEventbrite fr 2, Meetup fr 2, 밴드 fr 4

None of the eight shows people in a horizontally scrolling row. Three apps the brief named show no attendee list in their store frames and so add nothing to the table: Luma's event page shows host, time and Register (fr 4), 당근's 모임 tab shows no event roster, and Strava shows only a kudos avatar row with a count (fr 2, 6). The three sports apps (플랩풋볼, Spond, TeamSnap), where the roster is the task, use vertical grids or status-grouped lists; the five social apps use a short row or stack plus a count. Horizontal rows exist for browse content: Airbnb's "Recently viewed homes" and "Stay in…" cards peeking at the right edge (Play fr 2), Booking's Deals cards (fr 1), 네이버 and 카카오 photo strips with the next photo cut off (web, web), Luma's city cards and category chips (fr 2), Strava's sport chips (Strava).

Research and guidelines

SourceFinding
NN/g, carousels on mobile"users should be able to reach the last item in the carousel in 3–4 steps"; dots are weak, the "illusion of continuity" (content running past the edge) is a strong cue; "Important items used in hero carousels should be accessible in some other way"; edge swipes can trigger Back, so leave a page gutter; arrows over busy images lose contrast outdoors.
NN/g, carousel usability"5 or fewer frames within the carousel"; show count and position; put important information "also somewhere else in the UI"; "Do not auto-forward on mobile devices".
NN/g, illusion of completenessWhen the visible content looks complete, people stop: "Show additional content bleeding off screen"; keep crucial information out of carousels.
Baymard, gallery thumbnailsTruncating a carousel without a cue meant "participants did not always realize additional images were available"; a partial thumbnail was "equally effective" on mobile; a "+4" truncation tile and arrows were "highly effective". Sample size not stated.
Baymard, swatches"users simply don't recognize that the swatches can be scrolled"; truncate the last item clearly; "scroll arrows should be easy to discern at each side".
HIG scroll views"Make it apparent when content is scrollable… displaying partial content at the edge of a view indicates that there's more content in that direction." Do not nest a scroll view in one of the same orientation. HIG collections: collections suit image-based content; "Consider using a table instead of a collection for text."
M3 carouselAt compact width show up to three items when they carry text; small items 40 to 56 dp; on a vertically scrolling page carousels "require an accessible way to view all the items without horizontally scrolling": a "Show all" button, or an arrow icon button (48 dp) in the header; do not put buttons inside or beside the carousel.
M3 carousel accessibilityThe container is labelled with the total item count and the current item; users must be able to skip the carousel; reduced motion removes the parallax.
WAI-ARIA carousel patternContainer aria-roledescription="carousel"; each slide a named group, or "3 of 10" when no names exist; a rotation control first if it rotates.
WCAG 1.4.10 reflowA carousel passes if each panel fits a 320 px viewport and scrolls one way. WCAG 2.5.7: scrolling by the user agent is exempt; a custom draggable carousel needs click or tap buttons.

Reconciling the owner's two rules ​

The owner's wish to "keep the vertical page clean and organized" and the earlier rule "no horizontal scroll for my stuff" are both covered by the place-surface law (the old rule is its browsing-surface half), and the evidence supports that reading: horizontal rows are for optional, parallel, visual browse content that is not the viewer's obligation and not the page's primary fact. The roster fails every test: it is primary (who is coming, how many seats), it has holes that matter (open slots), it is the thing the CTA acts on, and the sports apps that handle it best show it vertically. A shelf test (all four must be yes):

  1. Is the content optional and visual (photos, next sessions, recommendations)?
  2. Is every item reachable in a vertical page one tap away, from the section head?
  3. Are there at most five items?
  4. Is it not the viewer's own obligation or data (회비, 내 경기, 알림) and not what the CTA acts on (roster, 경기)?

Recommendation ​

CollectionPageDecisionWhy
참석 rostersession detailvertical, one row of four cells (the existing 4-up geometry): up to four people, host first, or three people plus a door "+N" when there are more than four; empty slots are not drawn here (the head says "6/8 · 2자리 남음"); the full list is one tap awayprimary social proof and the CTA's subject; 0 of 8 peers scroll people; saves 116 pt of height (216 → 100) with no gesture cost (C)
예비, 불참session detaillink in the head, as todaysecondary
경기 (matches)session detailvertical rows, three shown, then "전체 보기"scores and taps; not a shelf
정보session detailvertical Cells; ExpandToggle past six rows (IA-3, unchanged)one task per screen
사진club hub, venue, post-sessionshelf (tiles 140)optional, visual; peers show strips with a peek
다음 일정club hub 홈 pane, venueshelf (cards 240), at most five, then "전체 보기"place surface; each card opens the session
추천 클럽, 추천 코트discoveryshelf (cards 240)browse content
멤버, 내 일정, 내 경기, 회비, 알림everywhereverticalthe viewer's own data
최근 5경기 (Form strip)head-to-headfixed row of five, no scrollfive fixed cells fit the rail

Shelf anatomy (new component; the three presets make a half item peek at 390)

PresetItemGapShown at 390Use
Card240 wide; media 4:3 above two lines121 card plus 118 pt (49%) of the next다음 일정, 추천
Tile140 square, r882 tiles plus 74 pt (53%)사진
Cell76 wide: avatar 48, name 13/18, 2 lines84 cells plus 34 pt (45%)people, only where a shelf is allowed
  • Head: title 17/24·600, count suffix 15/22·500 secondary, "전체 보기 ›" 13/18·500 secondary at the right with a 44 target (the M3 header arrow). On windows of 600 pt and up add ‹ › buttons in the head row, above the shelf, never beside or on it, and never hover-only.
  • Overflow: at most five items, then a sixth door card "전체 보기" (Baymard's "+4" tile). One item: full width. Two items that fit: no peek. Zero: no head.
  • Scroll: native horizontal scroll, the first item on the 20 rail, content running under the right edge; cards snap to item starts (M3 snaps hero and multi-browse layouts); tiles and cells scroll freely; no auto-advance, no dots, no parallax.
  • Accessibility: role=list labelled "사진, 12장"; one focus stop per item with the item's own spoken label; the 전체 보기 control comes first in focus order; arrow keys move focus on web; do not virtualise away off-screen items from the accessibility tree. A custom pan carousel (not the native scroll view) needs prev and next buttons (WCAG 2.5.7).
  • Gesture: every screen with a shelf takes the B9.3 treatment (fullScreenGestureEnabled: false) or the shelf starts after an inset; verify the first iOS 26 build (swipe back from the left edge, swipe a shelf from its first item). Session detail has no shelf in this plan, so the busiest detail page keeps its full-screen back swipe.

What changes ​

  • Library: new Shelf component (§18.2); §18.2 Roster door and §19.3 roster rules amended to one row; IA-3 step 3 (참가자: roster, 4-up, dashed empty slots, a 외 N명 door, 호스트 Tag) rewritten (an alternative if four faces matter: five 70-wide cells in the row); SectionHead gains the shelf head; the place-surface law cited in the library.
  • Boards: flat-v2-detail session frames (one-row roster), club hub and venue shelves; flat-v2-patterns Shelf specimen with the three presets.
  • Code: one Shelf primitive wrapping ScrollView with the presets; the roster section renders four cells and the door; lint: no ScrollView horizontal outside Shelf and the existing Tabs.

Audit of unreviewed sections ​

Scope: library §3 to §9 and §14 page components, and the additions in §18.2 to §22.2. Each row lists a value or behaviour that departs from current guidance or measured peer practice, with the evidence and a fix. Severity: H fix before build, M fix in this wave, L cheap polish. Rows that duplicate a numbered point above point back to it.

#SevSection (library)IssueEvidenceFix
1H§14 HeaderTextActionGhost text in ink with no tint or container: the shipped tint was the action's only cue and v2 removed it.NN/g weak signifiers: +22% time, +25% fixations (NN/g); canon line 122 (the tint "IS the one resting affordance cue"); every header text action in peers is a pill (§14).Retire; text only as H-4 pills.
2H§22.2 ProviderButton (Kakao)Radius 6; Kakao's guide requires 12."컨테이너 박스의 radius는 12 픽셀(Pixel)로 적용합니다"; the other values in our spec match the guide (container #FEE500, symbol #000000, label #000000 at 85%, system font, label no taller than a third of the container) (Kakao).Radius 12. It equals the lg Button radius, so the special case disappears.
3H§14 LiveScoreControls not legible; 6 px colour-only server dot; §14 says "150 ms numeral cross-fade" while §16 P4 says instant; labels promise points the engine does not store.§19 above.L-1 to L-10; reconcile P4; decide points versus games first.
4M§14 MediaBand (circles)36 circles at ink α0.4: white glyph reaches 2.81:1 at the circle's lower edge on a white photo (3.15 at its centre).WCAG 1.4.11 needs 3:1 (W3C); M3 default icon-button container 40 dp (M3); Airbnb circles about 40 pt (web render) (C).40 at α0.5 (worst case 3.8:1).
5M§16 P5 (text over a photo)White 15/22·600 text on ink α0.4: 2.8 to 3.6:1 across the pill on a white photo.WCAG 1.4.3 needs 4.5:1 for text smaller than 18 pt (24 px) regular or 14 pt (18.7 px) bold (W3C) (C): α0.6 is the minimum.Retired with the header text action (H-4).
6M§3 Header (⋯ menus)The boards draw ⋯ menus with two rows (club hub: 공유, 나가기) and a ⋯ as the only route to officials' tools.HIG pull-down: "a minimum of three items", "Avoid putting all of a view's actions in one pull-down button" (HIG); M3: "Avoid placing an overflow menu in the app bar when possible" (M3); U-05.H-3: three rows or none; promote 공유.
7M§14 ActionSheet heightThree values: "max 80%" (§14 row and the patterns board), 88% (§16 P2, the code), M3's initial 50%.M3 caps the initial height at 50% and lets it be pulled up (M3); HIG: "Avoid letting an action sheet scroll" (HIG). A nine-row host sheet is about 590 pt (432 rows + 48 group gaps + 56 title + 54 foot, C), under 88% of 844 (743).One value: open at content height, cap 88%, scroll only beyond it.
8M§14 CTA band helper lineThe fee and cancellation consequence is the smallest secondary text on the page (13/18).Eventbrite and Booking set the fact in bold beside the button and the qualifier small (Eventbrite fr 2, Booking fr 6); U-12 asked card meta at 14.Two-tone helper: the fact 15/22·600 ink ("참가비 15,000원"), the qualifier 13/18 secondary ("시작 24시간 전까지 무료 취소"); band grows by 4.
9M§14 MessageBubble + ComposerFive values differ from the best open reference; the home inset under the keyboard is unspecified (34 pt dead gap); attach target unspecified; failed state has one action.§18 above.§18 tables.
10M§14 ScoreEntry (auto-advance)Focus jumps to the next field after a digit; the tiebreak field takes two digits.WCAG 3.2.2 allows moving focus after a completed field only when the behaviour "is described for the user at the beginning of the form" (W3C); HIG text fields: show the keyboard that fits the content (HIG).Caption above the table "숫자를 입력하면 다음 칸으로 넘어가요"; no auto-advance on the tiebreak field; keep the numeric keypad.
11M§18.2 Activity heatmapCells are 12 pt; the scrub targets them. No legend. Five grey steps with no stated step difference.WCAG 2.5.8: 24 × 24, unless an equivalent control exists (W3C); a heatmap is read by value, so the scale needs a key.A month list or sentence as the equivalent ("이번 달 12일 활동"); legend "적음 ▢ ▢ ▢ ▢ ▢ 많음" 12/16; gate adjacent steps in the colour check (design judgement: ΔL* of 8 or more).
12M§22.2 Sheet, documentA lengthy legal text in a sheet.NN/g: avoid bottom sheets for content users will spend significant time reviewing, or that is lengthy or complex (NN/g); HIG: "For complex or prolonged user flows, consider alternatives to sheets" (HIG).이용약관 and 개인정보 처리방침 open as a pushed page (header ← and title, version line, scroll); keep the sheet for a three-line summary only.
13M§19.3 Reactions (quick row)The reaction row sits in a sheet that can cover the message it acts on; the viewer's own reaction in the feed action row (a heart) is unspecified.HIG context menus: "Prefer a graphical preview that clarifies the target of a context menu's commands" (HIG).The sheet's title row shows the sender and a one-line excerpt of the message; in the feed the action row shows the viewer's chosen emoji in place of the heart once they react.
14L§18.2 PostRow vs PhotoGridTwo gaps for one pattern: 8 between post photos, 2 in the album grid.Naver Cafe's editor draws a 2-up collage with a gap of a few points (fr 7); Band's album tiles, which carry captions, sit wider apart (fr 5).Rule by role: collage without captions 4 (r8), tiles with captions 8, full-bleed grid 2.
15L§22.2 Cell, consentThe 보기 control is a ghost text link: a weak signifier next to a checkbox.NN/g weak signifiers (NN/g)."보기 ›" with the chevron; keep its own focus stop.
16L§7 Switch48 × 28 track, thumb 24; both platforms use larger.M3: track 52 × 32, 48 dp target (M3).52 × 32 (same look, larger for the audience).
17L§19.3 Form strip12/16·700 inside 24 cells is the smallest text in any control.U-12 asked secondary text at 14 (usability audit).13/18·700 in 28 cells (five cells 156 wide); the spoken string is unchanged.
18L§14 Select mode (header)취소 and 전체 선택 are bare ink text.as row 1H-4 pills; the count title and polite announcement stay.
19L§18.2 MediaBand album overlayCount Tag and pager dots together.NN/g dots are weak signifiers; Airbnb counter only (Play fr 10).Counter only (M-6).

Checked, no departure found.

  • Calendar: Sunday red and Saturday blue match 네이버 캘린더's month grid and 플랩풋볼's day strip (네이버 캘린더 fr 1, 플랩풋볼 fr 2); the weekday labels are text, so colour is not the only cue. Band's month view uses the same chevrons and an 오늘 pill (fr 4).
  • Podium: rank is printed text and the medal ring is additive (WCAG 1.4.1); §20.3 already fixed the glyph contrast.
  • FilterSheet: matches Booking's pattern of a filter sheet with a live result count on its CTA (Booking fr 6).
  • SwipeAction: an accelerator only, which is what HIG asks of custom gestures: discoverable and "Not the only way to perform an important action" (HIG gestures); full swipe commits with an undo Toast.
  • PhotoGrid (3-up, 2 pt gaps), Comment (one reply level), Search takeover, Dialog (outside tap does not close it, Seed's default; two buttons, M3's limit), Tabs (44 row).
  • Live row: the pulse stops after five seconds, as WCAG 2.2.2 requires for moving content (W3C).
  • CountdownNotice: a payment hold is an essential time limit, the user is warned and told the way out, which WCAG 2.2.1 accepts (W3C, ticket-hold example); the per-second tick is auto-updating information, exempt only because it is essential (2.2.2 has no five-second exemption for it), so keep the polite 5:00 and 1:00 announcements and give assistive tech a static "남은 시간" line.
  • FAB: 당근's extended FAB measures about 42 pt tall in its store frame (fr 2, C); ours is 48, M3's is 56 (M3).
  1. Header registry (14). Ten glyphs only (back, close, search, share, bookmark, bell, message, gear, plus, ⋯), at most two trailing icons, ⋯ only with three or more rows. Bare ink header text is retired; text survives only to leave or commit a mode (취소 · 완료 · 저장 · 건너뛰기 · 전체 선택), drawn as sm pills.
  2. Entries leave the header (14). 관리 becomes a gear with a badge, backed by labelled tool Cells, the 할 일 section, a one-time coachmark and a five-official test with a pre-approved 관리 pill as fallback; 초대 코드 moves into the 클럽 tab's + sheet; 선택 into a three-row ⋯ (reconcile screens open in select mode); 편집 is the identity Block's pencil; 모두 읽음 stays a section command.
  3. One overlay rule (15). Confirm a consequence: Dialog. Commands for an object: one bottom list, renamed MenuSheet, with the anchored Menu only at 600 pt and up. Choose a value or enter data: Sheet. Read at length or run a flow: a page. Consequence choices after an action reuse the list with a question title.
  4. Photo bands (17). ‹ plus at most two registry icons (share first, then save or a three-row ⋯), circles 40 at ink α0.5; never text, pills or place actions; 길찾기 · 공유 · 전화 sit in a labelled body row on venues; the session's 단톡방, 문의하기 and 신고 become 정보 Cells; the album overlay is a counter without dots; no save icon on list thumbnails.
  5. Messaging values (18). Within a run 4 → 2, system lines 16 → 20, bubble max 306 (1:1) and 266 (group), 12 from the last bubble to the composer, home inset 0 while the keyboard is up, a labelled attach sheet, 삭제 beside 다시 보내기. The rest already matches Signal-iOS and KakaoTalk.
  6. Live score (19). A full-screen recorder where each team's own panel (at least 160 pt tall, 245 on a tall phone) is the control, real team names, a labelled 되돌리기 that says what it reverts, the server as glyph plus "서브", a non-blocking 코트 체인지 banner, a Dialog only when the match is decided, screen kept awake. Decide points versus games in the engine first.
  7. Session row (8). Venue on L1, time on L2 in ink 500 (no longer secondary), format and level on L3 in discovery only; when every row shares one court (a one-court club, a venue page) the court moves to the list head and the time leads.
  8. Shelves (23). The roster stays vertical but shrinks to one row of four cells (saves 116 pt). Horizontal shelves are for optional browse content only (photos, next sessions, recommendations): at most five items plus a 전체 보기 door, three presets that leave half an item peeking, and the B9.3 swipe-back cost on any screen that hosts one.
  9. Audit fixes. Kakao button radius 12; 약관 as a pushed page; Switch 52 × 32; a ScoreEntry advisory line and no auto-advance on the tiebreak field; heatmap text equivalent and legend; two-tone CTA helper; the reactions sheet shows its target message; MediaBand contrast and the §16 P4 conflict resolved.
  10. Gates and checks. A header-slot icon lint, a lint that allows horizontal ScrollView only inside Shelf and Tabs, one chat-constants file, the five-official U-05 test in the QA checklist, and the board updates listed under each point.

Appendix A: store listings read ​

The lookup link returns the listing's JSON; screenshotUrls holds the frames and description the store text. Versions and dates are from the lookup on 2026-10-11.

AppStore idCountryVersionReleasedSource
배달의민족378084485kr16.26.02026-10-06lookup
밴드-모임이 쉬워진다!542613198kr30.2.22026-10-08lookup
Booking.com367003839us70.42026-10-08lookup
당근1018769995kr26.41.02026-10-07lookup
Eventbrite487922291us10.85.02026-10-09lookup
플랩풋볼6608972481kr2.0.12026-09-21lookup
Google Calendar909319292us26.38.12026-10-06lookup
카카오톡 KakaoTalk362057947kr26.8.42026-10-07lookup
LINE443904275us26.15.12026-09-29lookup
Luma1546150895us2.182026-10-06lookup
MatchTrack Tennis Score Keeper977481057us2026.72026-09-28lookup
Meetup375990038us2026.10.82026-10-09lookup
민턴보드6746028000kr1.1.12026-09-12lookup
문토1535886772kr7.6.42026-10-09lookup
네이버 카페420615104kr26.1005.02026-10-07lookup
네이버 캘린더592346243kr4.7.52026-10-06lookup
피클볼 점수6758124151kr4.02026-08-31lookup
Playtomic1242321076us6.93.22026-10-07lookup
Racketly6736381821us5.1.02026-10-10lookup
Ralli6449350578kr1.1.92026-09-28lookup
Side Out1671243214us3.4.02026-01-21lookup
Smashpoint Tennis Tracker1098174650us3.42026-09-30lookup
소모임582910479kr4.4.12026-10-06lookup
Spond755596884us4.63.32026-09-24lookup
Strava426826309us484.0.02026-10-07lookup
SwingVision989461317us11.9.682026-10-09lookup
TeamSnap393048976us7.73.02026-09-30lookup
테니스점수판6774510577kr1.02026-05-31lookup
Tennis Scorecard App6451323049us2.7.22026-09-11lookup
Tennis Umpire App1316338557us5.3.02023-10-14lookup
테니스프렌즈6758872979kr1.0.632026-09-30lookup
토스839333328kr5.279.02026-10-02lookup
WhatsApp Messenger310633997us26.39.752026-10-08lookup

Other pages read: the Play listings, web renders, HIG pages, Material 3 pages, Seed and TDS docs, WCAG Understanding pages, NN/g and Baymard articles, and the repo documents linked in the text; every URL is in the link list below.

Markdown remains the source of truth. Run yarn docs:check before handoff.