${chip('Vardag', { dot: 'chart-cat-1', drop: true })}${chip('14 okt.', { icon: 'event', drop: true })}${chip('Du', { k: 'Betalt av', avatar: 'jacob', drop: true })}
Delning${ic('expand_less', { color: 'on-surface-variant' })}
@@ -877,7 +879,7 @@ function scrExpense(kind){
const acts = kind === 'deleted' ? '' : iconBtn('edit', 'Ändra') + iconBtn('delete', 'Ta bort');
let b = '';
if (kind === 'recurring') {
- b = detailHero({ cat: 'home', desc: 'Hyra september', acc: 'Huset', amt: 1240000, rec: 'Hyra' }) +
+ b = detailHero({ cat: 'housing', desc: 'Hyra september', acc: 'Huset', amt: 1240000, rec: 'Hyra' }) +
infoRows([['event', 'Datum', 'fredag 25 september 2026'], ['person', 'Betalt av', `${avatar('anna', 24)}Anna`], ['call_split', 'Delning', sharesRow(744000, 496000, 'Kontots standard 60/40')]]) +
timeline([{ t: 'Skapad automatiskt (återkommande) · 25 sep. 06:00' }]);
} else if (kind === 'deleted') {
@@ -974,7 +976,7 @@ function scrAnalytics(v){
Utgifter över tid
${stackChart(buckets, series, MONTHS, { max: 4500000, ticks: [0, 1500000, 3000000, 4500000], hl: 5, aria: 'Utgifter över tid' })}${series.map(s => `${CAT[s.key].sv}`).join('')}
Per kategori
${catBreakdown(3)}`;
}
- return screen({ top: topBar({ nav: null, title: 'Statistik', bg: v === 'scrolled' ? 'surface-container' : '' }), body: b, nav: 1, padStyle: 'gap:10px', scroll: v === 'scrolled' ? 360 : 0 });
+ return screen({ top: topBar({ nav: null, title: 'Statistik', bg: v === 'scrolled' ? 'surface-container' : '' }), body: b, nav: 1, padStyle: 'gap:10px', scroll: v === 'scrolled' ? 470 : 0 });
}
function scrDrill(){
const rows = VARDAG[0].rows.filter(r => r.cat === 'groceries');
@@ -998,17 +1000,17 @@ function scrProfile(){
${field({ label: 'Namn', value: 'Jacob', focus: true, sup: 'Så här ser Anna dig i Kvitt.' })}`;
return screen({ top: topBar({ title: 'Profil', actions: btn('Spara') }), body: b, padStyle: 'gap:14px' });
}
-function scrCategories(){
+function scrCategories(scrolled){
const row = (k, o = {}) => `${o.noDrag ? '' : `${ic('drag_indicator')}`}${catTile(k, 36, { muted: o.muted })}${CAT[k].sv}${ic('chevron_right', { color: 'on-surface-variant' })}
`;
const b = `${DEFAULT_CATS.map(k => row(k)).join('')}
${archivedRow(true)}${row('pant', { noDrag: true, muted: true })}
`;
- return screen({ top: topBar({ title: 'Kategorier', actions: iconBtn('add', 'Ny kategori') }), body: b, padStyle: 'gap:4px' });
+ return screen({ top: topBar({ title: 'Kategorier', actions: iconBtn('add', 'Ny kategori'), bg: scrolled ? 'surface-container' : '' }), body: b, padStyle: 'gap:4px', scroll: scrolled ? 330 : 0 });
}
function scrCategoryEditor(){
const b = `${catTile('groceries', 64)}
${field({ label: 'Namn', value: 'Matvaror', focus: true })}
Standardnamn:
Mat & hushåll${btn('Återställ namn', { kind: 'text', icon: 'restart_alt' })}
Ikon
- ${ICONS30.map(n => `${ic(n, { f: n === 'shopping_cart' })}`).join('')}
+ ${ICONS30.map(n => `${ic(n, { f: n === 'shopping_cart' })}`).join('')}
Färg
- ${COLORS12.map(c => `${c === 'green' ? ic('check', { size: 22 }) : ''}`).join('')}
+ ${COLORS12.map(c => `${c === 'green' ? ic('check', { size: 22 }) : ''}`).join('')}
${btn('Arkivera', { kind: 'outlined', icon: 'inventory_2' })}${ic('lock', { size: 16 })}Kan inte tas bort: standardkategori
`;
return screen({ top: topBar({ nav: 'close', title: 'Ändra kategori', actions: btn('Spara') }), body: b, padStyle: 'gap:10px' });
}
@@ -1032,14 +1034,14 @@ function scrRemoved(){
return screen({ body: b, padStyle: 'gap:0;min-height:100%', bottom: `${btn('Para ihop igen', { m: true, full: true, icon: 'link' })}
` });
}
function scrRecurring(){
- const T = [['home', 'Hyra', 1240000, 'Huset · Anna betalar', 'Varje månad den 25:e
Nästa 25\u00A0okt.'], ['utilities', 'Bahnhof bredband', 39900, 'Huset · Du betalar', 'Varje månad den 28:e
Nästa 28\u00A0okt.'], ['entertainment', 'Netflix', 17900, 'Vardag · Du betalar', 'Varje månad den 3:e
Nästa 3\u00A0nov.'], ['entertainment', 'Spotify Family', 25900, 'Vardag · Anna betalar', 'Varje månad den 12:e', true]];
+ const T = [['housing', 'Hyra', 1240000, 'Huset · Anna betalar', 'Varje månad den 25:e
Nästa 25\u00A0okt.'], ['utilities', 'Bahnhof bredband', 39900, 'Huset · Du betalar', 'Varje månad den 28:e
Nästa 28\u00A0okt.'], ['entertainment', 'Netflix', 17900, 'Vardag · Du betalar', 'Varje månad den 3:e
Nästa 3\u00A0nov.'], ['entertainment', 'Spotify Family', 25900, 'Vardag · Anna betalar', 'Varje månad den 12:e', true]];
const b = `${T.map(([k, d, a, w, s, p]) => `
${catTile(k, 40, { muted: p })}
${d}
${w}
${p ? `${ic('pause', { size: 14 })}Pausad Varje månad den 12:e` : s}
${kr(a)}`).join('')}
`;
return screen({ top: topBar({ title: 'Återkommande utgifter' }), body: b, padStyle: 'gap:10px', fab: fab('Ny återkommande') });
}
function scrRecurringEditor(){
const b = `${amountBlock(1240000, '12' + NB + '400,00', { pad: '2px 0 0' })}
${field({ label: 'Beskrivning', value: 'Hyra' })}
- ${catQuick('home', ['groceries', 'home', 'utilities', 'transport', 'entertainment'])}
+ ${catQuick('housing', ['groceries', 'housing', 'home', 'utilities', 'transport'])}
${chip('Huset', { dot: 'chart-cat-2', drop: true })}${chip('Anna', { k: 'Betalt av', avatar: 'anna', drop: true })}${chip('Kontots standard 60/40', { k: 'Delning', icon: 'call_split', drop: true })}
Schema
${field({ label: 'Dag i månaden', value: '25' })}${field({ label: 'Första månad', value: 'september 2026', trail: ic('expand_more') })}
@@ -1100,9 +1102,9 @@ const FRAMES = [
{ id:'S-5-account-archived-menu', title:'S-5 Gotland 2026 · meny (extra)', note:'Extra ram: Ta bort konto är avstängt eftersom kontot har utgifter och en betalning.', themes:LD, render:() => scrAccount({ archived:true, menu:true }) },
{ id:'S-6-account-editor', title:'S-6 Nytt konto', note:'Delningen som Expressive-reglage (tjock delad bana, smalt handtag) + två procentfält som alltid summerar till 100 + snabbval i en ButtonGroup.', themes:LD, render:() => scrAccountEditor(false) },
{ id:'S-6-account-editor-offline', title:'S-6 Nytt konto · offline', note:'Kräver anslutning: fälten och Spara är avstängda.', themes:LD, render:() => scrAccountEditor(true) },
- { id:'S-7-editor', title:'S-7 Ny utgift · 10 sekunder', note:'Egen siffertangentbordspanel i appen (beskrivningen använder systemtangentbordet). Kategoriraden visar de mest använda; Nöje valdes automatiskt utifrån beskrivningen (Systembolaget) och bildtexten "Vald utifrån beskrivningen" försvinner så fort man väljer kategori själv. Delning-chippet öppnar delningen med ett tryck. Spara i appfältet.', themes:LD, render:() => scrEditor(false) },
- { id:'S-7-editor-split', title:'S-7 Ny utgift · exakta belopp med fel', note:'Beloppet fälls ihop till en kompakt rad när man scrollar; raden visar också den automatiskt valda kategorin. Alla fyra lägen syns som valchips. Annas andel räknas ut och visas skrivskyddad; Spara är avstängd.', themes:LD, render:scrEditorSplit },
- { id:'S-7-editor-full', title:'S-7 Ändra utgift · allt på en person', note:'Transport valdes utifrån beskrivningen (SL-kort). Allt på Anna: personväljare som ButtonGroup, delningsstapeln helt i Annas färg, anteckningen utfälld, Ta bort i ändringsläget.', themes:LD, render:scrEditorFull },
+ { id:'S-7-editor', title:'S-7 Ny utgift · 10 sekunder', note:'Egen siffertangentbordspanel i appen (beskrivningen använder systemtangentbordet). Kategoriraden visar de mest använda; Nöje är vald automatiskt utifrån beskrivningen (Systembolaget), utan markör; användaren kan alltid byta. Delning-chippet öppnar delningen med ett tryck. Spara i appfältet.', themes:LD, render:() => scrEditor(false) },
+ { id:'S-7-editor-split', title:'S-7 Ny utgift · exakta belopp med fel', note:'Beloppet fälls ihop till en kompakt rad när man scrollar; raden visar också den valda kategorin. Alla fyra lägen syns som valchips. Annas andel räknas ut och visas skrivskyddad; Spara är avstängd.', themes:LD, render:scrEditorSplit },
+ { id:'S-7-editor-full', title:'S-7 Ändra utgift · allt på en person', note:'Transport är vald utifrån beskrivningen (SL-kort). Allt på Anna: personväljare som ButtonGroup, delningsstapeln helt i Annas färg, anteckningen utfälld, Ta bort i ändringsläget.', themes:LD, render:scrEditorFull },
{ id:'S-7-editor-200', title:'S-7 Ny utgift · 200 %', note:'fontScale 2: beloppet och Spara syns, mellandelen scrollar, tangentbordet växer.', themes:L, fontScale:2, render:() => scrEditor(true) },
{ id:'S-8-expense', title:'S-8 Utgift ICA Maxi Lindhagen', note:'Kategorifärgen bär kortet. Historiken har sista raden "Din ändring väntar på synk" med ihålig punkt i pending-färg.', themes:LD, render:() => scrExpense('normal') },
{ id:'S-8-expense-recurring', title:'S-8 Utgift · återkommande', note:'Återkommande: Hyra som havregul etikett.', themes:LD, render:() => scrExpense('recurring') },
@@ -1113,15 +1115,16 @@ const FRAMES = [
{ id:'S-9-settle-account', title:'S-9 Gör upp · ett konto (Huset)', note:'Beloppet går att ändra (förifyllt med kontots skuld); raden är fast och följer beloppet. Ingen Lägg till konto.', themes:LD, render:() => scrSettle('account') },
{ id:'S-9-confirm-dialog', title:'S-9 Bekräfta-dialog', note:'Dialogen upprepar varningen (AC-11.5).', themes:LD, render:() => scrSettle('dialog') },
{ id:'S-10-settlement', title:'S-10 Betalning', note:'Avatar → avatar visar riktningen; orden säger den.', themes:LD, render:scrSettlement },
- { id:'S-11-analytics', title:'S-11 Statistik', note:'TalkBack: "Utgifter över tid: högst i september, 41 484 kr; lägst i maj, 24 710 kr. Hem är störst i maj till augusti, Resor i september och oktober." Per kategori: "Hem 39,7 %, Mat & hushåll 20,6 %, Resor 18,3 %."', themes:LD, render:() => scrAnalytics('default') },
+ { id:'S-11-analytics', title:'S-11 Statistik', note:'TalkBack: "Utgifter över tid: högst i september, 41 484 kr; lägst i maj, 24 710 kr. Boende är störst i maj till augusti, Resor i september och oktober." Per kategori: "Boende 34,8 %, Mat & hushåll 20,6 %, Resor 18,3 %."', themes:LD, render:() => scrAnalytics('default') },
{ id:'S-11-analytics-scrolled', title:'S-11 Statistik · scrollad (extra)', note:'Extra ram, scrollad: slutet av diagram 2 och hela diagram 3. TalkBack per konto: "Huset 44,8 %, Vardag 37,6 %, Japan 2027 15,2 %, Gotland 2026 2,5 %."', themes:LD, render:() => scrAnalytics('scrolled') },
{ id:'S-11-analytics-week', title:'S-11 Statistik · vecka, min del, per konto', note:'TalkBack: "Min del per vecka: högst vecka 41, 4 300 kr; lägst vecka 42, 1 730 kr." Kontofärgerna är desamma som på Översikt.', themes:LD, render:() => scrAnalytics('week') },
{ id:'S-11-analytics-empty', title:'S-11 Statistik · tom period', note:'Anpassad period utan utgifter.', themes:LD, render:() => scrAnalytics('empty') },
{ id:'S-12-drilldown', title:'S-12 Mat & hushåll, oktober 2026', note:'Summa och rader som i S-5.', themes:LD, render:scrDrill },
{ id:'S-13-settings', title:'S-13 Inställningar', note:'Varje rad har en egen tonad ikonplatta, grupperade i segmenterade kort.', themes:LD, render:scrSettings },
{ id:'S-14-profile', title:'S-14 Profil', note:'', themes:LD, render:scrProfile },
- { id:'S-15-categories', title:'S-15 Kategorier', note:'Dra-handtag med TalkBack-etikett "Flytta "; Pant ligger under Arkiverade.', themes:LD, render:scrCategories },
- { id:'S-15-category-editor', title:'S-15 Ändra kategori', note:'Alla 30 ikoner och 12 färger. Standardkategorier kan arkiveras men inte tas bort.', themes:LD, render:scrCategoryEditor },
+ { id:'S-15-categories', title:'S-15 Kategorier', note:'14 standardkategorier i sorteringsordning. Dra-handtag med TalkBack-etikett "Flytta ". Listan scrollar; slutet med Arkiverade syns i nästa ram.', themes:LD, render:() => scrCategories(false) },
+ { id:'S-15-categories-scrolled', title:'S-15 Kategorier · scrollad (extra)', note:'Extra ram: slutet av listan med Arkiverade (1) och den arkiverade egna kategorin Pant.', themes:LD, render:() => scrCategories(true) },
+ { id:'S-15-category-editor', title:'S-15 Ändra kategori', note:'Alla 33 ikoner (nya: key, shield, account_balance) och 14 färger (nya: plum, sand). Standardkategorier kan arkiveras men inte tas bort.', themes:LD, render:scrCategoryEditor },
{ id:'S-16-sync', title:'S-16 Synkstatus', note:'', themes:LD, render:() => scrSync(false) },
{ id:'S-16-sync-clock', title:'S-16 Synkstatus · klockan går fel', note:'', themes:LD, render:() => scrSync(true) },
{ id:'S-17-update', title:'S-17 Uppdatering · tillåt installation', note:'Visas första gången, före systemets inställning.', themes:LD, render:scrUpdateDialog },
@@ -1206,7 +1209,7 @@ function reviewPage(){
Contrast is computed in JavaScript from the same token object that themes the phones. Red marks text below 4.5:1 or graphics below 3:1. owed (sage green, partner owes you) and owing (dusty plum, you owe) are a purple/green pair, distinguishable in deuteranopia, protanopia and tritanopia, and always come with words. settled uses the straw/oat family. Extras beyond the brief's names: --card (card fill: white on off-white in light, surface-container in dark), --on-cat (icon colour on a solid category/chart tile), --shadow, --photo-* (Jacob's picture stand-in), --sys-* (neutral Android notification shade). Dark containers for straw/oat and warning are pushed toward brown (hue ≈ 32°) so they never read olive.
${paletteTable()}
Category colours (§9.7 tokens)
- Muted, dusty versions of all twelve §9.7 tokens (token names unchanged). In Kalas the category colour is used solid as the tile fill with the icon in --on-cat (white in light, brown-black in dark), so every row still starts with a colour block, just a quieter one. The container (--cat-*-container) is the colour at 18 % over surface in light and 24 % in dark; it fills unselected picker tiles (icon in the category colour) and the expense-detail hero card. Category colours are never used as text. To keep muted tiles apart, lightness is spread on purpose (indigo, brown and purple darker; yellow, orange and lime lighter) and every pair is checked with CIEDE2000 below.
+ Muted, dusty versions of the twelve §9.7 tokens plus two proposed new tokens, plum (Försäkringar) and sand (Avgifter & skatter), so each of the 14 default categories (owner decision 2026-10-18: new Boende/key/indigo, Försäkringar/shield/plum, Barn/child_care/lime, Avgifter & skatter/account_balance/sand) has its own colour. The icon set grows to 33 with key, shield and account_balance. Light brown was darkened from #7A5F50 to #6B5244 to keep it apart from sand; the archived example category Pant moved from lime to teal so it no longer shares Barn's colour. In Kalas the category colour is used solid as the tile fill with the icon in --on-cat (white in light, brown-black in dark), so every row still starts with a colour block, just a quieter one. The container (--cat-*-container) is the colour at 18 % over surface in light and 24 % in dark; it fills unselected picker tiles (icon in the category colour) and the expense-detail hero card. Category colours are never used as text. To keep muted tiles apart, lightness is spread on purpose (indigo, brown and purple darker; yellow, orange and lime lighter) and every pair is checked with CIEDE2000 below.
${deTable()}
${catTable()}
Chart colours