Skip to content

Flat mobile grammar v2 — designed from the ratios (2026-10-09) ​

Status: Draft · Date: 2026-10-09 · Owner brief: "If we really are going for flat layouts, reconfigure all of the components in the page and work out their ratios as well. Don't rely on the old layouts. Design from scratch with best practices in mind." This is the system: one reference frame, one type scale, one spacing ladder, one set of component proportions, and six screens composed only from them. Nothing here reuses the card grammar. Colour comes from colour-system-research-2026-10-09.md §2 and is not restated. Evidence for the numbers: Apple HIG (Dynamic Type Large: body 17/22, subhead 15/20, footnote 13/18, caption 12/16, title 2 22/28, 44pt targets, 20pt inset on grouped lists), Material 3 (type scale 11–57, list items 56/72/88, 48dp targets, 4dp grid, 16dp margins), Toss TDS (T7 13 → T1 30 in roughly 1.15 steps, ListRow padding 12/24, min 44), Seed (12/13/14/16/18/20/22/24 … 48, list padding 12, gutter 16, avatar 48/56, radius 4/8/12/16/20/24) — URLs in the lane appendices of the two research notes.

1. Reference frame and grid ​

  • Reference device 390 × 844 pt (iPhone 15 class); the board draws at 1:1 CSS px.
  • Grid: 4pt. Every size, gap and position is a multiple of 4; text line-heights are multiples of 2 and stack onto 4.
  • Rail: 20 (Apple grouped-list inset 20; Toss 24; Seed 16). Content width 350.
  • Touch target: 44 minimum (Apple), 48 preferred for primary actions (Material).

2. Type scale (Pretendard; size / line-height · weight) ​

Anchor: body 15/22 (Apple subhead 15, Toss T6 15 — the Korean body size peers use). Steps are the Toss/Apple intervals, not a single multiplier: 12 → 13 → 15 → 17 → 20 → 24 → 40.

RoleSize / LHWeightRatio to bodyUse
display40 / 487002.67the block numeral (count, ELO)
hero24 / 327001.60detail title; identity name; stat numerals (stat strip uses 24/32)
title20 / 287001.33screen header title
headline17 / 246001.13row line 1; section titles; hero facts (500); primary button label
body15 / 22400 · 5001row line 2 (400, secondary ink); cell values (500); tab labels (600 active / 500); block meta
footnote13 / 18500 · 6000.87row trailing meta; tags (600); eyebrows; section actions; day headers
caption12 / 165000.80tab-bar labels (11/14 on iOS is allowed), counters

Line-height ratio 1.4–1.47 for text, 1.2 for display and hero (Apple 17/22 = 1.29, Toss 15/22.5 = 1.5, Seed 16/22 = 1.375). Weight ladder: 400 body · 500 meta/values · 600 headline/tags · 700 numerals/titles. No bold below line 1 in a row (ledger row 8; lane I).

3. Spacing ladder (roles, not just sizes) ​

StepRole
4line 1 → line 2 in a row; numeral → unit
8icon → text; tag padding; eyebrow → numeral in the block; section title → first row
12row vertical padding; thumb → text
16gap under tabs; chart inset; block internal element gap
20rail; block padding; FAB offset
24block → section header; hero top
32section seam (between sections); hero → first section
40bottom CTA band top padding to the last content

Ratios: seam ladder 8 : 16 : 32 (1 : 2 : 4) for title→row, tabs→content, section→section; block padding = rail (20) so the block's inner edge lines up with the page's text edge; row padding 12 = 0.6 × rail.

4. Component proportions ​

