W1 web Home and accounts: W-2 Home, W-3 account detail, W-4 account editor

Home (mirrors S-4, S-3 while the partner has not joined): global balance hero
with the seesaw and §9.3 wording, Settle up, active accounts with balance and
this month's count, collapsed "Arkiverade (n)" kept for the session, empty,
loading and error states, New expense when an active account exists.

Account detail (S-5): header with default split, split bar, archived badge and
balance; expenses and settlements interleaved by date, grouped by month with
household spend (settlement rows carry the allocation, AC-11.7); overflow menu
with Edit, Archive/Unarchive (undo snackbar, D-071) and Delete only when
allowed (AC-6.5); not-found, loading and error states.

Account editor (S-6): name (1-60 code points, name_taken on the field), two
percent fields that always sum to 100 with two decimals, slider and presets,
the "Av 100,00 kr" preview; discard dialog with a title and no body (D-080)
on every navigation away; E-18/E-19 apply the returned row.

The account preset for W-5 and W-7 is the query parameter `account`
(proposed D-144). Tests over a shared snapshot fixture and the fake server.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
2026-10-21 21:25:52 +02:00
parent aaa09d9073
commit 934eee793c
35 changed files with 3705 additions and 13 deletions
+143
View File
@@ -0,0 +1,143 @@
.page {
container-type: inline-size;
padding: 0 var(--gutter);
}
.grid {
display: flex;
flex-direction: column;
gap: var(--gap-section);
}
.heroColumn,
.accounts {
display: flex;
flex-direction: column;
gap: var(--gap-section);
min-width: 0;
}
/* Desktop: the balance beside the accounts. */
@container (min-width: 760px) {
.grid {
display: grid;
grid-template-columns: minmax(300px, 380px) minmax(0, 1fr);
align-items: start;
gap: var(--s6);
}
.heroColumn {
position: sticky;
top: var(--s4);
}
}
.sectionHeader {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--s2);
min-height: var(--touch-target);
}
.sectionTitle {
font: var(--type-title-medium);
letter-spacing: var(--tracking-title-medium);
}
.list {
display: flex;
flex-direction: column;
gap: var(--s2);
margin: 0;
padding: 0;
list-style: none;
}
.collapsible {
display: flex;
align-items: center;
gap: var(--s3);
min-height: var(--row-min);
padding: 0 var(--s4);
border: none;
border-radius: var(--radius-large);
background: var(--surface-container-low);
color: var(--on-surface-variant);
font: var(--type-title-small);
letter-spacing: var(--tracking-title-small);
text-align: start;
cursor: pointer;
}
.collapsible:hover {
background: var(--surface-container);
}
.collapsibleLabel {
flex: 1;
}
.skeleton {
display: block;
height: 76px;
border-radius: var(--radius-account-card);
background: var(--surface-container-high);
}
.addLabel {
white-space: nowrap;
}
@media (max-width: 479px) {
.addLabel {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
}
.emptyColumn {
display: flex;
flex-direction: column;
gap: var(--gap-section);
max-width: 640px;
}
.welcome {
flex-direction: row;
align-items: center;
gap: var(--s4);
}
.pair {
display: inline-flex;
flex: none;
}
.pairAvatar + .pairAvatar {
margin-left: -10px;
box-shadow: 0 0 0 2px var(--card);
}
.welcomeText {
display: flex;
flex-direction: column;
}
.welcomeTitle {
font: var(--type-title-medium);
letter-spacing: var(--tracking-title-medium);
}
.welcomeBody {
font: var(--type-body-medium);
letter-spacing: var(--tracking-body-medium);
color: var(--on-surface-variant);
}
.empty {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--s3);
padding: var(--s8) var(--gutter);
text-align: center;
}
.pile {
display: inline-flex;
}
.pile > * + * {
margin-left: -12px;
}
.emptyTitle {
font: var(--type-headline-small);
}
.emptyBody {
max-width: 44ch;
font: var(--type-body-large);
letter-spacing: var(--tracking-body-large);
color: var(--on-surface-variant);
}