Three visual directions (Skärgård, Kvitto, Kalas) as self-contained HTML pages with every SPEC §13.3 screen in light and dark, Swedish, plus PNG exports and the exporter script. Direction-independent docs: ia.md, screens.md, flows.md, components.md, tokens.md (values for all three directions), strings.csv (key,en,sv,notes), and the comparison with a recommendation in directions/README.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
16 KiB
Kvitt: design tokens
Status: U1 proposal (2026-10-17). One token set of names (binding once the owner picks a direction) with values for all three directions (directions/1-skargard, 2-kvitto, 3-kalas), so :core:design can be built from whichever is chosen. After the pick, U2 copies the chosen column into design-spec.md and deletes the other two here (one source of truth). Each direction's review page recomputes every contrast ratio below in JavaScript and marks failures; the values here were checked there.
Contrast targets (SPEC §13.1): text ≥ 4.5:1 against the surface it sits on; icons and graphics ≥ 3:1; nothing conveyed by colour alone.
1. How tokens map to Compose
| Token group | Compose home in :core:design |
Notes |
|---|---|---|
| Material 3 colour roles (§2) | lightColorScheme(...) / darkColorScheme(...) |
names map 1:1 (on-primary-container → onPrimaryContainer) |
| Kvitt semantic roles (§3) | KvittColors data class in a CompositionLocal, light and dark instance |
owed*, owing*, settled*, warning*, pending, avatar* |
| Category colours (§4) | KvittColors.category(ColorToken) and .categoryContainer(ColorToken) |
ColorToken enum from :core:model (§14.2.4) |
| Chart colours (§5) | KvittColors.chartCategorical[0..7], chartSequential[0..4], chartGrid, chartAxisLabel |
|
| Type (§6) | Typography(...) + KvittTypography(amountHero, amountLarge, amountMedium, amountSmall) |
amounts always fontFeatureSettings = "tnum" |
| Spacing (§7) | object KvittSpacing { val s1 = 4.dp … } |
|
| Shapes (§8) | Shapes(extraSmall…extraLarge) + KvittShapes for the Expressive sizes and custom shapes |
|
| Elevation, motion (§9) | MotionScheme (Expressive) or durations/easings constants |
Dynamic colour (Material You): offered only by Skärgård, as an off-by-default option that replaces §2 only; §3–§5 keep their values in every case.
2. Material 3 colour roles
L = light, D = dark.
| Token | Skärgård L | Skärgård D | Kvitto L | Kvitto D | Kalas L | Kalas D |
|---|---|---|---|---|---|---|
| primary | #1A6476 | #8ED0E2 | #23408E | #B3C3FF | #B23A1C | #FFB59F |
| on-primary | #FFFFFF | #00363F | #FFFFFF | #112A6A | #FFFFFF | #5E1604 |
| primary-container | #C2E8F3 | #0E4D5C | #DCE3F6 | #2B4590 | #FFDBD0 | #8A2A10 |
| on-primary-container | #0B4C5C | #C2E8F3 | #14295E | #DDE3FF | #3D0B00 | #FFDBD0 |
| secondary | #4E5F69 | #B6C9D4 | #4E5466 | #C2C6D8 | #4B6A2A | #B2D38A |
| on-secondary | #FFFFFF | #20333B | #FFFFFF | #2B3040 | #FFFFFF | #1F3701 |
| secondary-container | #D3E3EE | #374952 | #DFE2EB | #3B4050 | #D3EFAE | #344F15 |
| on-secondary-container | #374851 | #D3E5F0 | #1B2030 | #DEE1F1 | #112000 | #D3EFAE |
| tertiary | #7B5C24 | #E8C48A | #73552A | #DCC39A | #7A5900 | #F2C14E |
| on-tertiary | #FFFFFF | #422C00 | #FFFFFF | #3E2D10 | #FFFFFF | #402D00 |
| tertiary-container | #F7DFB4 | #5D4410 | #F1E2C8 | #574425 | #FFDF8E | #5A3F00 |
| on-tertiary-container | #5A410E | #FFDEA8 | #2E1F06 | #F7E1BD | #261A00 | #FFDF8E |
| error | #B3261E | #F2B8B5 | #B0261B | #FFB4A8 | #BA1A1A | #FFB4AB |
| on-error | #FFFFFF | #601410 | #FFFFFF | #690004 | #FFFFFF | #690005 |
| error-container | #F9DEDC | #8C1D18 | #F9DCD6 | #8E1E14 | #FFDAD6 | #93000A |
| on-error-container | #8C1D18 | #F9DEDC | #5A0E08 | #FFDAD4 | #410002 | #FFDAD6 |
| surface | #F6FAFC | #0F1417 | #F7F4EC | #1C1A17 | #FFF8F1 | #1D1415 |
| on-surface | #171C1F | #DEE3E6 | #1D1B17 | #ECE6DA | #231918 | #F1DFDB |
| surface-variant | #DBE4E8 | #40484C | #E7E2D6 | #4A463E | #F5DED6 | #53433F |
| on-surface-variant | #40484C | #BFC8CC | #58534A | #C0B9AB | #53433F | #D8C2BB |
| surface-container-lowest | #FFFFFF | #0A0F11 | #FFFDF8 | #161512 | #FFFFFF | #170F10 |
| surface-container-low | #F0F4F7 | #171C1F | #F2EEE5 | #211F1B | #FFF1E8 | #251B1C |
| surface-container | #EAEFF2 | #1B2124 | #EDE9DF | #26241F | #FAEADF | #2A1F20 |
| surface-container-high | #E4E9EC | #252B2E | #E6E1D6 | #302D28 | #F4E4D8 | #352A2A |
| surface-container-highest | #DEE3E6 | #303639 | #E0DBCF | #3B3832 | #EEDED2 | #403434 |
| surface-dim | #D6DBDE | #0F1417 | #D9D4C8 | #1C1A17 | #E6D6CB | #1D1415 |
| surface-bright | #F6FAFC | #353A3D | #FBF9F3 | #42403A | #FFF8F1 | #463A3A |
| inverse-surface | #2C3134 | #DEE3E6 | #32302B | #ECE6DA | #392E2C | #F1DFDB |
| inverse-on-surface | #EDF1F4 | #2C3134 | #F4F0E7 | #32302B | #FFEDE7 | #392E2C |
| inverse-primary | #8ED0E2 | #1A6476 | #B3C3FF | #23408E | #FFB59F | #B23A1C |
| outline | #70787C | #899296 | #7E786C | #8D877A | #85736E | #A08C87 |
| outline-variant | #BFC8CC | #40484C | #D3CDC0 | #48443C | #D8C2BB | #53433F |
| scrim | #000000 (40 %) | #000000 | #000000 (42 %) | #000000 | #000000 (38 %) | #000000 |
Key contrast (text role vs surface, L / D): on-surface 16.4 / 14.3 · 15.6 / 14.0 · 16.3 / 14.0; on-surface-variant 8.9 / 10.9 · 6.9 / 8.9 · 8.9 / 10.6; primary 6.4 / 10.8 · 8.7 / 10.1 · 5.7 / 10.6. outline is used for graphics only (3.99–5.84).
Direction-specific extra aliases: Kvitto paper (= surface-container-lowest in light, surface-container-high in dark; the receipt surface). Kalas card (#FFFFFF / #2A1F20) and on-cat (#FFFFFF / #1D1415, icon colour on solid category tiles).
3. Kvitt semantic roles
| Token | Use | Skärgård L | D | Kvitto L | D | Kalas L | D |
|---|---|---|---|---|---|---|---|
| owed | text/graphic: partner owes you | #00695C | #7DD8C5 | #2C6A38 | #92CC9A | #1B6B45 | #8BD8A8 |
| on-owed | #FFFFFF | #00382F | #FFFFFF | #0E3818 | #FFFFFF | #003920 | |
| owed-container | #C2EDE4 | #005047 | #DCEBD8 | #1E3A24 | #C4EFD2 | #0F5233 | |
| on-owed-container | #00443B | #A3F2E0 | #123A1C | #BFE8C4 | #00210F | #A7F5C3 | |
| owing | text/graphic: you owe partner | #A33E1C | #FFB59E | #A23B25 | #F2A890 | #7E2F84 | #F2AEF0 |
| on-owing | #FFFFFF | #5E1700 | #FFFFFF | #4F1708 | #FFFFFF | #4C0F53 | |
| owing-container | #FFDBCF | #7E2C0E | #F6DDD3 | #4B2418 | #F9D7F6 | #66226C | |
| on-owing-container | #792A0B | #FFDBCF | #4D170A | #FFDACD | #33003A | #FFD6F8 | |
| settled | "Kvitt" / "Ni är kvitt" | #4E5F69 | #B6C9D4 | #58534A | #C0B9AB | #6E5500 | #F2D45C |
| settled-container | #DCE5EA | #2C3B43 | #E6E1D6 | #302D28 | #FFE38F | #5A3F00 | |
| on-settled-container | #36464F | #D3E5F0 | #2A2823 | #E5DFD2 | #241A00 | #FFE38F | |
| warning | over-settle, sync warnings | #855700 | #F5BD62 | #875400 | #EBC06C | #8A4D00 | #FFB86E |
| on-warning | #FFFFFF | #452B00 | #FFFFFF | #3E2900 | #FFFFFF | #4A2800 | |
| warning-container | #FFDEAD | #633F00 | #F7E3BF | #4D3708 | #FFDDBA | #6A3B00 | |
| on-warning-container | #633F00 | #FFDEAD | #3B2600 | #FCE3AE | #2C1600 | #FFDDBA | |
| pending | sync-pending marker | #7B5C24 | #E8C48A | #875400 | #EBC06C | #00658F | #86CFFF |
| avatar-1 | initials background, user slot 1 | #C2E8F3 | #0E4D5C | #3F5E4C | #A5C9B0 | #9A4A00 | #FFB870 |
| on-avatar-1 | #0B4C5C | #C2E8F3 | #FFFFFF | #10291A | #FFFFFF | #2E1500 | |
| avatar-2 | initials background, user slot 2 | #F2DDB8 | #5D4410 | #6B4C8A | #CDB4E8 | #2C5F9E | #A8C8FF |
| on-avatar-2 | #5A400E | #F7DFB4 | #FFFFFF | #2F1B45 | #FFFFFF | #002F64 |
All owed/owing text values ≥ 5.6:1 on surface in both themes in all directions. Owed/owing hue pairs are chosen to stay distinct for red-green colour blindness (Skärgård sea-green vs coral, Kvitto green vs brick with a square marker, Kalas green vs purple); the words carry the meaning anyway. Avatar slot: a stable function of the user id (e.g. the last hex digit's parity), so each person keeps one colour on both phones (AC-4.5).
4. Category colours (SPEC §9.7 token names)
Use: the icon colour on its container (cat-<token> on cat-<token>-container), chart segments, Kalas solid tiles (on-cat icon on cat-<token>). Never text in light themes. Container rule: Skärgård 16 % (L) / 22 % (D) of the colour over surface; Kvitto 16 % / 24 %; Kalas 18 % / 24 %.
Baseline values (used unchanged by Kvitto and Kalas, and by Skärgård in dark):
| Token | Light | Dark | Skärgård light override |
|---|---|---|---|
| green | #2E7D32 | #81C784 | #2A732E |
| orange | #B84A00 | #FFB74D | #A84300 |
| brown | #795548 | #C8B4AC | — |
| yellow | #8A6A00 | #F2D45C | #7D6000 |
| blue | #1565C0 | #90CAF9 | — |
| teal | #00796B | #80CBC4 | #006F62 |
| purple | #7B1FA2 | #D1A0DB | — |
| red | #C62828 | #EF9A9A | — |
| pink | #AD1457 | #F48FB1 | — |
| grey | #5F6B73 | #B0BEC5 | #58646C |
| indigo | #3949AB | #A5AEE0 | — |
| lime | #5B6B00 | #C5D86D | — |
Measured: icon vs its container ≥ 3.7:1 (light) and ≥ 4.8:1 (dark) in every direction; colour vs surface ≥ 4.6:1 (light) and ≥ 7.7:1 (dark). These differ from the provisional hex values in SPEC §9.7 (orange, brown, yellow, purple, grey, indigo, lime in light; brown, yellow, purple, indigo, lime in dark): adopting them is a spec change (decisions entry + spec version bump) that the orchestrator makes after the pick (SPEC §13.4 U2).
Per-direction container hex values are listed on each review page (computed, not hand-typed).
5. Chart colours
| Token | Skärgård L | Skärgård D | Kvitto L | Kvitto D | Kalas L | Kalas D |
|---|---|---|---|---|---|---|
| chart-cat-1 | #1A6476 | #8ED0E2 | #23408E | #B3C3FF | #C2462A | #FF9F86 |
| chart-cat-2 | #A8741A | #E8C48A | #B4602A | #F0A673 | #4F7A2B | #A9D37F |
| chart-cat-3 | #5B5FA8 | #B8BCF4 | #2D7A6C | #7DCAB8 | #8C6200 | #F2C14E |
| chart-cat-4 | #4D8559 | #9BD3A3 | #7B4E9E | #CDA8EE | #2D63AE | #9CC2FF |
| chart-cat-5 | #A0526E | #EDA9C1 | #7F7225 | #D6C66B | #8A3F92 | #E2A6EA |
| chart-cat-6 | #2F86A0 | #5FB6D0 | #AE3A5C | #F29CB6 | #00796F | #7FD3C8 |
| chart-cat-7 | #7A6A58 | #CDB9A1 | #4D6A7A | #A6BFCD | #B0306A | #FF9EC3 |
| chart-cat-8 | #66737C | #AEBDC8 | #73552A | #DCC39A | #5B6670 | #B7C3CC |
| chart-seq-1 | #D3ECF3 | #1E3A42 | #D6DDF2 | #2A3352 | #FBD8CC | #4A2A23 |
| chart-seq-2 | #9FD3E2 | #245A68 | #A9B8E3 | #3C4C80 | #F4A68E | #7A3B2C |
| chart-seq-3 | #62AFC5 | #2F7C8F | #7890CF | #5A70B0 | #E3765A | #B5563C |
| chart-seq-4 | #2E869E | #5EADC3 | #4865B1 | #8499DC | #C24A2E | #E8826A |
| chart-seq-5 | #165A6B | #A3DDEC | #23408E | #B3C3FF | #8E2A14 | #FFB59F |
| chart-grid | #DEE3E6 | #303639 | #E3DED2 | #37342E | #EBDACF | #3E3233 |
| chart-axis-label | #40484C | #BFC8CC | = on-surface-variant | = on-surface-variant | #53433F | #D8C2BB |
Rules: categorical colours are assigned to accounts in created_at order (Vardag 1, Huset 2, Gotland 2026 3, Japan 2027 4, cycling after 8); categories always use their own category colour, so a category looks the same in lists and charts. Sequential ramps are for single-series views (a highlighted bucket, "Min del" totals); seq-1 and seq-2 are backgrounds only (< 3:1). Stacked segments are separated by a 2 dp gap in the surface colour so adjacent similar hues stay distinct.
6. Typography
| Direction | Typeface(s) | Licence | Amounts |
|---|---|---|---|
| Skärgård | Roboto Flex (variable: wght, wdth, opsz) | OFL 1.1 | Roboto Flex with tnum; hero uses wdth 84 |
| Kvitto | IBM Plex Sans (text), IBM Plex Mono (amounts, captions) | OFL 1.1 | Plex Mono (tabular by nature) |
| Kalas | Nunito | OFL 1.1 | Nunito (default figures tabular, verified in renders) |
Type scale (sp / line height / weight):
| Style | Skärgård | Kvitto | Kalas |
|---|---|---|---|
| display-large | 57/64 400 | 57/64 400 (unused) | 57/64 800 |
| display-medium | 45/52 400 | 45/52 400 (unused) | 45/52 800 |
| display-small | 36/44 400 | 36/44 400 (unused) | 36/44 800 |
| headline-large | 32/40 500 | 30/38 500 | 32/40 800 |
| headline-medium | 28/36 500 | 26/34 500 | 28/36 800 |
| headline-small | 24/32 500 | 22/30 500 | 24/32 800 |
| title-large | 22/28 500 | 20/28 500 | 22/28 800 |
| title-medium | 16/24 560 | 16/24 500 | 16/24 700 |
| title-small | 14/20 560 | 14/20 600 | 14/20 800 |
| body-large | 16/24 400 | 16/24 400 | 16/24 500 |
| body-medium | 14/20 400 | 14/20 400 | 14/20 500 |
| body-small | 12/16 400 | 12/16 400 | 12/16 600 |
| label-large | 14/20 560 | 14/20 500 | 14/20 800 |
| label-medium | 12/16 560 | 12/16 500 | 12/16 700 |
| label-small | 11/16 560 | 11/16 500 Mono caps, tracking 0.08 em | 11/16 700 |
| amount-hero | 60/64 720 wdth 84, decimals and kr at 50 % | 44/52 500 Mono | 44/52 900 |
| amount-large | 32/40 650 wdth 92 | 28/36 500 Mono | 28/36 900 |
| amount-medium | 16/24 620 | 15/22 500 Mono | 18/24 800 |
| amount-small | 14/20 520 | 12/16 400 Mono | 15/20 800 |
Font scale: sp follows Android's non-linear scaling (Android 14+, Compose default): text ≥ 24 sp grows less than smaller text, so a 60 sp amount does not double at 200 %. The 200 % frames approximate this. Amounts never ellipsize: they wrap or step down one size.
7. Spacing (dp)
All three use one 4 dp scale: space-1 4, space-2 8, space-3 12, space-4 16, space-5 20, space-6 24, space-8 32, space-10 40, space-12 48, space-16 64 (Kvitto does not use 40 and 64). Screen gutter 16 in all directions.
| Measure | Skärgård | Kvitto | Kalas |
|---|---|---|---|
| card padding | 20 | 20 (receipt) | 20 |
| home account row | ~72 (card row) | 60 | ~76 (card) |
| ledger row | 72 | 60 | 72 |
| settings row | 56 | 56 | 56 |
| keypad key | 64 | 52 | 52 |
| gap between grouped items | 2 | rule (1 dp dashed) | 12 |
8. Shapes (corner radius, dp)
M3 shape tokens: extraSmall 4, small 8, medium 12, large 16, largeIncreased 20, extraLarge 28, extraLargeIncreased 32, extraExtraLarge 48, full.
| Component | Skärgård | Kvitto | Kalas |
|---|---|---|---|
| buttons, chips | full | small 8 | full |
| text fields | large 16 (outlined) | extraSmall 4 | large 16 (filled, no indicator) |
| cards | extraLarge 28 | none (receipt zig-zag edge, 10 dp teeth) | 24–28 |
| balance hero | extraLargeIncreased 32 | top corners 8, zig-zag bottom | extraLarge 28 |
| grouped/segmented lists | outer 20, inner 4 | none, rules | outer 24, inner 8 |
| category icon container | medium 12 | extraSmall 4 | MaterialShapes Cookie4Sided (fallback 30 %) |
| avatars | MaterialShapes Cookie9/12 (fallback circle) | full | MaterialShapes Sunny (fallback circle) |
| FAB | largeIncreased 20 | medium 12 | largeIncreased 20 |
| dialogs | extraLarge 28 | large 16 | extraLarge 28 |
| keypad keys | full, morph to 16 on press | small 8 | full |
9. Elevation and motion
| Skärgård | Kvitto | Kalas | |
|---|---|---|---|
| elevation model | tonal (surface-container levels); 2 dp shadow on menus, 3 dp on FAB | almost none: rules and tones; shadow only on menus, FAB, dialogs | tonal + soft warm shadow on light cards (0 1 2, 0 2 8, 10 % brown); no shadows in dark |
| motion scheme | MotionScheme.expressive() springs: spatial fast 0.6/800, default 0.8/380, slow 0.8/200; effects 1.0/3800, 1600, 800 |
standard easing curves: receipt print reveal 350 ms emphasizedDecelerate, number roll 250 ms per digit, "Kvitt" stamp 200 ms, push shared-axis X 300 ms, tabs fade-through 200 ms | MotionScheme.expressive(); seesaw re-tilt spring 0.55/300; amount count-up 400 ms emphasizedDecelerate; bunting drop with 40 ms stagger when settled |
| stable fallback | MotionScheme.standard() / tween 200–500 ms emphasized |
(already stable) | MotionScheme.standard() |
| reduced motion | everything except fades snaps | everything becomes a 150 ms crossfade | springs critically damped |
10. Icons
Material Symbols (Apache 2.0), as a bundled variable font or vector drawables generated from it.
| Skärgård | Kvitto | Kalas | |
|---|---|---|---|
| style | Rounded | Sharp | Rounded |
| weight / grade / optical size | 400 / 0 / 24 | 300 / 0 / 20–24 | 500–600 / 0 / 24 |
| fill | 1 for selected nav item and category icons, else 0 | 0, except the selected nav item | 1 for category icons and selected nav item |
Category icons: the 30 tokens of SPEC §9.7. Other icons used by all directions: home, bar_chart, settings, add, close, arrow_back, more_vert, edit, delete, swap_horiz, payments, cloud_upload / cloud_off / cloud_done, sync, warning, info, history, event_repeat, devices, person_add, content_paste, share, content_copy, drag_indicator, archive / unarchive, backspace, system_update, phonelink_erase.