ComponentGeometryProportion / rationale
Status bar44 (drawn in the mock for 1:1 honesty, quiet)iOS
Header56; title 20/28·700 at the rail; right actions 24 glyphs in 44 targets, gap 8; no dividericons are action targets (owner); 56 = Apple nav bar + 12
Underline tabsrow 44; label 15/22 600 ink (active) / 500 $textSecondary; label padding 0 12; underline 2pt ink under the label width; 16 belowToss, 카카오뱅크, 배민
Brand blockwidth 350, radius 16, padding 20, min 144: eyebrow 13/18·600 at α0.8 + chevron 20 right · 8 · numeral 40/48·700 with unit 15/22·600 on the baseline · 8 · meta 15/22·500 at α0.85; ELO variant adds 8 · progress 6 (optic on α0.2 track) · 8 · caption → 158144/844 = 17% (peers 16–18%); width : height = 2.4 : 1; left-stacked; pressable; no button inside
Section headertitle 17/24·600; action 13/18·500 secondary + chevron 16; 32 above, 8 below1 : 2 : 4 seam ladder
Row, media (sessions, clubs)padding 12; thumb 56 r8 (club logo r12); gap 12; L1 17/24·600 ink; 4; L2 15/22·400 secondary; trailing 15/22·600 tabular or one Tag; pitch 80; no divider, no fillthumb : pitch = 0.7 (Toss 혜택 0.77); text block 50 inside a 56 thumb; one trailing element
Row, person (members, dues, ranking, results)padding 12; avatar 40; gap 12; L1 15/22·600; 4; L2 13/18·500 secondary; trailing 15/22·700 tabular (score, amount, ELO) or one Tag; pitch 64club-detail canon; Seed avatar 40–48
Day header32 tall; 15/22·600 ink date + 13/18·500 secondary relative day at the right; 16 above—
Tagheight 24; padding 0 8; radius 6; 13/18·600; weak / solid tiers from the ledger tone table; ≤ 1 per rowlabel : row = 24 : 80 = 0.3
Choice (control)height 36; padding 0 14; radius full; 15/22·500; 1px $border resting; ink fill + check selectedsettings and wizards only
Primary button52; radius 12; 17/24·600; brand solidToss 52–56, Apple 50
Bottom CTA bandbutton 52 inside padding 16 + home inset 34; a hairline above only when content scrolls under itone CTA per detail page
FABextended pill 48; padding 0 20; icon 20 + 8 + label 15/22·600; brand solid; 20 from the right rail and 16 above the tab bar당근 글쓰기; the one coloured action on list screens
Tab bar56 + home inset 34; icons 24 stroke 2; labels 11/14·500; active = filled glyph + ink + 600Apple / M3; neutral, never brand
Stat strip80; three columns; numeral 24/32·700; label 13/18·500 secondary; 1 × 24 hairline between columnsnumeral : label = 1.85
Hero (detail)top 24; eyebrow 13/18·500 secondary; 4; title 24/32·700; 16; three facts 17/24·500 with a 20 glyph (stroke 2, label colour) + 8; fact gap 8; 32 belowledger §5 tiers: the only glyphs on the screen
Cell row (facts)48; label 15/22·400 secondary left; value 15/22·500 ink right; no dividerclub-detail canon
Rosteravatar 48 in a 4-up grid (gap 16); name 13/18·500 below (4); level Tag 24 below (4)Playtomic
Chart160 tall, inset 16, one ink line, no fill—
Avatars40 rows · 48 roster · 56 identity blockSeed 48/56
Radii6 tag · 8 thumb · 12 button and club logo · 16 block · full avatar / pillSeed 4–24
Icons24 actions · 20 hero facts · 16 chevronsApple 17–24

4b. Seams — how flat surfaces divide (added 2026-10-09, lane K) ​

Owner: "Are we adding dividers? What's the best practice on flat surfaces?" Evidence: lane K — 22 measured peer screens across 15 apps, Apple HIG (plain vs inset-grouped lists, scrollEdgeAppearance), Material (lists, dividers, liftOnScroll), Seed's three-tier separator statement (inset line = weak, full line = medium, 8px band = strong), Toss TDS Border (full / padding24 / height16), GOV.UK section break, Gestalt proximity and common region (Wertheimer 1923, Palmer 1992). No controlled study of dividers vs whitespace on mobile lists exists; these are guideline-and-practice rules, stated with the numbers peers actually use.

