Skip to content

Lane E — perceptual science behind the surface, block and ink proposals (2026-10-09) ​

Status: Reference · Date: 2026-10-09 · Evidence appendix for colour-system-research-2026-10-09.md. Scripts and computed tables referenced by path live in the session scratch directory (not committed); formulas are in the note's computed-evidence section.

Scope: docs/design/research/visual-benchmark-2026-10-08.md §3 and §5 and board /wireframes/visual-tone T0–T7. All numbers below were computed with bench/colour_lab.py (Lc, WCAG, CIELAB, ΔE2000) plus scripts in bench/lane_e/ (apca_lut.py, calc_apca.py, calc2.py, calc3.py, calc_hair.py, calc_dark.py, csf.py). English only.

Three method notes before the table:

  1. The helper's APCA font table is wrong. colour_lab.apca() (the Lc number) is fine. colour_lab.apca_font_need() is not: it does not match the published lookup (Myndex apca-w3, data/LUT-GseriesMay28-2022.js, the latest published table). Example, minimum px by weight 400/500/600/700: helper at Lc 90 = 14/13/12/11.5, published = 16/15.5/14.5/14; helper at Lc 60 = 21/18/16/15, published = 24/21/18/16; helper at Lc 45 = 28/24/21/18, published = 42/32/28/24; helper at Lc 30 = 42/36/32/28, published = 108/108/96/72. Anything in lanes A-D that used apca_font_need is too lenient by 2-66 px. I did not edit colour_lab.py; this report uses lane_e/apca_lut.py, which loads the published numbers. Source: https://raw.githubusercontent.com/Myndex/apca-w3/master/data/LUT-GseriesMay28-2022.js and https://github.com/Myndex/apca-w3
  2. APCA is a gauge, not a standard. The WCAG 3 Editor's Draft of 2026-04-08 still says "The contrast algorithm used in WCAG 3 is yet to be determined"; APCA was removed from the July 2023 working draft; its author calls it "draft guidance we are actively testing" and says independent validation exists, which I could not locate (no peer-reviewed validation found in my searches). https://adrianroselli.com/2026/04/wcag3-contrast-as-of-april-2026.html . WCAG 2.2 AA (4.5:1) remains the compliance test. APCA is also very strict at small sizes (14/500 needs Lc 100-105 even for "content" text), so below I use it as a relative ranking and report WCAG next to it.
  3. Sources I could not read (JavaScript-rendered, returned only the page title): m3.material.io colour-roles / science-of-colour / tone-based-surfaces pages, m2.material.io dark-theme page, Apple HIG colour page. For Material I therefore computed the tonal ladder from the reference implementation (materialyoucolor 3.0.4, a port of https://github.com/material-foundation/material-color-utilities, spec_version='2021', seed #006D37) and cite the library, not the spec page.

1. Verdict table ​

Verdict key: KEEP = evidence supports the board value; ADJUST = keep the direction, change the value; DROP = evidence does not support the claim (remove the claim or the rule). Evidence column carries the URL; numbers are measured or computed unless marked "(secondary)".

Proposal 1 — Two grounds (basement #F0F7F3 under white cards; white lists with hairlines) ​

#Claim as the board makes itWhat the research says (numbers, URL)VerdictFinal value / reason
1.1#F0F7F3 (L* 96.6, ΔL* 3.4, 1.09:1) is a comfortably noticeable step under white cardsColour difference: card vs basement ΔE76 4.67 / ΔE2000 4.66 = 2.0x the JND of 2.3 ΔEab and inside the "3.5-5: clear difference" band (scale from Mokrzycki & Tatol 2011, https://colour.readthedocs.io/en/master/generated/colour.difference.JND_CIE1976.html). Today's #F8FBF9: ΔE76 2.21 = 0.96x JND, i.e. the current card step sits exactly at threshold, which is why it reads as one flat sheet. Edge detectability (own implementation of the Barten 1999 CSF, https://doi.org/10.1117/3.353254 , large-field 1 cpd): proposed step is a 4.4% Michelson edge = 5.3x threshold at 300 nits / 0 lux, 3.2x at 500 nits / 20,000 lux, 2.0x at 1,000 nits / 100,000 lux; today's canvas 2.6x / 1.6x / 1.0x. Peers: Toss 3.9, Seed 3.9, iOS 4.4, Monzo 3.0, Cash 5.2 (visual-benchmark §2.1); Material 3 (computed, spec 2021, seed #006D37): the surface (tone 98) sits 1.9 L under white container-lowest, and its containers sit 2.1 / 4.1 / 5.9 / 8.0 L* under the surface.KEEP#F0F7F3. Defensible band ΔL* 3.0-4.4. Below 3.0 the step falls under 3x threshold in 20,000 lux shade; above 4.4 the benefit is small and the owner's "greyer" objection returns (that upper bound is aesthetic, not science).
1.2A green-tinted near-white (C* 3.2) does not shift the perceived white pointChromatic adaptation: degree of adaptation D = F[1 - (1/3.6)e^-((L_A+42)/92)] = 0.84-0.94 for L_A 10-100 cd/m2 (https://en.wikipedia.org/wiki/CIECAM02). Bradford/von Kries, D = 0.9: the white card appears shifted by ΔE76 1.4 when the field is 50/50 basement/white, 2.0 at 70% basement, 3.0 at 100% basement (worst case); today's canvas worst case 1.3, Toss grey 1.1. Shift direction a* +1.3, b* -0.5 (faintly magenta/warm, not grey). Chroma ceiling: Material 3 neutral surfaces carry HCT chroma 6.2 at tones 94-98 (computed, spec 2021); ours is HCT 6.4 / Cab 3.2; Radix sage steps 1-3 are Cab 0.9-1.2 (https://raw.githubusercontent.com/radix-ui/colors/main/src/light.ts). The tint alone is a 3.2 ΔE chromatic step against white, above the 2.3 JND, so it is visible on purpose.KEEPAdd a chroma cap to the gate: C*ab <= 4.5 (Material 3's own surface chroma; ours 3.2). Nothing in the literature gives a lower "safe" ceiling; do not go to Radix levels (0.9) unless you want the basement to read neutral grey.
1.3White cards on a mint basement might look greyer or warmer (simultaneous contrast)Lightness contrast makes the white card look brighter, not greyer. Chromatic induction pushes it toward the complement (magenta): size grows with inducer saturation and flattens (Kirschmann's 4th law); measured shifts for closely surrounding saturated surfaces were "very small" (summary in Faul et al. 2008, https://sites.socsci.uci.edu/~kjameson/FaulEtAl2008.pdf ; original https://doi.org/10.1016/S0960-9822(06)00372-1). At C* 3 the computed shift above (<= 1.4 ΔE76 realistic) is below the JND.KEEPNo action; the card will read as clean white with a barely warm cast. No evidence supports a greyer reading.
1.4A 1.09:1 card edge might violate non-text contrast (WCAG 1.4.11)1.4.11 covers (a) visual information needed to identify UI components and states and (b) graphical objects needed to understand content. "This success criterion does not require that controls have a visual boundary indicating the hit area"; a boundary is "only required when there is no other visual way to identify the presence of the control" (https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html). Cards with text, a chevron or a photo are identified by that content.KEEPNo violation. But two real 1.4.11 exposures sit next to it: (i) segmented-control selected pill white on #E5EBE7 = 1.21:1 is a state cue; "any visual information necessary to indicate state... such as whether a component is selected" must reach 3:1 (same page), so the selected state needs a second cue (label weight/ink change or icon), which the board's "ink label" already provides; keep it and test it. (ii) #E5EBE7 on the basement is only 1.11:1 (ΔE2000 2.5, ~1 JND). Use #DFE7E1 (the existing $borderSubtle): 1.26:1 on a card, 1.16:1 on the basement, ΔE2000 3.65 on the basement.
1.5Hairline #DFE7E1 (1.26:1) -> #CDD6CF (1.49:1) is needed for perceptibility on phone DPR 3 and web DPR 1Geometry: 1 dp at 36.2 cm (Bababekova 2011 mean text-message distance, https://pubmed.ncbi.nlm.nih.gov/21499163/) = 1.51 arcmin = a 19.9 cpd fundamental; the CSS reference pixel is 0.0213 deg = 1.28 arcmin (https://www.w3.org/TR/css-values-3/#reference-pixel) = 23.5 cpd. Model (own calc, Barten, periodic-bar approximation, overstates an isolated line): #DFE7E1 line is 16.5x threshold on phone and 9.7x on DPR 1 in the dark/indoors, and still 8.4x / 5.5x at 100,000 lux; #CDD6CF is 27.6x / 16.2x indoors and 13.6x / 8.9x in sun. So even the lighter hairline is visible; the two DPRs differ by ~40% in threshold, not in kind. Peers ship darker: Material 3 outline-variant (tone 80) 1.62:1 on its surface and 1.70 on white; iOS opaqueSeparator #C6C6C8 1.71:1 (https://sarunw.com/posts/dark-color-cheat-sheet/ , third-party table). Existing $border #CAD4CC is already 1.52:1.KEEPHairline L* 80-85, 1.5-1.7:1 on white; #CDD6CF (1.49) is acceptable but duplicates $border (1.52). One token, not two (single source of truth). The reason to darken is margin for aged eyes and glare, not detectability.
1.6Lists/feeds pure white with 1px hairlinesMaterial 3 "outlined card" = surface colour + outlineVariant border (tone 80, 1.6-1.7:1), the elevated card is surfaceContainerLow and the filled card surfaceContainerHighest (Flutter's Material 3 defaults, https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/card.dart ; tones from the computed ladder, section 2.4). Nothing in the literature favours tone-only separation over hairline separation; sun-glare compression (section 2.5) favours having the hairline.KEEPWhite + hairline for lists. In direct sun every tone step <= 5.5 collapses to 2-3x threshold, so hub cards on the basement have no fallback separator; consider an optional $borderSubtle outline on hub cards if device QA outdoors shows merging.

Proposal 2 — One solid brand block per hub (10-18% of the screen, #006D37, white ink, big numeral) ​

#ClaimWhat the research saysVerdictFinal value / reason
2.1A single colour singleton captures attention; breaks if tab bar / segmented control are also brandColour is an "undoubted" guiding attribute and "attention is attracted to items that differ from their surroundings, if those differences are large enough"; salience is relative to the surround and to distractor homogeneity (Wolfe & Horowitz 2017, https://pmc.ncbi.nlm.nih.gov/articles/PMC9879335 ; search efficiency falls as target-distractor similarity rises, Duncan & Humphreys 1989, https://doi.org/10.1037/0033-295X.96.3.433 ). Feature search is shallow vs conjunction search (~28.7 ms/item for the conjunction condition; Treisman & Gelade 1980, https://doi.org/10.1016/0010-0285(80)90005-5 , slope figure via the secondary simulation at https://arxiv.org/pdf/2310.10061 ). A salient irrelevant item can interfere with goal-directed search (Theeuwes 1992, https://doi.org/10.3758/BF03211656 ). The saliency model weights an intensity channel as well as colour (Itti, Koch & Niebur 1998, https://doi.org/10.1109/34.730558 ). Limits: these are small-item array experiments; salience alone "does only modestly well in predicting the deployment of attention" and fails when the observer has a top-down goal (Wolfe & Horowitz). A 10-18% dark block wins on size and luminance contrast (WCAG 6.48:1 vs white), not only on hue uniqueness.ADJUSTKeep the block, but state the rule as "exactly one filled brand object above 2.5% of the frame; chrome neutral (budget §5 already does this); the primary CTA is the only other brand solid". Do not cite pop-out slopes as proof of the 10-18% number.
2.210-18% of the screen is the right areaNo peer-reviewed optimum exists. Peer measurements are the basis (Monzo 18.4%, Wise 14.4%, visual-benchmark §2.2). Print-ad eye tracking found surface size of pictorial/brand elements did not raise attention while text size did (Pieters & Wedel 2004, https://doi.org/10.1509/jmkg.68.2.36.27794 , via press summary https://news.umich.edu/print-ad-pictures-less-is-more , secondary). A colour-arrangement patent flags 19% occupancy against a 15% limit (an engineering heuristic, https://image-ppubs.uspto.gov/dirsearch-public/print/downloadPdf/9336608).ADJUSTKeep 10-18% as a benchmark range, labelled as such. The perceptual constraints that bind are content type (2.3) and legibility (2.5), not area.
2.3(not on the board) A solid coloured rectangle can be skipped as an adNN/g eye tracking: a "blue rectangular promotion" on a white page was "totally ignored" by most users; a right rail that covered ~25% of the content area drew 1 of 132 fixations (0.8%), "33 times smaller" than its size predicted; "large images that stand out from the page can also be mistaken for ads" (https://www.nngroup.com/articles/banner-blindness-old-and-new-findings/).ADJUSTThe block must hold the answer (next session time, count, ELO) as 28-44/700 numerals, no decorative art, no promo-like copy, and sit at the start of the content column, not in a rail. This is the largest evidence-backed risk to proposal 2.
2.4Large saturated areas cause fatigue / "colour vibration"; Helmholtz-Kohlrausch brighteningNo study isolates large saturated area as a fatigue variable (my searches; closest are two abstract-level 2022 display studies: discomfort lowest at mid saturation, https://doaj.org/article/13da8d34f25c4495840ff8c7fba4d5a7 , and discomfort when a phone's saturation is cut below 0.7x, https://m.researching.cn/articles/OJ6fb642c4209b1b46). H-K magnitude (Nayatani 1997 VCC, https://doi.org/10.1002/(SICI)1520-6378(199712)22:6<385::AID-COL6>3.0.CO;2-R , coefficients per https://colour.readthedocs.io/en/master/_modules/colour/appearance/hke.html): #006D37 +1.3 L* (Gamma 1.07), #14804A +1.5, lime #C6E84B -1.9 (none), versus #B8332E +6.1 and #4B0082 +6.5. The effect is weakest in green-yellow and strongest in red-magenta (High et al. 2023, https://hdl.handle.net/11250/3110488); models overstate it (same source family). Vibration needs equiluminant saturated edges; here white/brand is Lc 86.6 and lime/brand Lc 63.2. CIE 208:2014 reports large stimuli look lighter and more chromatic than small ones (https://www.cie.co.at/publications/effect-stimulus-size-colour-appearance).KEEPNo gate needed. Judge the green at block scale on a device, not from a swatch (it will look lighter and a little more vivid).
2.5White ink on the block is readable at the 12-13px label sizeWhite on #006D37: Lc 86.6, WCAG 6.48:1. APCA table needs Lc 105 for 13/600 and 114 for 12/500 (content), so 13/600 labels pass only the "spot text" row and 12/500 labels pass none; the minimum size at Lc 86.6 is 14.0px at 700, 14.6px at 600, 15.6px at 500, 16.4px at 400. Numerals 32-44/700 need Lc 36-40 and pass with ~50 points to spare. White-with-opacity labels: AA (4.5:1) needs alpha >= 0.77 (#C4DDD1); at 0.70 the contrast is 4.01:1 and fails; at 0.80 (#CCE2D7) 4.76:1, Lc 64.6.ADJUSTBlock labels: white 100% at >= 14px/700 or 15px/600, not 12-13. Any secondary label on the block is a solid token of alpha >= 0.8 (#CCE2D7), never 70%. Numerals as drawn: KEEP.
2.6Lime #C6E84B text/fills on the blockLime on #006D37: WCAG 4.64:1, Lc 63.2 (min 15.4px at 700). Fine as a fill (non-text needs 3:1) and as a 28px+ numeral; lime label text at 12-13px/700 would need Lc 100 and fails. Lime chips with ink text #0D100E: Lc 84.1, 13.7:1 (passes spot/sub-fluent at 13/700 by 0.9 only). Lime on white is 1.40:1, on the control track 1.15:1 (visual-benchmark §5: not there).KEEPLime on the block = fills and numerals >= 28px/700 only. Lime chips use ink text. Lime never as small text.
2.760-30-10No study found; every source is a decorator, paint seller or tile retailer, and the origin is undocumented (e.g. https://livingetc.com/ideas/60-30-10-rule , https://sheerluxe.com/home/interior-design/how-to-use-the-60-30-10-decorating-rule). The only related literature is colour-harmony research on hue/lightness/chroma relations, not area ratios.DROPDo not cite it. The 10-18% / <= 3% targets are peer-benchmark ranges (visual-benchmark §2.2).
2.8Material 3 Expressive research supports colour/containment-driven attentionWhat the page measured: 46 studies, "hundreds of designs", 18,000+ participants; eye tracking on 10 apps, key UI elements spotted "up to four times faster" (best case); preference "up to 87%" at ages 18-24; +32% subculture, +34% modernity, +30% rebelliousness; tap time down "by seconds" (no value). It names "color, shape, size, motion, and containment" as the fundamental elements. Caveats on the page: "a strong minority" preferred calmer designs, usability scores fell when standard patterns were replaced, removing labels hurt usability, figures are best cases, authored by Google about its own system. It does not report type weight, area percentage, or brand-colour singletons (https://design.google/library/expressive-material-design-google-research).KEEP (as qualitative support only)Cite for "size + colour + containment steer attention" and for the minority-who-prefer-calm caveat. Do not cite for any number we use.

Proposal 3 — Ink hierarchy ​

#ClaimWhat the research saysVerdictFinal value / reason
3.1Promote one fact to 18/700Size has the strongest record for drawing the first glance: most surface-size studies find large objects are fixated sooner and more often (review, https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3856423/ ; it concerns objects and ads in general, so applying it to type is an inference). I found no head-to-head study of weight vs size for hierarchy and no JND for text size or weight steps (searched). Ink #0D100E on white: Lc 105.5, 19.1:1, APCA needs only 55 at 18/700 (50-point margin). The step 16/600 -> 18/700 is +12.5% size and +14% Pretendard stem (measured, 222 -> 254 font units).KEEP18/700. Evidence is "no harm, modest step"; if the fact is meant to dominate, 20/700 (+25%) is the convention (Toss T4 20), not a finding. Light weights are the only weight finding with force: avoid them for body (https://doi.org/10.1145/2971485.2996745).
3.2Body 14/400 -> 14/500Pretendard Hangul stems (measured from assets/fonts OTFs): 400 -> 500 is +18% horizontal / +20% vertical (14px: horizontal 0.92 -> 1.08 device px at 1x; 2.75 -> 3.24 at 3x). Boldness improves single-letter recognition at small visual angles and hurts at the extremes (Beier & Oderkerk 2019, https://doi.org/10.1016/j.actpsy.2019.102904). APCA content-text need drops from 110 to 105 (published by-size table says 100 for both 14/400 and 14/500; the Lc-sorted matrix interpolates 110 and 105); ink on white (Lc 105.5) passes at 500 by 0.5 and fails at 400.KEEP14/500 for body on web (1x), where it lifts Hangul horizontal strokes from below 1 device px to above it. On 3x phones the difference is ~0.5 device px: real but small.
3.3Meta 14/500 -> 13/40013/400 is the weakest cell in the system: Hangul horizontal stem 0.85 device px at 1x (thinner than a pixel, so rendered grey); APCA needs Lc 113.5 (unreachable; max ~106) and even #4F5851 (Lc 85.6) fails every class; the minimum px at that Lc is 16.4 (400). Visual angle at 36.2 cm: 13px Latin x-height 0.173 deg, below the 0.2 deg lower edge of the fluent-reading range (Legge & Bigelow 2011, https://pmc.ncbi.nlm.nih.gov/articles/PMC3428264); 13px em 0.327 deg and Hangul ink height 0.277 deg vs the Korean critical print size 0.41 deg young / 0.52 deg older adults (Korean J. Cognitive & Biological Psychology 27(3), https://doi.org/10.22172/cogbio.2015.27.3.003 ; abstract does not define "print size", and it is a desktop study). Shrinking size and weight together compounds the loss.ADJUSTMeta = 13/500 in $textSecondary (stem 1.00 device px at 1x; Lc 85.6 meets the APCA spot row 85) or keep 14/400. The inversion fix (body heavier than meta) is kept: body 14/500 vs meta 13/500 differ by size and colour, not weight.
3.4Tertiary #626C64 is rightWCAG 5.46:1 on white, 5.02:1 on the basement: passes AA with 0.5-1.0 margin, fails AAA. APCA Lc 77.3 / 71.4: needs 17.7px (400) or 15.9-17.4px (500); fails every use-case row at 13-14px. It is lighter than any Material 3 text role (on-surface-variant = tone 30 in spec 2021, tone 40 in spec 2025; ours L* 44.6).ADJUST$textTertiary only at >= 16px/500 or for non-essential strings (timestamps next to a primary fact); never the only carrier of a fact at 13-14px. Do not darken the token; fix the usage.
3.5Secondary #4F5851 is rightWCAG 7.38:1 (white), 6.78:1 (basement); Lc 85.6 / 79.8. Meets AAA on white, 0.22 short on the basement.KEEPIf the secondary must reach 7:1 on the basement too, #4A534D does it (7.32:1, Lc 81.8); not required for AA.
3.6Reduce "muted ink share" from 49% toward 30%No study sets a share of muted vs full ink. What exists is directional: low contrast raises eye strain and lowers findability, worst outdoors (NN/g, https://www.nngroup.com/articles/low-contrast/); designers lightened text on purpose (Marks 2016, https://kevinmarks.com/unreadable-web); 83.9% of home pages had low-contrast text in 2026, avg 34 instances per page, up 15% (WebAIM Million, https://webaim.org/projects/million/). The 49% and 30% are peer-benchmark numbers (ink L* < 35 pixel share), not perceptual thresholds.DROP the number, KEEP the directionReplace the share target by a per-role floor (section 4): secondary for all <= 14px text, tertiary only >= 16px/500. The share then follows.
3.7Hangul-specific legibility evidenceNo mobile Hangul minimum-size study found (the closest is the desktop CPS study above). The text of the Korean accessibility guidance (KWCAG 2.2 / mobile-app guideline) could not be retrieved, so I make no claim about its size or contrast clauses. Hangul ink height is 0.85 em (mean of 18 syllables; Latin x-height 0.53 em), so a Hangul line at 13px is 1.6x taller than Latin lowercase at the same size, which is why 13px Hangul is less bad than 13px Latin but still under the Korean CPS.KEEP (as caveat)Treat 13px Hangul as the floor for secondary text and 14px for anything that is a fact; do not go below.

Proposal 4 — Gate thresholds ​

#Gate as writtenCheck against 1-3VerdictFinal number
4.1Basement vs card ΔL* >= 3.03.0 gives a 3.9% Michelson edge indoors, 2.4% at 20,000 lux (~2.8x threshold), 1.5% at 100,000 lux (1.8x). Below 3.0 shade visibility drops under 3x.KEEPΔL >= 3.0* (basement #F0F7F3 = 3.38).
4.2Basement vs card ΔL* <= 5.5Not derivable from perception; it is the aesthetic ceiling (Cash 5.2 is the top of the measured peers; the owner rejected 4.9 as grey on a near-neutral colour).KEEP (label it aesthetic)ΔL <= 5.5*, plus C*ab <= 4.5 (new, Material 3 level; ours 3.2).
4.3Fills on card >= 1.2:1#E5EBE7 = 1.209, passes by 0.009; the same fill on the basement is 1.111 (ΔE2000 2.5).ADJUSTFill on card >= 1.2:1 AND fill on basement >= 1.15:1. #DFE7E1 (1.261 / 1.159) passes both and is an existing token.
4.4List canvas pure whiteConsistent with 1.5-1.6; no evidence against.KEEP#FFFFFF.
4.5(not on the board) hairlinePeers 1.6-1.7:1; ours 1.49ADDHairline on white 1.4-1.8:1 (#CDD6CF = 1.49).
4.6(not on the board) text floorsSection 3ADDAny text >= 4.5:1 on its real background (WCAG); text <= 14px >= 6.5:1 (#4F5851 passes; tertiary excluded); alpha text on the brand block >= 0.8; block labels >= 14/700.

Proposal 5 — Dark ladder (#090C0A canvas, #1A201B card, #70D5A2 primary) ​

#ClaimWhat the research saysVerdictFinal value / reason
5.1Same budget holds in the darkDark ladder: canvas L* 3.1 -> card L* 11.5 = ΔL* 8.4, ΔE2000 6.55, luminance ratio 3.9x (Y 0.0034 -> 0.0133). Material 3 dark steps from surface (L* 6.2, spec 2021): container-low +3.9, container +5.9, container-high +10.7, container-highest +15.8; Material 2 elevation overlays 5%/7%/9% white on #121212 = +5.8/+8.2/+10.2 L* (https://m2.material.io/design/color/dark-theme , percentages confirmed via search). Ours sits between container (+5.9) and container-high (+10.7). Ambient glare compresses the dark step far faster than the light one: at 500 nits the step is 288% (0 lux), 76% (300 lux), 28% (1,000 lux), 1.5% (20,000 lux).ADJUSTDark gate: card vs canvas ΔL 6.0-12.0* (not the light 3.0-5.5). #090C0A/#1A201B = 8.4, KEEP. State that dark is an evening/indoor mode: the ladder is invisible outdoors.
5.2Light-on-dark legibilityDark-on-light has the advantage at small sizes: both age groups were better with positive polarity (Piepenbrock et al. 2013, https://doi.org/10.1080/00140139.2013.790485); the advantage tracks display luminance via pupil size (Buchner et al. 2009, https://doi.org/10.1080/00140130802641635); negative polarity had the highest legibility thresholds in dark ambient light, and bright light removed the gap (Dobres et al. 2017, https://doi.org/10.1016/j.apergo.2016.11.001). Halation for astigmatic readers (almost half of people have >= 0.5 D, ~10% >= 1 D, per a vendor summary https://www.levelaccess.com/blog/accessibility-for-people-with-astigmatism/) is plausible (pupil dilation raises aberration: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3706062/) but I found no controlled study comparing astigmatic readers across themes. Material uses off-white text: M2 87% white on #121212 = L* 88.5; M3 on-surface tone 90.ADJUST (soft)Primary dark text #EFF3F0 is L* 95.5 (Lc 97.4 on the card). Cap at L* ~90-92, e.g. #DFE4DC (Lc 87.5, 12.9:1, still AAA). Evidence is moderate for the polarity effect and weak for halation; keep dark text weights at 500+ for Hangul (thin strokes plus bloom lose counters).
5.3#70D5A2 primary, secondary/tertiary text#70D5A2 as text on the card: 9.26:1, Lc 67.8 (fails APCA 14/600 content rows); as a fill with ink label #0D100E: Lc 70.4, 10.7:1. Dark text tiers sit at L* 95.5 / 87.3 / 78.0, a hierarchy spread of 8 and 17 L* vs 32 and 40 in light, so hierarchy leans on size/weight in dark. Dark 13/400 secondary #D7DCD8 (Lc 82.7 on card) fails the APCA 13/400 rows (need 114) like light does.KEEPSame type rule as light (13/500 for meta). No change to the primary token.
5.4A brand block in dark#006D37 vs card 2.56:1 (vs canvas 3.03:1): it will not read as a luminance singleton; only chroma carries it. #015228 (existing colorsDark.primary.dark, L* 29.9): vs card 1.77:1, white on it Lc 95.5 / 9.38:1. #70D5A2 as a block is 9.26:1 against the card but is a large bright area on a dark UI (glare, bloom).ADJUSTUse #015228 (white ink) in dark and verify on an OLED device before shipping; the singleton argument (2.1) is weaker in dark. This is the least-evidenced row in the report.

2. Computed tables ​

All tables regenerate with python3 calc_apca.py, calc2.py, calc3.py, calc_hair.py, calc_dark.py in bench/lane_e/ (raw outputs saved as t_apca.md, t_misc.md, t_surface.md, t_hair.md, t_dark.md).

2.1 APCA per role (light): text on white card / basement ​

Columns: Lc = APCA contrast (magnitude); WCAG = 2.x ratio; table Lc needed = Lc the published APCA lookup requires for primary content text at that px and weight (interpolated from the Lc-sorted matrix; the by-size table says 100 for 14/400 and 14/500, 90 for 16/400, 55 for 18/700); body / sub-fluent / spot = verdict under the APCA README adjustments (body text: +15 when the table value is under 75; sub-fluent labels: -15, floor 30; spot text: -25, floor 30; https://github.com/Myndex/apca-w3); min px = smallest size at which this Lc is enough at that weight. Hangul was not tested by APCA (Latin reference font Barlow); treat it as a gauge.

A. Text roles on white card / basement / today canvas (APCA table Lc = needed Lc for that px/weight; then body / sub-fluent / spot verdicts) ​

role (px/weight)fgbgLcWCAGtable Lc neededbody (need) / sub-fluent (need) / spot (need)min px at this Lc & weight
cardTitle 16/600#0D100E#FFFFFF105.519.1370PASS (85) / PASS (55) / PASS (45)12.9px
cardTitle 16/600#0D100E#F0F7F399.717.5970PASS (85) / PASS (55) / PASS (45)13.5px
promoted fact 18/700#0D100E#FFFFFF105.519.1355PASS (70) / PASS (40) / PASS (30)11.9px
promoted fact 18/700#0D100E#F0F7F399.717.5955PASS (70) / PASS (40) / PASS (30)13.0px
cardBody NOW 14/400#0D100E#FFFFFF105.519.13110fail (110) / PASS (95) / PASS (85)14.4px
cardBody NOW 14/400#4F5851#FFFFFF85.67.38110fail (110) / fail (95) / PASS (85)16.4px
cardBody NOW 14/400#0D100E#F0F7F399.717.59110fail (110) / PASS (95) / PASS (85)15.0px
cardBody NOW 14/400#4F5851#F0F7F379.86.78110fail (110) / fail (95) / fail (85)17.3px
cardBody PROPOSED 14/500#0D100E#FFFFFF105.519.13105PASS (105) / PASS (90) / PASS (80)13.9px
cardBody PROPOSED 14/500#4F5851#FFFFFF85.67.38105fail (105) / fail (90) / PASS (80)15.6px
cardBody PROPOSED 14/500#0D100E#F0F7F399.717.59105fail (105) / PASS (90) / PASS (80)14.5px
cardBody PROPOSED 14/500#4F5851#F0F7F379.86.78105fail (105) / fail (90) / fail (80)15.8px
cardMeta NOW 14/500#4F5851#FFFFFF85.67.38105fail (105) / fail (90) / PASS (80)15.6px
cardMeta NOW 14/500#626C64#FFFFFF77.35.46105fail (105) / fail (90) / fail (80)15.9px
cardMeta NOW 14/500#4F5851#F0F7F379.86.78105fail (105) / fail (90) / fail (80)15.8px
cardMeta NOW 14/500#626C64#F0F7F371.45.02105fail (105) / fail (90) / fail (80)17.4px
cardMeta PROPOSED 13/400#4F5851#FFFFFF85.67.38114fail (114) / fail (98) / fail (88)16.4px
cardMeta PROPOSED 13/400#626C64#FFFFFF77.35.46114fail (114) / fail (98) / fail (88)17.7px
cardMeta PROPOSED 13/400#4F5851#F0F7F379.86.78114fail (114) / fail (98) / fail (88)17.3px
cardMeta PROPOSED 13/400#626C64#F0F7F371.45.02114fail (114) / fail (98) / fail (88)19.1px
cardMeta alt 13/500#4F5851#FFFFFF85.67.38110fail (110) / fail (95) / PASS (85)15.6px
cardMeta alt 13/500#626C64#FFFFFF77.35.46110fail (110) / fail (95) / fail (85)15.9px
cardMeta alt 13/500#4F5851#F0F7F379.86.78110fail (110) / fail (95) / fail (85)15.8px
cardMeta alt 13/500#626C64#F0F7F371.45.02110fail (110) / fail (95) / fail (85)17.4px
numeral 28/700#0D100E#FFFFFF105.519.1342PASS (58) / PASS (30) / PASS (30)11.9px
numeral 28/700#0D100E#F0F7F399.717.5942PASS (58) / PASS (30) / PASS (30)13.0px
numeral 44/700#0D100E#FFFFFF105.519.1336PASS (52) / PASS (30) / PASS (30)11.9px
numeral 44/700#0D100E#F0F7F399.717.5936PASS (52) / PASS (30) / PASS (30)13.0px

B. Brand block (white / white-alpha / optic on #006D37) ​

role (px/weight)fgbgLcWCAGtable Lc neededbody / sub-fluent / spotmin px
hero numeral 44/700 white#FFFFFF#006D3786.66.4836PASS (52) / PASS (30) / PASS (30)14.0px
hero numeral 32/700 white#FFFFFF#006D3786.66.4840PASS (55) / PASS (30) / PASS (30)14.0px
block label 13/600 white#FFFFFF#006D3786.66.48105fail (105) / fail (90) / PASS (80)14.6px
block label 12/500 white#FFFFFF#006D3786.66.48114fail (114) / fail (100) / fail (90)15.6px
block label 14/500 white#FFFFFF#006D3786.66.48105fail (105) / fail (90) / PASS (80)15.6px
block label 13/600 white@80%#CCE2D7#006D3764.64.76105fail (105) / fail (90) / fail (80)17.1px
block label 13/500 white@70%#B2D3C3#006D3754.14.01110fail (110) / fail (95) / fail (85)24.7px
block label 13/600 white@70%#B2D3C3#006D3754.14.01105fail (105) / fail (90) / fail (80)21.5px
optic chip text on block 13/700#C6E84B#006D3763.24.64100fail (100) / fail (85) / fail (75)15.4px
optic numeral 28/700#C6E84B#006D3763.24.6442PASS (58) / PASS (30) / PASS (30)15.4px
optic 12/600#C6E84B#006D3763.24.64110fail (110) / fail (95) / fail (85)17.4px
white@80% = #CCE2D7 white@70% = #B2D3C3

C. Semantic text on white (13/600 badge text) and brand-as-text ​

rolefgbgLcWCAGtable Lc neededbody / sub-fluent / spotmin px
success 14/600#14804A#FFFFFF74.04.9895fail (95) / fail (80) / PASS (70)15.2px
warning 14/600#946200#FFFFFF75.75.2495fail (95) / fail (80) / PASS (70)15.0px
error 14/600#B8332E#FFFFFF78.35.9195fail (95) / fail (80) / PASS (70)14.9px
info 14/600#4B0082#FFFFFF97.212.9595PASS (95) / PASS (80) / PASS (70)13.8px
brand link 14/600#006D37#FFFFFF81.56.4895fail (95) / PASS (80) / PASS (70)14.8px

Reading the tables:

  • Ink #0D100E clears every role on white and on the basement, except that 14/400 body fails the strict "body" row (needs 110, ink gives 105.5); 14/500 passes by 0.5 on white and fails on the basement (99.7 vs 105).
  • #4F5851 (secondary) and #626C64 (tertiary) fail the APCA content rows at 13/14 px in every combination. They pass WCAG 2.x comfortably (secondary 7.38 / 6.78; tertiary 5.46 / 5.02).
  • In the block, white at 100% has Lc 86.6; white at 80% drops to Lc 64.6 and at 70% to Lc 54.1 / 4.01:1 (below AA).

2.2 Light surface ladder ​

tokenhexL*C*abΔL* vs whiteΔE2000 vs whiteWCAG vs whiteY step vs white (Weber)vs basement #F0F7F3: ΔL* / ΔE2000 / WCAG
white card / list#FFFFFF100.00.0----3.38 / 4.66 / 1.088
today's canvas#F8FBF998.31.51.652.221.0424.2%1.73 / 2.45 / 1.044
proposed basement#F0F7F396.63.23.384.661.0888.5%-
rejected gray100#F0F5F196.12.73.934.181.1039.8%0.55 / 0.93 / 1.014
proposed control track#E5EBE792.53.07.495.901.20918.2%4.12 / 2.51 / 1.111
$borderSubtle (today's hairline)#DFE7E190.94.29.097.551.26121.7%5.72 / 3.65 / 1.159
existing $border#CAD4CC84.05.6-11.881.52236.0%-
proposed hairline#CDD6CF84.84.915.2211.081.48834.4%11.84 / 7.61 / 1.368
iOS opaqueSeparator (third-party table)#C6C6C879.91.1-12.621.706--
Material 3 outline-variant (spec 2021, seed #006D37)#C1C9BF80.16.1-14.171.697--

Perceptual yardsticks used above: JND 2.3 ΔEab (colour-science constant, from Mokrzycki & Tatol 2011); ΔEab 2-3.5 "unexperienced observer notices", 3.5-5 "clear difference", >5 "two different colours" (https://colour.readthedocs.io/en/master/generated/colour.difference.JND_CIE1976.html). Today's card step is ΔE76 2.21 (0.96x JND); the proposed one 4.67 (2.0x JND).

2.3 Peer and system ladders (card white vs second surface) ​

sourcehexL*C*abΔL*ΔE2000WCAG
Toss grey100#F2F4F696.11.23.912.591.103
당근 Seed basement#F3F4F596.10.63.862.331.101
iOS grouped#F2F2F795.62.64.383.641.116
Monzo#F1F8F497.03.23.034.571.078
Cash App#F0F0F094.80.05.203.051.140
Radix sage 2 / 3 / 4#F7F9F8 / #EEF1F0 / #E6E9E897.8 / 94.9 / 92.10.9 / 1.2 / 1.22.25 / 5.10 / 7.90-1.057 / 1.137 / 1.222
TwoMore proposed#F0F7F396.63.23.384.661.088

Note the proposed basement has the largest ΔE2000 of the set (4.66) despite a mid-pack ΔL*: the tint adds ~1.3 ΔE on top of the lightness step. Radix source: https://raw.githubusercontent.com/radix-ui/colors/main/src/light.ts ; scale roles: https://www.radix-ui.com/colors/docs/palette-composition/understanding-the-scale (step 1-2 backgrounds, step 6 non-interactive borders, step 7-8 interactive borders).

2.4 Material 3 tonal ladder, computed (seed #006D37, tonal spot, contrast 0) ​

Computed with materialyoucolor 3.0.4 (port of https://github.com/material-foundation/material-color-utilities). The m3.material.io spec pages were not readable, so these are the library's outputs.

rolespec 2021 lightL*ΔL* vs surfacespec 2021 darkL*ΔL* vs surface
surface#F6FBF398.1-#1015106.2-
container-lowest#FFFFFF100.01.9#0B0F0B3.92.2
container-low#F0F5ED96.02.1#181D1810.13.9
container#EBEFE794.04.1#1C211C12.15.9
container-high#E5EAE292.15.9#262B2616.910.7
container-highest#DFE4DC90.08.0#31363122.015.8
outline-variant#C1C9BF80.117.9 (1.62:1)#41494130.123.9
on-surface-variant#41494130.1-#C1C9BF80.1-

Library default (spec 2025) differs: dark surface L* 4.0 with steps +2.1 / +5.0 / +8.0 / +11.2; light outline-variant L* 72.4. Neutral HCT chroma of the surface and containers is 6.2 (tones 94-98 light, spec 2021). Material 2 dark overlays (white on #121212, L* 5.5): 5% = +5.8 L*, 7% = +8.2, 9% = +10.2, 11% = +12.5, 16% = +18.1 (percentages per https://m2.material.io/design/color/dark-theme as reported in search; Flutter's formula (4.5 ln(dp+1) + 2)% reproduces them, https://api.flutter.dev/flutter/material/ElevationOverlay/applyOverlay.html).

2.5 Ambient light: what survives a veiling glare ​

Model: screen reflectance rho = 5% (DXOMARK measured 4.6% SCI on one phone, https://www.dxomark.com/fairphone-5-display-test/ ; DisplayMate: Apple tablets 2.0-2.6%, other tablets 4.5-6.5%, https://displaydaily.com/ipad-shoot-out-results-from-displaymate/), diffuse veil V = rho * E / pi added to every surface. DXOMARK's lab tiers are 1,000 lux (indoor) and above 90,000 lux (sunlight). This is my arithmetic, not a measurement.

step0 lux, 300 nits1,000 lux, 300 nits20,000 lux, 500 nits100,000 lux, 1,000 nits
card vs today's canvas (ΔL* 1.65): Michelson edge2.15%2.04%1.30%0.82%
card vs proposed basement (3.38)4.43%4.20%2.66%1.66%
card vs Toss grey (3.91)5.13%4.86%3.08%1.92%
card vs ΔL* 5.57.27%-4.32%2.69%
edge as multiple of the Barten threshold at 1 cpd (0.84%): today / proposed / Toss2.6 / 5.3 / 6.12.4 / 5.0 / 5.81.6 / 3.2 / 3.71.0 / 2.0 / 2.3

V values: 5% reflectance gives 15.9 nits at 1,000 lux, 318 nits at 20,000 lux, 1,592 nits at 100,000 lux. Barten model: my own implementation of Barten 1999 (https://doi.org/10.1117/3.353254) with the parameter set used in the PQ/SMPTE ST 2084 derivation (Miller, Nezamabadi & Daly 2013, https://doi.org/10.5594/j18290 ), entered from memory and not cross-checked against the standard text (k 3.0, T 0.1 s, eta 0.03, X0 2 deg, Xmax 12 deg). Output: peak sensitivity 360-400 at 4-8 cpd for 100-300 cd/m2, i.e. thresholds of 0.25-0.3%, plausible for photopic luminance but not independently verified; treat every multiple as order-of-magnitude. Using 0.5 cpd instead of 1 cpd (threshold 1.66%) halves the multiples. A tennis club screen spends time in 20,000-100,000 lux; NN/g names bright-sun reading as the failure case for low contrast (https://www.nngroup.com/articles/low-contrast/).

2.6 Hairline detectability (Barten, periodic-bar approximation) ​

Line widths: phone 1 dp = 0.159 mm at 36.2 cm = 1.51 arcmin (fundamental 19.9 cpd); desktop CSS reference pixel 0.0213 deg = 1.28 arcmin (23.5 cpd). Entry = fundamental amplitude (4/pi x Michelson) as a multiple of threshold; an isolated line is weaker than a periodic bar pattern, so read these as upper bounds.

hairlineCR vs whitephone 0 luxphone 20k luxphone 100k luxDPR1 web 0 luxDPR1 20k luxDPR1 100k lux
#DFE7E11.2616.5x11.9x8.4x9.7x7.5x5.5x
#CDD6CF1.4927.6x19.5x13.6x16.2x12.3x8.9x
#C2CAC4 (L* 80.6)1.6735.2x24.5x16.9x20.6x15.4x11.2x

2.7 Type: Pretendard stems and viewing angles ​

Stem widths measured from assets/fonts/Pretendard-*.otf (2048 upm): Hangul vertical stem (ㅣ) 158 / 190 / 222 / 254 units for 400 / 500 / 600 / 700; horizontal stem (ㅡ) 134 / 158 / 184 / 208. Ratios: 500/400 = 1.20 vertical, 1.18 horizontal; 600/500 = 1.17; 700/600 = 1.14.

size, DPR400 horiz500 horiz600 horiz700 horiz400 vert500 vert
13px, 1x (device px)0.851.001.171.321.001.21
14px, 1x0.921.081.261.421.081.30
14px, 3x2.753.243.774.273.243.90
16px, 1x1.051.231.441.621.231.48

Visual angle at 36.2 cm (1 px = 0.159 mm; Bababekova 2011), Pretendard Regular metrics (Hangul ink height 0.847 em, mean of 18 syllables; Latin x-height 0.530 em):

pxemHangul ink heightLatin x-height
120.302 deg0.255 deg0.160 deg
130.3270.2770.173
140.3520.2980.187
150.3770.3190.200
160.4020.3400.213
170.4270.3620.227
180.4520.3830.240

Reference lines: fluent-reading range starts at 0.2 deg x-height (Legge & Bigelow 2011, https://pmc.ncbi.nlm.nih.gov/articles/PMC3428264 : "approximately 0.2 deg to 2 deg"); Korean critical print size 0.41 deg (young) / 0.52 deg (older), definition of "print size" not stated in the abstract (https://doi.org/10.22172/cogbio.2015.27.3.003). 0.41 deg is a 16 px em at this distance if "print size" means the em; 0.52 deg is 20.6 px.

2.8 Dark ladder and dark text ​

tokenhexL*Yvs canvas: ΔL* / ΔE2000 / WCAG
canvas#090C0A3.10.0034-
gray100#1115126.30.00703.22 / 2.57 / 1.067
card#1A201B11.50.01338.40 / 6.55 / 1.185 (luminance ratio 3.9x)
border light#262D2817.70.0244card vs it: 6.16 / 4.05 / 1.175
surface tertiary#37403926.10.0477card vs it: 14.59 / 10.08 / 1.544
border default#515B5337.60.0986card vs it: 26.09 / 19.05 / 2.346

Dark step vs glare (card vs canvas, Weber (Ya-Yb)/Yb, rho 5%): W 200 nits: 288% (0 lux), 36% (300 lux), 12% (1,000 lux), 0.6% (20,000 lux); W 500 nits: 288% / 76% / 28% / 1.5%.

Dark text (token values from classic-grass.theme.ts) ​

rolefgbgLcWCAGtable Lc neededbody / sub-fluent / spot
title 16/600 text.primary#EFF3F0#090C0A99.117.5570PASS (85) / PASS (55) / PASS (45)
promoted 18/700 text.primary#EFF3F0#090C0A99.117.5555PASS (70) / PASS (40) / PASS (30)
body 14/500 text.primary#EFF3F0#090C0A99.117.55105fail (105) / PASS (90) / PASS (80)
body 14/500 text.secondary#D7DCD8#090C0A84.414.15105fail (105) / fail (90) / PASS (80)
meta 13/400 text.secondary#D7DCD8#090C0A84.414.15114fail (114) / fail (98) / fail (88)
meta 13/400 text.tertiary#BBC3BD#090C0A69.010.91114fail (114) / fail (98) / fail (88)
primary as text 14/600#70D5A2#090C0A69.510.9895fail (95) / fail (80) / fail (70)
title 16/600 text.primary#EFF3F0#1A201B97.414.8170PASS (85) / PASS (55) / PASS (45)
promoted 18/700 text.primary#EFF3F0#1A201B97.414.8155PASS (70) / PASS (40) / PASS (30)
body 14/500 text.primary#EFF3F0#1A201B97.414.81105fail (105) / PASS (90) / PASS (80)
body 14/500 text.secondary#D7DCD8#1A201B82.711.94105fail (105) / fail (90) / PASS (80)
meta 13/400 text.secondary#D7DCD8#1A201B82.711.94114fail (114) / fail (98) / fail (88)
meta 13/400 text.tertiary#BBC3BD#1A201B67.29.20114fail (114) / fail (98) / fail (88)
primary as text 14/600#70D5A2#1A201B67.89.2695fail (95) / fail (80) / fail (70)
button label ink on #70D5A2 16/600#0D100E#70D5A270.410.6970fail (85) / PASS (55) / PASS (45)

Dark text and block facts behind rows 5.2-5.4:

  • Dark text tiers sit at L* 95.5 (#EFF3F0), 87.3 (#D7DCD8), 78.0 (#BBC3BD); #70D5A2 is L* 78.3.
  • Candidate primary text caps: Material 3 spec-2021 on-surface tone 90 #DFE4DC (L* 90.0): Lc 87.5 / 12.85:1 on the card, Lc 89.2 / 15.22:1 on the canvas. Material 2's 87% white on #121212 is #DEDEDE (L* 88.5): Lc 84.7 / 12.33:1 on the card. Pure white on the canvas is Lc 107.7 / 19.65:1; the current #EFF3F0 is Lc 99.1.
  • Dark block candidates: #70D5A2 fill is 10.98:1 vs canvas, 9.26:1 vs card, ink on it Lc 70.4; brand #006D37 is 3.03:1 vs canvas, 2.56:1 vs card, white on it Lc 86.6; colorsDark.primary.dark #015228 (L* 29.9) is 2.10:1 vs canvas, 1.77:1 vs card, white on it Lc 95.5 / 9.38:1.
  • Separator references: iOS opaqueSeparator #C6C6C8 1.71:1 on white (L* 79.9); Material 3 outline-variant #C1C9BF 1.70:1 on white and 1.62:1 on its surface #F6FBF3; a same-hue L* 80.6 candidate #C2CAC4 is 1.67:1 on white and 1.54:1 on the basement.

3. What the science does NOT support (folklore, overstated, or unmeasured) ​

  1. "60-30-10." No study tests it; every source found is a decorator, paint or tile seller with no origin cited. It is a rule of thumb. Do not put it in the board or the canon. (Sources: https://livingetc.com/ideas/60-30-10-rule , https://sheerluxe.com/home/interior-design/how-to-use-the-60-30-10-decorating-rule)
  2. Pop-out proves the 10-18% block. Feature-search experiments use small items in arrays (Treisman & Gelade 1980; Wolfe & Horowitz 2017). A block that is 10-18% of a screen is a large dark object; it wins on size and luminance contrast (white-vs-green 6.48:1) as much as on hue uniqueness, and Wolfe & Horowitz say salience alone "does only modestly well in predicting the deployment of attention" once the user has a goal. The 10-18% number is a peer measurement (Monzo 18.4%, Wise 14.4%), not a perceptual optimum.
  3. The von Restorff / isolation effect. It is a memory result from list learning (Hunt 1995, https://doi.org/10.3758/BF03214414 ; Hunt & Lamb 2001, https://doi.org/10.1037/0278-7393.27.6.1359 ; title-level check only). It says distinct items are better recalled, not that a distinct block is better seen or acted on. Do not cite it for the block.
  4. "Large saturated areas cause visual fatigue / colour vibration." I found no study that varies saturated area as a fatigue factor. Vibration needs equiluminant saturated edges (not present: Lc 86.6 and 63.2). The Helmholtz-Kohlrausch brightening for #006D37 is +1.3 L*, versus +6 for red or violet. Do not add a rule against it; do not cite it as a risk either.
  5. Material 3 Expressive "up to 4x faster" and "87% preference." Best-case, vendor-authored, ages 18-24 for the 87%, 10 apps for eye tracking; it names colour, size and containment as levers but reports no area share, no type weight, and no brand-singleton test; it also reports usability losses when standard patterns were replaced and a "strong minority" preferring calm designs. Qualitative support only.
  6. "Muted ink share 49% -> 30%." Not a perceptual quantity. The supporting literature is directional (NN/g, Marks, WebAIM 83.9% in 2026). The per-role contrast floor is what the science supports.
  7. "500 vs 400 is a hierarchy tier." Measured Pretendard stems differ by +18-20% (0.16 device px at 14px/1x; 0.5 at 3x). I found no stroke-width or font-weight JND, so I cannot say whether neighbouring weights read as different levels; the only weight findings are that very light and very heavy weights hurt (Beier & Oderkerk 2019; Burmistrov et al. 2016, https://doi.org/10.1145/2971485.2996745) and that boldness helps at small visual angles. Weight is a refinement; size and colour carry the hierarchy.
  8. "The hairline must be 1.5:1 to be perceptible." Not required: even #DFE7E1 (1.26:1) is 5.5-16x the modelled threshold. Darker is for margin (age, sun, glare) and for matching peers (1.6-1.7:1), not for detectability.
  9. "ΔL <= 5.5" and "fills >= 1.2:1" as perceptual thresholds.* Neither is derived from psychophysics. 5.5 is the top of the measured peers; 1.2 is where the current #E5EBE7 track happens to land (1.209).
  10. "The green tint shifts the white point" or "makes the card look grey." Computed shift at D = 0.9 is <= 1.4 ΔE76 realistically (3.0 worst case, 100% basement); the direction is faintly magenta, not grey.
  11. "Halation makes dark-mode Hangul unreadable." Plausible mechanism (pupil dilation raises aberration; positive-polarity advantage in two peer-reviewed studies) but no controlled study of astigmatic readers across themes was found, and the astigmatism prevalence figures I found are vendor summaries.
  12. APCA's font-size verdicts as a pass/fail gate. APCA is not adopted by any standard (WCAG 3 draft: algorithm TBD), its lookup table is demanding enough that 14/500 body needs Lc 105 even for ink, and independent validation was not located. It is useful for ordering choices (more Lc, larger, heavier = better) and for flagging 13px grey text, nothing more.
  13. Convergence of peers as proof. Toss, Seed and Material 3 all land at ΔL* 3.9-4.1 for a tone step; that is shared practice, which I confirm is perceptually sound (2x JND, 3x threshold in shade), not independent evidence.

4. Final numbers (for the gate and the tokens) ​

itemvaluebasis
Hub basement vs card3.0 <= ΔL <= 5.5*; #F0F7F3 = 3.38>= 2x JND indoors, ~3x Barten threshold at 20,000 lux; upper bound aesthetic
Basement chroma capC*ab <= 4.5 (ours 3.2)Material 3 neutral surface chroma (HCT 6.2); white-point shift <= 1.4 ΔE76 at C* 3.2
List canvas#FFFFFFno contrary evidence
Fill on card>= 1.2:1keep
Fill on basement>= 1.15:1 (new)#E5EBE7 is 1.111; #DFE7E1 1.159
Control track#DFE7E1 (reuse $borderSubtle) instead of #E5EBE7passes both fill rules; one token fewer
Hairline on white1.4-1.8:1 (L* ~80-85); #CDD6CF 1.49peers 1.6-1.7; merge with $border #CAD4CC 1.52
Text>= 4.5:1 everywhere; >= 6.5:1 for text <= 14px; tertiary #626C64 only >= 16px/500WCAG 2.2 AA; APCA ranks 13-14px grey as the weakest cell
Rolesbody 14/500 $text; meta 13/500 $textSecondary; promoted 18/700; title 16/600; numerals 28-44/700stems >= 1 device px at 1x; angles in 2.7
Block labels>= 14px/700 or 15px/600 white 100%; secondary label alpha >= 0.8 (#CCE2D7)Lc 86.6; alpha 0.77 is the AA floor
Lime on blockfills and numerals >= 28px/700 onlyLc 63.2, 4.64:1
Block ruleexactly one filled brand object > 2.5% of the frame; holds the answer as numerals; no promo stylingNN/g banner blindness; saliency literature
Dark card vs canvas6.0 <= ΔL <= 12.0*; #090C0A/#1A201B = 8.4Material 3 spec-2021 dark steps 3.9-15.8
Dark primary textcap at L* ~90-92 (e.g. #DFE4DC) instead of #EFF3F0 (95.5)polarity/luminance literature; M2 87%, M3 tone 90
Dark brand block#015228 with white ink, device-test before shippingluminance singleton is weak in dark

5. Caveats ​

  • My own models. The ambient-light table, the Barten edge/hairline multiples, the Bradford adaptation shift and the Nayatani brightness estimate are my arithmetic on standard models, with parameters entered from memory where flagged; they are order-of-magnitude. The Barten model is for sinusoidal gratings in a 2 deg field; an isolated 1.5 arcmin line and a large-field edge both depart from it. Reflectance 5% and diffuse reflection only (specular glare makes sun worse).
  • Secondary or partial sources: Pieters & Wedel 2004 (press summary), Treisman slope (arXiv simulation), astigmatism prevalence (vendor), iOS separator values (third-party table), Dobres et al. 2017 and Piepenbrock et al. 2013 (abstract-level), Xiao et al. 2011 (bibliographic only; the size-effect statement rests on CIE 208:2014 as summarised in search), Kirschmann/Mizokami (as summarised in Faul et al. 2008), the two 2022 saturation-comfort papers (abstract-level), Korean CPS paper (abstract; "print size" undefined).
  • Not readable: m3.material.io pages, m2.material.io dark-theme page, Apple HIG, Korean KWCAG/NIA texts. Material numbers are library-computed; Apple separator values are third-party.
  • DXOMARK: the page I could read lists the 1,000 lux and >90,000 lux tiers; the "20,000 lux outdoor" tier appeared in search summaries but not on that page.
  • Viewing distance 36.2 cm is a demonstrated, not observed, mean (Bababekova 2011: 129 participants; text-message distance; range 17.5-58 cm). Android dp 0.159 mm, iOS pt ~0.156 mm.
  • Colour model. All hex values treated as sRGB/D65; phone panels (P3, OLED) and OS colour management change absolute luminance and warmth, not the ratios.
  • APCA was computed for flat colour; thin Hangul strokes under 1 device px are lighter than the flat value, so the 13/400 findings are, if anything, optimistic. Reference font is Barlow, not Pretendard.
  • Age. Contrast sensitivity at 19-24 cpd falls with age; the club population skews older than the lab samples behind these models. That argues for the margins above, not for tightening them.
  • No device test. Nothing here was seen on a phone. Rows 2.4, 5.2 and 5.4 especially need the on-device pass the project already plans.

6. Sources (all URLs used) ​

Standards and specs: https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html · https://github.com/Myndex/apca-w3 · https://raw.githubusercontent.com/Myndex/apca-w3/master/data/LUT-GseriesMay28-2022.js · https://adrianroselli.com/2026/04/wcag3-contrast-as-of-april-2026.html · https://www.w3.org/TR/css-values-3/#reference-pixel · https://en.wikipedia.org/wiki/CIECAM02 · https://www.cie.co.at/publications/effect-stimulus-size-colour-appearance

Design systems: https://design.google/library/expressive-material-design-google-research · https://github.com/material-foundation/material-color-utilities · https://pypi.org/project/materialyoucolor/ · https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/card.dart · https://docs.flutter.dev/release/breaking-changes/new-color-scheme-roles · https://m2.material.io/design/color/dark-theme · https://api.flutter.dev/flutter/material/ElevationOverlay/applyOverlay.html · https://raw.githubusercontent.com/radix-ui/colors/main/src/light.ts · https://www.radix-ui.com/colors/docs/palette-composition/understanding-the-scale · https://sarunw.com/posts/dark-color-cheat-sheet/

Colour and vision science: https://colour.readthedocs.io/en/master/generated/colour.difference.JND_CIE1976.html (Mokrzycki & Tatol 2011) · https://doi.org/10.1117/3.353254 (Barten 1999) · https://doi.org/10.5594/j18290 (Miller et al. 2013) · https://doi.org/10.1002/(SICI)1520-6378(199712)22:6<385::AID-COL6>3.0.CO;2-R (Nayatani 1997) · https://colour.readthedocs.io/en/master/_modules/colour/appearance/hke.html · https://hdl.handle.net/11250/3110488 (High et al. 2023) · https://doi.org/10.1016/S0960-9822(06)00372-1 (Brown & MacLeod 1997) · https://sites.socsci.uci.edu/~kjameson/FaulEtAl2008.pdf · https://doi.org/10.1002/col.20610 (Xiao et al. 2011) · https://doaj.org/article/13da8d34f25c4495840ff8c7fba4d5a7 · https://m.researching.cn/articles/OJ6fb642c4209b1b46

Attention: https://doi.org/10.1016/0010-0285(80)90005-5 · https://pmc.ncbi.nlm.nih.gov/articles/PMC9879335 (Wolfe & Horowitz 2017, https://doi.org/10.1038/s41562-017-0058) · https://doi.org/10.1037/0033-295X.96.3.433 · https://doi.org/10.3758/BF03211656 · https://doi.org/10.1109/34.730558 · https://doi.org/10.1509/jmkg.68.2.36.27794 · https://news.umich.edu/print-ad-pictures-less-is-more · https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3856423/ · https://arxiv.org/pdf/2310.10061 · https://doi.org/10.3758/BF03214414 · https://doi.org/10.1037/0278-7393.27.6.1359 · https://www.nngroup.com/articles/banner-blindness-old-and-new-findings/ · https://www.nngroup.com/articles/low-contrast/

Legibility and type: https://pmc.ncbi.nlm.nih.gov/articles/PMC3428264 (Legge & Bigelow 2011; https://doi.org/10.1167/11.5.8) · https://doi.org/10.22172/cogbio.2015.27.3.003 · https://pubmed.ncbi.nlm.nih.gov/21499163/ (Bababekova et al. 2011; https://doi.org/10.1097/OPX.0b013e3182198792) · https://doi.org/10.1016/j.actpsy.2019.102904 · https://doi.org/10.1145/2971485.2996745 · https://kevinmarks.com/unreadable-web · https://webaim.org/projects/million/

Dark mode: https://doi.org/10.1080/00140139.2013.790485 · https://doi.org/10.1080/00140130802641635 · https://doi.org/10.1016/j.apergo.2016.11.001 · https://arxiv.org/abs/2203.16546 · https://www.levelaccess.com/blog/accessibility-for-people-with-astigmatism/ · https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3706062/

Ambient light: https://www.dxomark.com/fairphone-5-display-test/ · https://displaydaily.com/ipad-shoot-out-results-from-displaymate/

Folklore sources (60-30-10): https://livingetc.com/ideas/60-30-10-rule · https://sheerluxe.com/home/interior-design/how-to-use-the-60-30-10-decorating-rule

Repo inputs (read-only): docs/design/research/visual-benchmark-2026-10-08.md, packages/ui/src/theme-hex.ts (border #CAD4CC, borderSubtle #DFE7E1), packages/app/src/config/themes/classic-grass.theme.ts (dark ladder and text tokens), assets/fonts/Pretendard-*.otf.

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