Skip to content

Lane K — separation on flat surfaces: dividers, bands, whitespace (2026-10-09) ​

Status: Reference · Date: 2026-10-09 · Evidence appendix for flat-mobile-grammar-v2-2026-10-09.md §4b (seams). Frame and crop paths refer to the session scratch directory (not committed).

Scope: the owner's question "are we adding dividers, and what is best practice on flat surfaces?" for the flat grammar v2 (docs/design/flat-mobile-grammar-v2-2026-10-09.md: rail 20, 4pt grid, media rows 80 / person rows 64, section seam 32, block to list 24, pure white canvas) and scheme S2 (#D4D4D4 hairline, #F2F2F2 fill). Nothing under /home/sungkyu08/Dev/twomore-v2 was touched. All files are under bench/lane_k/ (sources in lane_k/src/, helpers seam2.py, strip2.py, gaps.py, colcalc.py, crops in lane_k/crops/). Contact sheet of the 8 clearest seam examples: bench/lane_k/contact-seams-8.png (also split in contact-seams-8a.png, contact-seams-8b.png; built with python3 sample.py --contact).

Reading order: section 1 (guidelines), 2 (22 measured peer screens), 3 (counts), 4 (rules for us, with evidence), 5 (not supported), 6 (caveats).


1. Guideline table (source · rule · values · URL) ​

"Verbatim" marks text I read in the fetched source; everything else is a value read from a published token or source file. Version pins: @toss/tds-mobile 2.5.1 (npm pack, 2026-10-09), @toss/tds-colors 0.1.0, @carbon/themes 11.83.0, @fluentui/tokens 1.0.0-alpha.24, @atlaskit/tokens 20.4.0, androidx material3 tokens v0_117, daangn/seed-design dev.

1a. Platform guidelines ​