SeamRuleValueEvidence
Row → row (media 80, person 64)no line; the 12 padding is the rhythm—9 of 17 peer screens with consecutive rows use spacing only, all with a 30–56pt anchor and a 59–81 pitch (Toss 혜택, 카카오뱅크, Monzo); lines appear only on 88–121pt photo rows and inside cards
Cell → cell (single-line 48 label/value: 정보, settings, dues ledger)quiet hairline, inset to the rail (20 both sides)#E5E5E5 1px (1.26:1), the heaviest measured Korean row hairline (네이버); peers 1.10–1.26Apple inset-grouped separators, Material 1 lists, GOV.UK summary list, Carbon; 테니스프렌즈 내 정보 — a 48pt cell has no anchor, so proximity alone does not group it (amends the 2026-09-06 FactRow rule; D8)
Section → sectionwhitespace + the section title, no line32 ink-to-ink (the edge rule trims the last row's bottom padding, so the box gap is 32)flat peers 27.7–55.8pt ink-to-ink, median 36; none of the 22 screens draws a line between ordinary sections
Zone change (hero zone → content; content → comments/discussion)one full-bleed band, at most one per screen#F2F2F2 (L* 95.5), 12pt, 24 above and 24 below카카오페이 band 13.1pt with 33/37 air; published Toss 16, Seed 8, Material heavy 8; median of 12 values 11.7; measured and published bands sit at L* 96.1–96.2
Block / hero → contentspacing only24peer median 25 (21–34, 8 of 10); the coloured block is already a container
Tab row → contentspacing24 before a title or day header (was 16)peers 22–31 under underline tabs
Sticky header / tab rowhairline only while content scrolls under itfull-bleed #D4D4D4 (1.48:1)Apple scrollEdgeAppearance (transparent at rest), Material liftOnScroll; 4 of 6 peers draw it under the tab row, the sharpest at 1.45 (Toss) and 1.49 (배민)
Tab bar / CTA bandhairline only while content lies below; no shadow#D4D4D4same; only floating pill tab bars (당근, 카카오뱅크, 네이버) carry a shadow
Dark modeedges white α0.14, cells white α0.09; the band goes darker than the canvas#000000 band under an ink canvasToss, Seed, Apple dark grouped

Hairline tiers, therefore two: edge #D4D4D4 (sticky edges, tab rows) and cell #E5E5E5 (single-line cell groups). Nothing else draws a line.

Why this amends the Divider law of 2026-09-06 ("dividers separate sections"): that law was written after a build that drew hairlines between rows and whitespace between sections, so a section edge read like one more row. In this grammar rows carry no line, every section opens with a 17/600 title on 32 of air, and the row rhythm (80/64) is taller than the old 40pt rows — the failure mode the section line fixed cannot occur. The section line is retired (D9); the band replaces it for the one case a change of kind needs more than air (D10).

Developer test: delete the line and keep the gap — if the two things still read as separate groups, there is no line. A line is allowed only at a sticky or tab edge while content passes under it, between single-line cells of one group, and as the one band where the kind of content changes.

5. Screens (390 × 844; stacks top → bottom; every number from §2–§4) ​

홈 — status 44 · header 56 ("홈", bell) · 8 · block 144 (eyebrow "내일, 9월 19일 (토)" + chevron; "2" + "개 일정"; "첫 시작 09:00 · 올림픽공원") · 24 · section "내일 일정" / "전체 보기 ›" · 8 · 2 media rows (80) · 32 · section "이번 주" · 8 · 2 media rows · FAB "+ 일정" · tab bar. Trailing on rows: "4/8" or one Tag (참석 success-weak).

경기 · 번개 찾기 — status · header ("경기", search, bell) · underline tabs (내 경기 / 번개 찾기 / 저장됨) · 16 · day header "9월 18일 (금) · 오늘" · 3 media rows (LIVE danger-solid Tag; "6/8"; 마감 임박 warning Tag) · 16 · day header "9월 19일 (토) · 내일" · 2 rows · FAB "+ 번개" · tab bar.

클럽 — status · header ("클럽", invite code, plus) · tabs (내 클럽 / 탐색) · 16 · media rows with club logo 56 r12: L1 club name, L2 "서초구 · 멤버 42 · NTRP 3.0–4.0", trailing unread count Tag (neutral) or nothing · 탐색 variant: trailing 모집 중 brand-weak Tag · tab bar.

기록 — status · header ("기록", bell) · 8 · ELO block 158 (eyebrow "ELO · NTRP 3.5–4.0" + chevron; "1,482"; progress; "마스터까지 518점") · 24 · tabs (우리 클럽 / 친구 / 지역 / 전국) · 16 · stat strip 80 (47 총 경기 · 68% 승률 · 3승 연승) · 32 · section "최근 ELO 추이" · 8 · chart 160 · 32 · section "클럽 랭킹" / "전체 보기 ›" · 8 · 3 person rows (rank number 13/18·600 secondary in a 24 column before the avatar; trailing ELO 15/22·700 + level Tag) · tab bar.

프로필 — status · header ("프로필", settings) · 8 · identity block 144 (avatar 56; name 24/32·700 + level Tag; "강남 테니스 클럽 · 3년 차" 15/22 α0.85; edit 24 ghost top-right) · 24 · stat strip (47 총 경기 · 68% 승률 · 92% 출석률) · 32 · section "친구 24명" / "전체 ›" · 8 · avatar row 40 × 6 (gap 8) · 32 · section "최근 경기" / "전체 보기 ›" · 8 · 3 person rows (L1 opponents, L2 date; trailing score 17/24·700 tabular + 승/패 Tag) · 32 · section "업적" · tab bar.

세션 상세 — status · header (back; bookmark, more) · hero (eyebrow "강남 라켓클럽"; "올림픽공원 테니스장"; facts: 📅→calendar "9월 19일 (토) 09:00–11:00", pin "올림픽공원 테니스장 · 하드", card "무료") · 32 · section "참가자 6/8" · 8 · roster 4-up (two rows, two empty dashed slots) · 32 · section "정보" · cell rows (종목 복식 · 대상 NTRP 3.0–4.0 · 호스트 김민준 · 참가비 무료) · 40 · CTA band "참석하기".

6. What leaves ​

Cards on list surfaces; the segmented pill on lists; the capacity bar, price, bookmark, three emoji lines and status word on rows; $primarySubtle as a surface; the 21-glyph vocabulary (4 concrete glyphs stay, hero only); any component not in §4. Web follows the mobile grammar later.

7. Verification the board must pass ​

Every drawn element's top edge, height and left edge are multiples of 4; the rail measures 20 on every screen; media rows pitch exactly 80 and person rows 64; the block measures 144 (158 for ELO); the tab bar 56 + 34; type sizes and line-heights match §2 to the pixel; one coloured action per list screen (the FAB) and one block per hub; one trailing element per row; zero glyphs in rows. Measured from the DOM, printed under each screen.

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