SourceRule (verbatim or paraphrase)ValuesURL
Apple HIG, Lists and tables"the grouped style uses headers, footers, and additional space to separate groups of data". No separator thickness, inset, or colour is stated on the page.none statedhttps://developer.apple.com/design/human-interface-guidelines/lists-and-tables (read via https://developer.apple.com/tutorials/data/design/human-interface-guidelines/lists-and-tables.json)
Apple HIG, Layout, "Group related items""you might use negative space, container shapes, or separator lines to show which elements are related and which are unrelated." (three tools, no ranking)nonehttps://developer.apple.com/design/human-interface-guidelines/layout (json mirror .../layout.json)
UIKit UITableView.Styleplain: "Section headers and footers are displayed as inline separators and float when the table view is scrolled." grouped: "sections have distinct groups of rows ... don't float". insetGrouped: "sections are inset with rounded corners".nonehttps://developer.apple.com/documentation/uikit/uitableview/style/plain , /grouped, /insetgrouped (json mirror under tutorials/data/documentation/uikit/uitableview/style-swift.enum/)
UIKit separatorInset"In iOS 7 and later, cell separators don't extend all the way to the edge of the table view." Inset is settable per cell (left/right). The default numbers (15 / 16 / 20 pt) are NOT in the docs text.not statedhttps://developer.apple.com/documentation/uikit/uitableview/separatorinset , /uitableviewcell/separatorinset
UIKit coloursseparator: "thin borders or divider lines that allows some underlying content to be visible" (partly transparent); opaqueSeparator: "always opaque". Light values from a third-party table (not Apple text): separator #3C3C43 at 29 % = #C6C6C8 on white; opaqueSeparator #C6C6C8 (L* 79.9, 1.71:1); dark opaqueSeparator #38383A (1.79:1 on black, 1.45:1 on #1C1C1E); systemGroupedBackground #F2F2F7 (L* 95.6) / dark #000000; secondarySystemGroupedBackground #FFFFFF / dark #1C1C1E.1.71:1 hairline; grouped fill L* 95.6; dark grouped fill is darker than the cardhttps://developer.apple.com/documentation/uikit/uicolor/separator , /opaqueseparator ; values: https://sarunw.com/posts/dark-color-cheat-sheet/
Apple HIG, Scroll views, "Scroll edge effects""provides a visual separation between certain interface elements, such as toolbars, and the scrolling content area behind them"; "Only use a scroll edge effect when a scroll view is behind floating interface elements. Scroll edge effects aren't decorative."; "Apply one scroll edge effect per view."an edge treatment appears only where content passes under a barhttps://developer.apple.com/design/human-interface-guidelines/scroll-views (json mirror .../scroll-views.json)
UIKit scrollEdgeAppearance / standardAppearance"When ... part of the scroll view's content appears underneath the navigation bar. If the edge of the scrolled content reaches that bar, UIKit applies the appearance settings in this property." Default (nil): "the settings found in standardAppearance, modified to use a transparent background." So: at rest the bar is transparent; once content scrolls under it, the standard appearance (background plus default shadow/hairline) takes over. UIBarAppearance.shadowColor: "If this property is nil or contains the clear color, the bar displays no shadow."hairline/shadow only after scrollhttps://developer.apple.com/documentation/uikit/uinavigationbar/scrolledgeappearance , /uibarappearance/shadowcolor
Apple HIG, Navigation barsThe standalone page now returns the HTML shell (404); its content moved to Toolbars ("Reduce the use of toolbar backgrounds ... use a ScrollEdgeEffectStyle when necessary to distinguish [bar from content]"; large title "transitions to a standard title as people begin scrolling").nonehttps://developer.apple.com/design/human-interface-guidelines/toolbars
Material 3 Android docs, Dividers"Dividers are thin lines that group content in lists or other containers"; full width: "separate larger sections of unrelated content. They also separate interactive areas from non-interactive areas."; inset: "separate related content within a section. They are equally indented from both sides"; heavy: "indicating a visual break or stop between major sections in a long page"; item decoration can hide the last divider (lastItemDecorated, default true).thickness 1dp (heavy 8dp); colour colorOutlineVariant (= NeutralVariant80 #CAC4D0, L* 79.9, 1.70:1); insets default 0; heavy example margins 16dp top and bottomhttps://github.com/material-components/material-components-android/blob/master/docs/components/Divider.md ; token files https://github.com/androidx/androidx/blob/androidx-main/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/DividerTokens.kt (Color = OutlineVariant, Thickness = 1.0.dp)
Material Web, Divider"Use full width dividers to separate larger sections of unrelated content." "Use inset dividers to separate related content within a section." "Dividers can reinforce tapability, such as when used to separate list items or define tappable regions in an accordion."--md-divider-thickness: 1px, colour --md-sys-color-outline-varianthttps://github.com/material-components/material-web/blob/main/docs/components/divider.md
Material 1 (archived), Dividers"Dividers help users understand how content is organized by establishing a rhythm and hierarchy on a page. But a heavy use of dividers can lead to visual noise and dilute their impact." "Full-bleed dividers emphasize separate content areas and sections, but if such strong divisions are not required, consider using white space, subheaders, or inset dividers." "When lists don't have an anchoring element such as an avatar or icon, spacing alone isn't always enough to separate tiles. In this case, full-bleed dividers can help create rhythm." Grid lists: "white space and the subheaders separate the sections adequately". Inset dividers "should be used in conjunction with anchoring elements such as avatars" aligned to the Title Key Line. "place the divider above the subheader".1dp, 12 % black (= #E0E0E0 on white, 1.32:1) or 12 % whitehttps://m1.material.io/components/dividers.html (archived; m3.material.io/components/divider/* is script-rendered and unreadable here)
Material 3 top app bar (Android)liftOnScroll default true; liftOnScrollColor default colorSurfaceContainer; AppBarLayout elevation 0dp to 4dp by state; "Upon scroll, it increases elevation and lets content scroll behind it." (lift = tone change in M3 colour-based theming)0dp at rest; container colour changes on scrollhttps://github.com/material-components/material-components-android/blob/master/docs/components/TopAppBar.md
Material 3 Expressive researchcontainment is one of five expressive tools ("grouping like elements together"); "high-contrast visual containment, and other key attributes ... make interfaces better and more usable"; "What works in a media player or email app might not be suitable for something like a banking interface. Product makers need to respect well-established UI patterns." 46 studies, 18,000+ participants, but containment is never isolated as a variable.nonehttps://design.google/library/expressive-material-design-google-research

1b. Research and general design guidance ​

SourceRuleValuesURL
NN/g, Common Region (Krause)boundary (border or background) groups items and "can overpower other grouping principles such as proximity or similarity"; "When possible, using whitespace alone to create clear groupings reduces the visual complexity of a design. Borders are often added in an abundance of caution ... this approach can result in busy, cluttered designs and in many situations it's enough to rely on proximity for grouping."; "segmenting a page into distinct sections can create false floors, and may prevent users from scrolling down the page because they think they've hit the end. This issue is especially common when borders extend the full width of the screen."; "Websites with fixed or sticky headers can especially benefit from using a distinguishing background color or clear border, to effectively separate the header from the page content scrolling below."; test questions: "can I communicate this grouping by simply adding or removing whitespace?"nonehttps://www.nngroup.com/articles/common-region/
NN/g, Proximity (Harley)"Proximity is one of the most important grouping principles and can overpower competing visual cues such as similarity of color or shape."; "Far-away elements appear unrelated"nonehttps://www.nngroup.com/articles/gestalt-proximity/
NN/g, Visual hierarchygrouping "is usually conveyed implicitly through proximity and the use of white space or explicitly through enclosure"; "Consider using a container. If varying whitespace alone is not enough ... add extra elements like borders or backgrounds. These additional elements can create visual clutter, so use them sparingly."nonehttps://www.nngroup.com/articles/visual-hierarchy-ux-definition/
NN/g, Cards"Card layouts are less scannable than lists" (fixed positions make lists more predictable); cards suit heterogeneous items, not similar ones; the common-region principle "frees designers from using negative space"nonehttps://www.nngroup.com/articles/cards-component/
NN/g, Flat UI (Moran 2017)weak signifiers (flat, ghost) cost +22 % time, +25 % fixations (n = 71, 9 sites). About clickability signifiers, NOT separation. Included to stop it being misapplied.https://www.nngroup.com/articles/flat-ui-less-attention-cause-uncertainty/
Primary literatureWertheimer (1923), Untersuchungen zur Lehre von der Gestalt II, Psychologische Forschung 4: 301-350, doi:10.1007/bf00410640 (proximity). Palmer (1992), "Common region: a new principle of perceptual grouping", Cognitive Psychology 24(3): 436-447, doi:10.1016/0010-0285(92)90014-S. Palmer and Rock (1994), "Rethinking perceptual organization: the role of uniform connectedness", Psychonomic Bulletin and Review 1: 29-55, doi:10.3758/BF03200760 (a line or band that connects items is a stronger grouping cue than proximity). DOIs confirmed through Crossref 2026-10-09.https://api.crossref.org/works/10.1007/bf00410640 etc.
Vercel Geist design guide"The page is normally one continuous canvas. Earn a surface or boundary only when it communicates selection, interaction, warning, contrast, or a real grouping that spacing cannot express. Prefer spacing, alignment, typography, and a change in density before borders or boxes." Gap ladder: within-group space-2..4, between-group space-6..8, "major section turns normally space-8..12". Scope is report pages, not mobile lists.gaps 2-4 / 6-8 / 8-12 tokenshttps://vercel.com/design.md
GOV.UK, Section break"By default govuk-section-break is only visible by its margin. You can add the govuk-section-break--visible class to make it visible with a separator line." Sizes: --m = spacing scale 4 (15 px mobile, 20 px tablet+), --l = scale 6 (20 / 30 px), --xl = scale 8 (30 / 50 px), applied top AND bottom; visible line = 1 px solid border colour = black tint-80 #CECECE (L* 82.8, 1.57:1; the older mid-grey #B1B4B6 was 2.08:1); surface light-grey #F3F2F1 (L* 95.5).invisible by default; 1px #CECECE; margins 15-50 pxhttps://design-system.service.gov.uk/styles/section-break/ ; source https://github.com/alphagov/govuk-frontend/blob/main/packages/govuk-frontend/src/govuk/core/_section-break.mixin.scss ; spacing scale settings/_spacing.scss
GOV.UK, Summary listborders "join the information on each row and its action together"; "Think carefully before you remove row borders. Borders help many users find and read information that's laid out in rows, especially users who zoom in on pages or use assistive technologies"; removal only if the list "does not have any actions" (--no-border).https://design-system.service.gov.uk/components/summary-list/

1c. Design systems with published values ​

Contrast is WCAG ratio against #FFFFFF, computed in lane_k/colcalc.py; alpha lines are composited on white.

SystemRow / cell dividerSection / edge dividerBand / fillInsetThicknessSection spacing and notesURL / source
Toss TDS (@toss/tds-mobile 2.5.1)ListRow border: 'indented' (default) or 'none': 1px line drawn at the TOP of each row, margin-left: 24px; width: calc(100% - 24px), i.e. starts at the rail (24) and runs to the right edge (no right inset)Border variant="full" full width; variant="padding24" same indent as ListRowBorder variant="height16": <hr> 16px tall (prop height overrides) on greyBackground #F2F4F6 (L* 96.1, 1.10:1; dark #101013)rail 24 (left only)hairline = SVG tile rgba(0,0,33,0.07) that is 0.5 px tall in a 1px element (= #EDEDEF if full pixel, 1.17:1; half a CSS pixel tall, i.e. about 1 device px at 2x/3x); dark rgba(222,222,255,0.14); token adaptiveHairlineBorder #E5E8EB (L* 91.9, 1.23:1), dark #3C3C47row padding 12 (v) / 24 (h); BottomCTA has a background prop with values 'default' or 'none', doc (Korean, index.d.ts): "none으로 주면 gradient와 배경색이 없어져요" = none removes the gradient and the background colour; the API has no hairline or shadow optiondist/esm/index.js Border (pR map), ListRow ::before; https://tossmini-docs.toss.im/tds-mobile/ ; colours @toss/tds-colors colors.light.css / colors.dark.css
Seed (당근)neutral-subtle stroke = black alpha 0x0C (4.7 %) = #F3F3F3, 1.11:1; dark white alpha 0x0D (5 %)neutral-muted stroke = black alpha 0x10 (6.3 %) = #EFEFEF, 1.15:1; dark white alpha 0x17 (9 %)"8px Gap": basement layer #F3F4F5 (gray-200, L* 96.1, 1.10:1) behind default #FFFFFF; dark basement #000000 behind #16171BFigma-only inset = gutter (16)1px (divider.yaml)Verbatim guidance: three tiers: Inset Divider "약함" (weak, same-group), Full-width Divider "중간" (medium, group boundary, action areas), 8px Gap "강함" (strong, "기존 내용과 크게 구분되는 내용"). "반복되는 레이아웃(예: 리스트)에서는 요소 간 구분이 자연스럽게 이루어지므로 Divider가 필요하지 않을 수 있습니다." (repeating layouts such as lists may need no divider). "마지막 섹션의 Divider는 표시하지 않습니다." (no divider after the last section). neutral-muted is for "한 화면에 한두 번만" (once or twice per screen). ListHeader paddingY 8.https://seed-design.io/llms/components/divider.txt ; tokens https://github.com/daangn/seed-design/blob/dev/packages/rootage/color.yaml
PolarisDivider default border-secondary = gray-7 #EBEBEB (L* 93.0, 1.19:1)same component, borderColor propsurface-secondary #F7F7F7 (L* 97.2)noneborder-width-025 = 1px"color for hr elements or any visual dividers"polaris-react/src/components/Divider/Divider.tsx; polaris-tokens/src/themes/base/color.ts
Carbon (white theme)data-table rows carry bottom borders border-subtleborder-subtle-00 #E0E0E0 (1.32:1); border-subtle-01 #C6C6C6 (1.71:1)layer-01 #F4F4F4 (L* 96.2)none1px@carbon/themes lib/index.js
Fluent 2"Inset dividers don't extend to the edges of a container and imply closer relationships. Use them to group similar items.""Block dividers span the width of their container. Use them to create strict distinctions between items."background3 #F5F5F5 (L* 96.5)strokeWidthThin 1px; Stroke2 #E0E0E0 (1.32:1), Stroke1 #D1D1D1 (1.53:1)"Minimally, default dividers and dividers with content should have 12 pixels of space on top and bottom. Dividers with icons should have 8." "Put the divider above the header"; "Don't underline headers with dividers."https://fluent2.microsoft.design/components/web/react/core/divider/usage ; @fluentui/tokens
Atlassiancolor.border #0B120E24 = #DDDEDD (L* 88.4, 1.35:1)elevation.surface.sunken #F8F8F8 (L* 97.6); surface.container #17171708no Divider component page found (primitives only)@atlaskit/tokens token-default-values.js
Material 3outlineVariant #CAC4D0 1.70:1same; heavy divider 8dpsurfaceContainer* family0 by default1dprows above
AppleopaqueSeparator #C6C6C8 1.71:1samegrouped #F2F2F7per-celldevice hairlinerows above
Bandnone published (three searches, lane H)

Reading across 1c: published ROW hairlines on white are 1.11 to 1.35:1 for the Korean and web-product systems (Seed 1.11, Toss 1.17-1.23, Polaris 1.19, Fluent/Carbon/M1 1.32, Atlassian 1.35) and 1.70-1.71 for the platform systems (Apple, M3, Carbon -01). Published fills for a section band cluster at L* 95.5 to 97.6 (Seed 96.1, Toss 96.1, GOV.UK 95.5, Apple 95.6, Carbon 96.2, Fluent 96.5, Polaris 97.2, Atlassian 97.6). Published band HEIGHTS are few: Toss 16, Seed 8, Material heavy 8dp. Two systems say in words that a section/zone divider is stronger than a row divider (Seed's three tiers; M3 heavy; Fluent block vs inset).


2. Peer measurement table (22 screens, 15 apps) ​

How measured (details in section 6): each frame is an App Store marketing screen on disk; the screen's width is found from the widest canvas-coloured run through the centre, pt = px / (screen width px / 390) (393 for Dynamic-Island mocks). strip2.py finds the longest single-colour horizontal run per row (lines, bands, insets); seam2.py and gaps.py give content/whitespace segments; classification by eye on a hi-res crop of every frame (crops in lane_k/crops/). "Hairline" = the darkest row of a thin line (peak). Because frames are down-scaled, a 1px line is smeared over 2-3 rows, so the peak is a lower bound on the line's true darkness (section 6). LH = value taken from lane H (lane-h-flat-lists-and-blocks.md), not re-measured.

Whitespace figures are INK to INK (bottom of the last visible element to the top of the next) unless noted; our grammar numbers are box to box, so add the line-box slack (about 3.5 pt per side for 17/24 text) and the row padding when comparing (section 4, rule 3).

Column key: surface = what the page is made of (F = flat on white, C = cards/containers on a tinted or white ground).

#App · screenSurfaceRow to rowSection to sectionHero/block to listSticky edgeHairline: hex · L* · CR · thickness · insetBand (pt, colour)Whitespace (pt)Frame (scale px/pt)
1Toss · 증권 홈Fn/a (1 row in frame)whitespace + 17/700 titlenumeral block to controls 21.0, to sub-title 36.0, to first row 26.5tab row: full-bleed hairline under it#D3D7DC peak · 85.8 · 1.45 · about 1 pt · full-bleed (0/0)none55.8 (tiles to "내 투자"), 36.0 (controls to "해외주식"), 31.2 (tab hairline to first title)hi/839333328_2 (2.723)
2Toss · 혜택Fnone (56 pt discs, pitch 72.8, air 16.9)n/atitle to first row 27.6nonenonenone16.9 between rowshi/839333328_5 (2.721)
3Toss · 홈C on tintnone inside card (1 hairline above footer link, LH)card gap on tintheader card to next card 10.7-11.4 (LH 9.2)none at restLH onlygap #EBEFF1 · 94.2 · 1.1610.7-11.4hi/839333328_0 (2.723)
4카카오뱅크 · 내 계좌Fnone (disc 37, pitch 64.6, air 27.6)n/anumeral to inset hairline 25.6, hairline to first row 25.6tab row: 2 pt ink indicator only, no full-width line#E6E6E6 · 91.3 · 1.25 · 0.8 pt · inset 19.5 / 19.9 (= rail)none25.6 above and below the linehi/1258016944_2 (2.462)
5카카오뱅크 · miniCnone (pitch 62.6)card gappale hero to first card 9.4 (LH)floating pill tab bar, soft shadownonegap on near-white (#FAFAFA events)9.4 (LH)hi/1258016944_7 (2.259)
6카카오페이 · 포인트C on tintnone (37 pt disc + chevron, pitch 72.8)card gap3-tile card to list card 7-8nonenonecanvas #F3F4F5 · 96.1 · 1.10; gap 7.2-7.67.2-7.6hi/1464496236_7 (2.226)
7카카오페이 · 보험진단Fn/afull-bleed grey band between hero zone and next section, with whitespace on both sideshero block to band 33, band to next section label 37tab row: full-bleed hairline + 2 pt indicator#EDEFF0 peak · 94.3 · 1.15 · about 1 pt · full-bleed#F2F4F4-#F4F5F6 · 96.0-96.5 · 1.09-1.10 · 13.1 pt33 above, 37 below the bandhi/1464496236_5 (2.221)
8당근 · 피드Finset hairline (photo 116, pitch 150.5)n/achips to first photo 16 (LH)none under header or chips#F2F3F6 · 95.8 · 1.11 · 0.9-1.4 pt · inset 16.0 / 16.5nonen/ahi/1018769995_1 (2.187)
9당근 · 당근페이C on tintinset hairline inside card (24.2 / 23.3)card gapbalance card to icon row 31 (LH)none#EFEFEF · 94.4 · 1.15 · 1.4 ptgap #F7F8F9 · 97.5 · 1.06 · 9.1-10.19.1-10.1hi/1018769995_7 (2.187)
10네이버 · 마이C on tintinset hairline (photo 88, pitch 112 LH)card gaptab row to first row 128 incl. notice (LH)floating pill nav, soft shadow#E5E5E5 · 90.9 · 1.26 · 1.5 pt · inset 19.2 / 21.6gap #EDF0F4 · 94.7 · 1.14 · 12.312.3hi/393499958_6 (2.036, edges estimated)
11카카오톡 · 친구Fnone (avatar 48, pitch 65.4, air 20.0)whitespace + 15/700 title with collapse chevrongrey info card #F3F3F3 to title 27.7; title to first row 19.1 (avatar strip 16.3)none; white tab bar, no edgenonenone35.0 (row to title), 39.9 (avatar strip to title)hi/362057947_5 (2.203)
12배민 · 배민클럽Ffull-bleed hairline (photo 121, pitch 162 LH)n/abanner to "기본순" label 45 (LH)tab row: full-bleed hairlinerows #F2F4F6 · 96.1 · 1.10 · 1.3 pt · full-bleed; tab row #D4D3D4 · 84.7 · 1.49nonen/ahi/378084485_2 (2.303)
13Band · 홈C on #F8F9FAn/a (tile grid)feed section header with full-bleed hairline under ittile grid to action card to headertab bar: 1px top hairline + tint #F7F7F7#EBEBEB · 93.0 · 1.19 · 1 pxnonen/alane_h/hi/542613198_2 (2.495)
14테니스프렌즈 · 내 정보C on tintinset hairline in card (48.0 pitch, 24 pt glyph + chevron)label on grey canvas 30 above (LH), cardlime card to tiles 21, tiles to label 30 (LH)tab bar: full-bleed top hairline#E6E5EA · 91.1 · 1.25 · 1.26 pt · inset 19.5 / 20.5canvas #F8F9FB · 97.9 · 1.05n/alane_h/hi/6758872979_5 (3.185)
15테니스프렌즈 · 홈C on tintone card per item (105 pt)card gap 32 (LH)greeting/banner to cardtab bar hairline (as 14)as 14canvas #F8F9FB32 (LH)lane_h/hi/6758872979_3 (3.185)
16Munto · 소셜C on tintone card per item (r about 16)card gapnonenonenonegap #F4F4F4 · 96.2 · 1.10 · 15.815.8lane_k/hi/1535886772_3 (2.726)
17Munto · 플레이스Fnone (poster rows 117.4 pt tall, air 15.4, pitch 132.8)n/atab text to line 10.6, line to chips 14.3, chips to first row 15.4tab row: inset hairline under it#F4F4F4 · 96.2 · 1.10 · 1.1 pt · inset 11.4 / 12.1none10.6 / 14.3 / 15.4lane_k/hi/1535886772_4 (2.726)
18Monzo · 홈C (white card on white)inset hairline in card (pitch 62, logo 32)card gap 25 (LH)red card to Activity card 25 (LH)none#E7E8EA / #E1E2E4 / #EDEDEF / #ECEEED · 92.0 / 89.9 / 93.8 / 93.9 · 1.23 / 1.30 / 1.17 / 1.17 · 0.6-1.1 pt · inset 31.4 / 31.4none25 (LH)frames_c/monzo/1052238659_0 (1.781, 393)
19Cash App · MoneyC on tintone in-card divider in the CANVAS colourcard gapcard to card 24.6 (LH)none#EFEFEF · 94.4 · 1.15 · 1.3 pt (equals canvas)canvas #F0F0F0 · 94.8 · 1.1424.6 (LH)frames_c/cashapp/711923939_0 (2.326, 393)
20Playtomic · clubFn/an/aphoto to title 30, title to tabs 45 (LH)tab row: full-bleed hairline (blurred)#F4F5F6 peak · 96.5 · 1.09 · full-bleednonetabs to date strip 22 (LH)frames_c/playtomic/1242321076_4 (2.336, 393)
21Wise · 홈Fnone (pitch 81)whitespace (segmented to rows 56, LH)nonenonenone found by line scannone40-56 (LH)frames_c/wise/612261027_0 (1.522, 393, low-res)
22Revolut · InvestC (dark card on black)none (pitch 79.6)n/agradient hero to list 34 (LH)nonenone foundcard #1A1A1A (L* 9.3) on black34 (LH)frames_c/revolut/932493382_6 (2.351, 393)

Bottom bars seen in these frames (static, scroll-top state): 테니스프렌즈 and Band draw a 1px top hairline on the tab bar (#E6E5EA 1.25; #EBEBEB 1.19) and Band tints the bar #F7F7F7; 당근, 카카오뱅크 (홈 and mini) and 네이버 float a pill bar with a soft shadow; 카카오톡 draws nothing (white bar, rows cut by it; profile of the boundary rows shows white to white).


3. Counts ​

Denominators are the screens in section 2 that show the thing counted.

QuestionCount
Surface: flat on pure white vs containers (cards on a tint, or card on white / dark)flat on white 10 of 22 (Toss 증권, 혜택, 카카오뱅크 내 계좌, 카카오페이 보험진단, 당근 피드, 카카오톡, 배민, Munto 플레이스, Playtomic, Wise); containers 12 (Toss 홈, 카카오뱅크 mini, 카카오페이 포인트, 당근페이, 네이버, Band, 테니스프렌즈 x2, Munto 소셜, Monzo, Cash App, Revolut), 9 of them on a tinted canvas (L* 94.2-97.9)
(a) Row to row (17 screens that show consecutive rows)none (spacing only) 9 (53 %): Toss 혜택, 카카오뱅크 x2, Toss 홈, 카카오페이 포인트, 카카오톡, Munto 플레이스, Wise, Revolut; inset hairline 5 (29 %): 당근 피드, 당근페이, 네이버, 테니스프렌즈 내 정보, Monzo; full-bleed hairline 1 (6 %): 배민; card per row 2 (12 %): 테니스프렌즈 홈, Munto 소셜
(a') what predicts a row line8 of the 9 no-line lists have a leading visual of 56 pt or less (disc 30-56, avatar 48) and two text lines; the 9th is Munto 플레이스 (poster-led rows 117 pt tall, air 15.4, no line). Lines appear on photo-led rows of 88-121 pt in 3 of 4 cases (당근 116, 네이버 88, 배민 121; Munto 117 is the exception) and on rows inside a white card: single-line settings rows with a 24 pt glyph (테니스프렌즈, 48 pitch) and transaction rows (Monzo, 당근페이). Hairline rows measured 48-62 or 112-162 pitch; none of the 64-81 pitch two-line rows with a 30-56 pt anchor draws one
(b) Section to section (screens with 2+ sections)without containers: whitespace + title 3 (Toss 증권, 카카오톡, Wise), full-bleed grey band 1 (카카오페이 보험진단), full-bleed hairline under a section header 1 (Band, a header underline, not a seam between sections); gap between containers on a tint 10 (Toss 홈, 카카오뱅크 mini, 카카오페이 포인트, 당근페이, 네이버, 테니스프렌즈 x2, Monzo, Cash App, Munto 소셜). Zero flat peers use a hairline between ordinary sections
(c) Hero or block to listspacing only 8 of 10 where measured (Toss 증권, Toss 혜택, 카카오톡, 당근페이, Monzo, Cash App, 테니스프렌즈, Revolut); a hairline after a summary numeral 1 (카카오뱅크 내 계좌; no brand block); a band 1 (카카오페이 보험). Distances: 21 / 24.6 / 25 / 25.6 / 27.6 / 27.7 / 31 / 34 pt, median 25
(d) Underline-tab row to content (6 screens with one)full-bleed hairline directly under 4 (Toss 증권 1.45, 배민 1.49, 카카오페이 보험 1.15, Playtomic 1.09 as measured); inset hairline 1 (Munto 1.10); none, indicator only 1 (카카오뱅크). Gap below: 22 (Playtomic), 31.2 (Toss)
(d') Plain header (no tabs) bottom edge at scroll-topno line 8 of 8 (카카오톡, 당근, Band, 카카오뱅크 홈, Toss 홈, 테니스프렌즈, Monzo, Munto 소셜). The frames cannot show the scrolled state
(d'') Tab bar top edge1px hairline 2 (Band, 테니스프렌즈), floating pill with shadow 3 (당근, 카카오뱅크, 네이버), nothing 1 (카카오톡)
Hairline contrast on white, ROW hairlines (n = 8)CR 1.10-1.26, median 1.19, L* median 93.0 (about #EBEBEB)
Hairline contrast, TAB-ROW / edge lines (n = 5, sharpest first)1.49 (배민), 1.45 (Toss), 1.15, 1.10, 1.09 (the last three are blurred, lower-resolution frames); the two sharp ones are the darkest
Band / canvas tint (n = 10 measured, 7 published)measured L* median 96.2 (94.2-97.9); published median L* 96.1 (95.5-97.6); #F2F2F2 is L* 95.5
Band / container-gap height7.2-7.6 (카카오페이), 9.1-10.1 (당근페이), 9.4 (카카오뱅크), 10.7-11.4 (Toss), 12.3 (네이버), 13.1 (카카오페이 full-bleed band), 15.8 (Munto), 24.6-25 (Cash App, Monzo); published 8 (Seed, M3 heavy), 16 (Toss); median of all 12 values 11.7 pt
Whitespace between flat sections, ink to ink27.7, 31.2, 35.0, 36.0, 39.9, 45, 55.8; median 36 pt
Hairline inset (measured, symmetric to the rail)카카오뱅크 19.5/19.9, 당근 16.0/16.5, 네이버 19.2/21.6, 테니스프렌즈 19.5/20.5 (all 4 flat-peer cases: inset to the rail, both sides; Monzo 31.4/31.4 = card padding); Toss TDS component default is rail on the left and bleed on the right

4. The rules for us (C), each tied to its evidence ​

Definitions: row hairline = the quiet tier (cells, rows); edge hairline = the stronger tier (tab row, sticky bar edges, the one-or-two-per-screen boundaries); band = full-bleed fill; rail = 20.

Summary of the answer to "are we adding dividers?": default is no. Space carries the separation; three exceptions earn a line, and one earns a band.

Rule 1. Media rows (80) and person rows (64): no separator ​

  • Final: no hairline, no band, no card. Row air stays the 24 that comes from 12 + 12 padding (peer air 16.9 to 27.6). The last row never ends in a line.
  • Evidence: 9 of 17 peer lists have none and they are exactly the lists built like ours (two lines, anchor 30-56, pitch 59-81: Toss 혜택/홈, 카카오뱅크, 카카오페이, 카카오톡, Wise, Revolut); hi/839333328_5, hi/1258016944_2, hi/362057947_5. Seed: "반복되는 레이아웃(예: 리스트)에서는 ... Divider가 필요하지 않을 수 있습니다" and its Don't image for dividers between list items (https://seed-design.io/llms/components/divider.txt). Material 1: anchored lists (avatar/icon) are the case where spacing is enough; it recommends lines only for "items without anchors". NN/g common region: "using whitespace alone ... reduces the visual complexity". Proximity test: the thumb or avatar sits 12 from its text while the next row is 24 away, so grouping is already vertical-by-row.
  • Confidence: high for 64-80 pitch with a 40-56 anchor. The one counter-case in the set is not ours (Munto 플레이스 is a no-line poster list at 133 pitch, 117 pt rows).

Rule 2. Dense label/value cells (48, no thumb): inset hairline, to the rail ​

  • Final: 1px row hairline between adjacent cells, inset to the rail on both sides (20 / 20), none above the first or below the last cell. If a cell ever has an avatar, inset to the text start (20 + 40 + 12 = 72) as Material 1's "Title Key Line" and Apple's default do, but our rule 1 means avatar rows carry no line.
  • Applies to: 정보 block, settings, dues ledger rows that are single-line.
  • Evidence (thinner than rule 1; say so): the only flat-peer measurement of single-line label rows is 테니스프렌즈 내 정보, pitch 48.0, 24 pt glyph + chevron, inset hairline 19.5 / 20.5 (lane_h/hi/6758872979_5, #E6E5EA 1.25:1). Documentation: Material 1 "When lists don't have an anchoring element ... spacing alone isn't always enough ... full-bleed dividers can help create rhythm"; GOV.UK summary list borders "join the information on each row and its action together" and removal is allowed only "if your summary list does not have any actions"; Carbon data-table rows carry border-subtle bottoms (lane F); Fluent: inset dividers "imply closer relationships ... group similar items"; Toss TDS ListRow defaults to an indented 1px line. Measured insets are to the rail in 4 of 4 flat cases, symmetric.
  • Mechanism, not proof: in a label-left, value-right cell the two items are 200+ pt apart while the next cell is 24 below, so proximity groups the columns, not the row (NN/g Proximity: "far-away elements appear unrelated"); the line restores the row. The mechanism does NOT apply to two-line rows with an anchor and a trailing pill, which peers leave line-free (rule 1).
  • Open decision for the owner: the club-detail canon today says "no divider" for cell rows (grammar section 4); this rule reverses it for single-line cells only. Cheapest check: one task test ("find 참가비", "find the unpaid member") with and without, on the web rung; no published study decides it (section 5).

Rule 3. Section to section: whitespace 32 + title; a band only for a zone change ​

  • Final: ordinary sections = 32 of whitespace, then the 17/24-600 title, 8 below it (the grammar's ladder, unchanged). Measure the 32 from the last row's content bottom (thumb or text), i.e. the last row drops its bottom padding; then ink to ink is about 32 + 3.5 = 35.5 pt, on the peer median of 36. If the 32 is stacked on the 12 row padding it becomes about 47 ink to ink, beyond every peer but Toss's 55.8.
  • Band = full-bleed 12 pt, #F2F2F2 with 24 of whitespace above and 24 below (the one measured peer keeps 33 above and 37 below its 13.1 pt band; a band is an extra signal on top of air, not a replacement for it), reserved for a change of KIND of content (see rule 6), at most one per screen, never between two ordinary list sections, never at the last section (Seed: "마지막 섹션의 Divider는 표시하지 않습니다").
  • No hairline between ordinary sections.
  • Evidence: flat peers separate sections with whitespace + title: Toss 증권 55.8 / 36.0 / 31.2, 카카오톡 35.0 / 39.9 (hi/839333328_2, hi/362057947_5); zero flat peers use a line between sections. Band precedent is a single measured screen (카카오페이 보험진단, 13.1 pt, #F2F4F4-#F4F5F6, 33 above and 37 below) plus published bands (Toss Border height16 default 16 on #F2F4F6; Seed 8px gap on #F3F4F5; M3 heavy divider 8dp "visual break ... between major sections in a long page"). The median of every band or container gap found is 11.7, hence 12 on the 4pt grid. Seed's own table is the best statement of the ladder: inset line = weak, full-width line = medium, 8px band = strong (https://seed-design.io/llms/components/divider.txt). NN/g: boundaries "can overpower" proximity and full-width ones create "false floors", so keep the band thin and make sure a title or content peeks within the viewport below it. GOV.UK keeps its section break invisible by default and visible only on request.
  • Why 12 and not 8 or 16: 12 is the measured median; 8 reads as a gap between cards (it IS the card gap in Seed/당근페이); 16 equals Toss's default and Munto's card gap but costs a full 16 of a 844 screen; both are acceptable, 12 is the evidence-weighted pick.

Rule 4. Block or hero to content: spacing only, 24 ​

  • Final: 24 from a brand block (144/158) to the next section header or first row; no hairline, no band. Hero (detail page) to first section stays 32 (grammar).
  • Evidence: block/summary to list distances measured in peers: 21 (테니스프렌즈), 24.6 (Cash App), 25 (Monzo), 25.6 (카카오뱅크 numeral to line, line to row), 27.6 (Toss 혜택 title to first row), 27.7 (카카오톡 card to title), 31 (당근페이), 34 (Revolut), median 25 (LH and section 2). A coloured fill is already a common region (NN/g), so a line after it repeats the boundary (Vercel Geist: "Earn a surface or boundary only when it ... spacing cannot express"). The one hairline-after-summary peer (카카오뱅크 내 계좌) has a plain numeral, not a coloured block, and still leaves 25.6 on both sides of the line.
  • Confidence: high.

Rule 5. Sticky header, tab row, tab bar, CTA band: one edge hairline, only where content passes under it ​

  • Final: edge hairline #D4D4D4 (S2 value, 1.48:1), 1px, full-bleed.
    • Header: transparent/white at scroll offset 0, hairline fades in once content scrolls under (UIKit scrollEdgeAppearance transparent at rest, standardAppearance when content reaches the bar; M3 liftOnScroll).
    • Underline tab row: hairline always present directly under the tab row (peers 4 of 6 full-bleed; the two sharpest measure 1.45 and 1.49, = #D4D4D4); the 2 pt ink indicator sits on it.
    • Tab bar and bottom CTA band: hairline on top while more content lies below the bar (scroll end reached = no line), as the grammar already says for the CTA.
    • No shadow anywhere (ours is a ban; peers' shadows exist only on floating pill bars: 당근, 카카오뱅크, 네이버).
  • Evidence: Apple HIG scroll edge: "Only use a scroll edge effect when a scroll view is behind floating interface elements. Scroll edge effects aren't decorative."; NN/g common region: sticky headers "benefit from ... a clear border" to separate from content scrolling below; M3 lifts the top bar (0 to 4dp) only on scroll. Tab-row lines: hi/839333328_2 (#D3D7DC, 1.45), hi/378084485_2 (#D4D3D4, 1.49). Toss's bottom CTA is documented as having a gradient plus a background colour by default and no line option (TDS BottomCTA prop background, 'default' or 'none', index.d.ts; I did not render it); a gradient is not a shadow, but we keep the hairline as the grammar says.
  • Limits: all 22 frames are static; whether peers add the line only when scrolled cannot be seen. At scroll-top none of 8 plain headers shows a line.

Rule 6. Zone changes on a detail page ​

  • Hero zone to content zone: whitespace 32 (hero 32 below, as in the grammar); no band. Hero and content are one reading flow, same canvas.
  • Content to comments (or any user-generated stream, or a footer zone): 24 whitespace, 12 pt band #F2F2F2, 24 whitespace, then the comments title (peer: 33 / 13.1 / 37). The band says "different kind of material", which whitespace alone does not.
  • Content to the bottom CTA band: whitespace 40 then the edge hairline when content scrolls under it (rule 5).
  • Evidence: 카카오페이 보험진단 uses a full-bleed band exactly between a summary hero zone and the analysis zone (hi/1464496236_5); Seed ranks the 8px gap as the "strong" tier for "기존 내용과 크게 구분되는 내용"; M3 heavy divider; Toss Border height16 is the same device. For hero to content, Toss 증권 and 카카오톡 use whitespace. Confidence: medium (one measured band screen, three published bands); the comments case is an extrapolation from "different kind of material".

Rule 7. Tabs row to content ​

  • Final: full-bleed edge hairline under the tab row (rule 5), then 24 to a section title or 16 to a day header/row. The grammar's 16 below tabs is on the low side of the peers: Toss 31.2 ink to ink (about 28 box to box) to the first title, Playtomic 22 to the date strip (LH). With the new hairline, 24 before a title keeps the ink distance near 27, inside 22-31.
  • Evidence: counts (d); hi/839333328_2, hi/378084485_2; Fluent: "Use dividers along with spacing and headers".

Rule 8. Last row to tab bar ​

  • Final: nothing extra. List tail 48 (canon) then the bar; the bar's own top hairline (rule 5) is the only line. No line above the bar when the list has reached its end.
  • Evidence: in all 6 frames that show a bar under a list, no peer draws a separator between the last row and the bar; 카카오톡's white bar has no edge at all (boundary profile white to white), Band and 테니스프렌즈 draw only the bar's own top line (#EBEBEB 1.19, #E6E5EA 1.25), three peers float a pill.

Rule 9. S2 values, peer range, and dark mode ​

Token (proposal)ValueLight check against peersDark equivalent
Edge hairline#D4D4D4, L* 84.9, 1.48:1, 1pxmeasured sharp tab/edge lines 1.45-1.49 (Toss, 배민); published section/edge lines 1.35-1.71 (Atlassian 1.35, Fluent Stroke1 1.53, GOV.UK 1.57, M3 1.70, Apple 1.71). In range, matches the sharpest measured peers. Heavier than every measured Korean ROW line (1.10-1.26).white at alpha 0.14 over the canvas: on #15181A = #36383A (1.51:1). Same as Toss TDS dark rgba(222,222,255,0.14); Apple dark #38383A on #1C1C1E is 1.45
Row / cell hairline (new, quieter tier)#E5E5E5, L* 91.3, 1.26:1, 1pxmeasured row lines median 1.19 (range 1.10-1.26): #E5E5E5 is the heaviest peer (네이버 #E5E5E5); published row lines 1.11-1.35 (Toss #E5E8EB 1.23, Polaris 1.19, Fluent 1.32). Using #D4D4D4 for rows would be 0.2 darker than the heaviest measured row peer.white at alpha 0.09: on #15181A = #2A2D2F (1.29:1); Seed dark muted is alpha 0.09
Band#F2F2F2, L* 95.5, 1.12:1, 12 ptmeasured L* median 96.2 (94.2-97.9); published median 96.1 (GOV.UK light-grey 95.5, Apple grouped 95.6, Toss and Seed 96.1). At the median.darker than the canvas, not lighter: Toss #101013 under #17171C (dL* -3.5), Seed #000000 under #16171B (-7.6), Apple #000000 under #1C1C1E (-11.2). On an ink canvas #15181A (L* about 9) use #000000 (dL* -9). On canvases darker than L* 6 a band is invisible: use the edge hairline instead.
Hairline thickness1 css px on web; one device pixel on native (Apple draws 1/scale; Toss TDS Border is a 0.5px-tall tile); never 2peers measured 0.8-1.5 pt after blursame
Insetsrow hairline 20 / 20 (rail, both sides); edge hairline and band full-bleed (0 / 0)measured 16-21.6 symmetric; TDS component differs (left rail, right bleed)same
Seamsblock to content 24; section 32 (from content bottom); title to first row 8; band 12 with 24 above and 24 below; tab row to title 24, to row 16section 2 and rules 3-7same

The one-line test for a developer ​

Delete the line and keep the gap: would the two things still read as two groups? If yes, no line. A line is allowed only for (1) an edge where content scrolls under a bar or tab row, (2) a single-line label/value cell group with no thumb, (3) a change of kind of content, which gets the 12 pt band instead of a line.

Shorter, for the PR checklist: space first; edge hairline for sticky edges and tab rows; quiet inset hairline for single-line cells; 12 pt band for a zone change; nothing else.


5. What the research does NOT support ​

  • No controlled study that dividers, bands or whitespace change scanning speed or accuracy on mobile lists. A search for one found only indirect work (a desktop eye-tracking study of whitespace in text: no effect on speed or memory; separated vs continuous lists, Seki, with no rule-vs-space split; Enders 2008 zebra stripes: no accuracy effect, from lane F). Every "best practice" above is design-system guidance (Seed, Material, Fluent, GOV.UK) or Gestalt theory (Wertheimer 1923, Palmer 1992, Palmer and Rock 1994), not an experiment on lists.
  • The wording "use dividers sparingly" is not verified from the current M3 spec: m3.material.io is script-rendered and returns no text. The sentences I could read are in Material 1 (archived), the Material Web docs and the Android docs. "Heavy use of dividers can lead to visual noise" is M1.
  • No evidence for 32 vs 36 vs 40 as an optimum. The peer median is 36 ink to ink; 32 is defensible only with the box-to-box definition in rule 3.
  • No evidence for 12 vs 8 vs 16 as the optimum band; 12 is a median of 12 mixed values (7.2 to 25) from card gaps, one band and three published bands.
  • "Hairlines help money lists" is convention (GOV.UK, Carbon, Material 1), not proof; lane F already said so. This lane found no new evidence.
  • Hairline "perceptibility" thresholds: choosing 1.26 vs 1.48 is a peer/convention choice, not a perception requirement (lane E: even 1.26 is multiple times the modelled threshold).
  • False floors (NN/g) are qualitative; no number for how thin a band avoids them. 12 pt with a title peeking is a judgment.
  • Header hairline only when scrolled: documented by Apple (scrollEdgeAppearance) and Material (liftOnScroll); the marketing frames cannot confirm what the peers do. A hairline vs a tone change (M3's lift colour) is not decided by any source.
  • Dark-mode bands: three systems (Toss, Seed, Apple), all darker-than-canvas; none published for an ink canvas.
  • M3 Expressive's containment finding points the other way (more containment, up to 4x faster key-element spotting, where "key elements" were buttons, not rows) and never isolates containment. It also says banking-style UIs should respect established patterns. It does not argue against flat lists; it is not evidence for cards in them either.
  • Vercel Geist's "prefer spacing" rule is stated for report pages, not mobile apps.
  • NN/g has no article titled "use whitespace before lines"; the sentence closest to it is the Common Region caution quoted in 1b.
  • Apple's numeric defaults for separator inset and margins (15 / 16 / 20) are not in the HIG or UIKit text I could fetch.
  • Toss Border usage in the app is inferred from the package, not seen in a frame; no peer frame shows a Toss height16 band.

6. Caveats ​

  • Frames are vendor App Store marketing images (selection bias, staged data, dates 2025-04 to 2026-10), at scroll-top, so sticky behaviour is not observable. Mock-up frame edges are read from rounded outlines; Naver (393499958_6) and Wise are estimated or low-resolution.
  • Scale = measured screen width / 390 pt (393 pt for Dynamic-Island mocks: Monzo, Wise, Revolut, Cash App, Playtomic). 테니스프렌즈 is full-bleed 1242 px / 390 = 3.185 (a 414-pt device would be 3.0, so values can be up to 6 % high). 당근 uses the white screen width inside the bezel (853 px, 2.187 px/pt), 3 % off lane H's 2.26 that included the bezel outline. Error budget: +-2 pt on sizes below 60 pt, +-4 % on pitches.
  • Hairlines are blurred by the down-scale (about 0.9x) and by compression: a 1px line spreads across 2-3 rows, so the peak is a lower bound on darkness (true lines are as dark or darker). The ranking of hairline darkness (sharp tab/edge lines 1.45-1.49 vs row lines 1.10-1.26) survived because I compared only like with like; the three lighter tab-row values (카카오페이 1.15, Playtomic 1.09, Munto 1.10) come from softer frames and should be read as 1.1+.
  • Whitespace is ink to ink; our grammar is box to box. 17/24 text has about 3.5 pt of slack above and below its ink, and rows add 12 padding unless the edge rule removes it (lane H section 3.4: first/last row drop their outer padding).
  • The Toss TDS half-pixel hairline is a 1x1 SVG tile with a 0.5-tall rect inside a 1px element: on a 1x display it composites as half intensity (about #F6F6F7, 1.08:1), on 2x/3x as a crisp 1 device px at 7 % alpha (#EDEDEF, 1.17:1). That is why app frames show Toss hairlines lighter than #E5E8EB.
  • adaptiveHairlineBorder #E5E8EB and greyBackground #F2F4F6 are TDS token values; the app may differ (lane H confirmed 17/13 text, 24 padding, 30 pt icons agree).
  • Apple colour values come from a third-party table (sarunw.com); Apple's own colour pages are script-rendered.
  • Gestalt DOIs checked via Crossref; Wertheimer's text itself was not read.
  • Counts mix measured (this lane) and LH values where marked; 22 screens is a convenience sample of the frames on disk, not a random sample. Revolut, Wise and Cash App row structure is from lane H.
  • No sub-agents, no git writes, nothing under the repo modified. Files written: this note, bench/lane_k/* (helpers, crops, contact sheets, src/ fetched sources including src/tdscol/, src/pk/ npm packs), and 8 Munto hi-res frames at bench/lane_k/hi/1535886772_*.png (public App Store images, fetched with fetchhi.py).

Appendix: files ​

  • Contact sheets of the 8 clearest seam examples: bench/lane_k/contact-seams-8.png (one row, 5359 x 924), contact-seams-8a.png (Toss 증권 tab hairline + whitespace, 카카오뱅크 inset hairline, 카카오톡 whitespace sections, 카카오페이 tab hairline + grey band), contact-seams-8b.png (당근 inset hairlines, 배민 full-bleed hairlines + tab line, 네이버 cards on tint + inset hairlines, 테니스프렌즈 in-card hairlines + tab bar line). Crops: bench/lane_k/crops/seam1..8_*.png.
  • Helpers: lane_k/strip2.py (row events), seam2.py (content/whitespace segments), gaps.py (column runs), colcalc.py (L*, WCAG ratio), sheet.py, crop.py, edges.py, hig_text.py (Apple JSON to text), h2t.py (HTML to text).
  • Sources fetched: lane_k/src/ (Apple JSON, M3/GitHub md, Seed color.yaml and divider doc, GOV.UK, NN/g, Vercel, TDS colours, Polaris, Carbon, Fluent, Atlassian tokens).

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