1
2
3
4:root,
5:root[data-theme="dark"] {
6 color-scheme: dark;
7 --page: #0d0d0d;
8 --surface-1: #1a1a19;
9 --surface-2: #232321;
10 --text-primary: #ffffff;
11 --text-secondary: #c3c2b7;
12 --text-muted: #898781;
13 --grid: #2c2c2a;
14 --axis: #383835;
15 --border: rgba(255, 255, 255, 0.10);
16 --accent: #3987e5;
17 --delta-good: #0ca30c;
18 --status-good: #0ca30c;
19 --status-warning: #fab219;
20 --status-critical: #d03b3b;
21 --series-1: #3987e5;
22 --series-2: #d95926;
23 --series-3: #199e70;
24 --series-4: #c98500;
25 --series-5: #d55181;
26 --series-6: #008300;
27 --series-7: #9085e9;
28 --series-8: #e66767;
29}
30
31:root[data-theme="light"] {
32 color-scheme: light;
33 --page: #f9f9f7;
34 --surface-1: #fcfcfb;
35 --surface-2: #f0efec;
36 --text-primary: #0b0b0b;
37 --text-secondary: #52514e;
38 --text-muted: #898781;
39 --grid: #e1e0d9;
40 --axis: #c3c2b7;
41 --border: rgba(11, 11, 11, 0.10);
42 --accent: #2a78d6;
43 --delta-good: #006300;
44 --series-1: #2a78d6;
45 --series-2: #eb6834;
46 --series-3: #1baf7a;
47 --series-4: #eda100;
48 --series-5: #e87ba4;
49 --series-6: #008300;
50 --series-7: #4a3aa7;
51 --series-8: #e34948;
52}
53
54* { box-sizing: border-box; }
55
56html, body { margin: 0; }
57
58body {
59 background: var(--page);
60 color: var(--text-primary);
61 font: 14px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
62 padding: 20px clamp(14px, 4vw, 32px) 40px;
63 max-width: 1160px;
64 margin: 0 auto;
65}
66
67h1, h2, h3 { margin: 0; font-weight: 650; }
68h1 { font-size: 20px; }
69h2 { font-size: 15px; }
70h3 { font-size: 13px; margin-top: 16px; }
71
72a { color: var(--accent); }
73
74.visually-hidden {
75 position: absolute;
76 width: 1px; height: 1px;
77 overflow: hidden;
78 clip: rect(0 0 0 0);
79 white-space: nowrap;
80}
81
82
83
84.topbar {
85 display: flex;
86 align-items: center;
87 justify-content: space-between;
88 gap: 12px;
89 flex-wrap: wrap;
90 padding-bottom: 18px;
91}
92
93.brand { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
94.tagline { color: var(--text-muted); font-size: 13px; }
95.topbar-actions { display: flex; gap: 8px; }
96
97
98
99.btn {
100 background: var(--surface-2);
101 color: var(--text-primary);
102 border: 1px solid var(--border);
103 border-radius: 8px;
104 padding: 7px 12px;
105 font: inherit;
106 cursor: pointer;
107}
108.btn:hover { border-color: var(--axis); }
109.btn:focus-visible,
110input:focus-visible,
111select:focus-visible {
112 outline: 2px solid var(--accent);
113 outline-offset: 1px;
114}
115.btn-primary {
116 background: var(--accent);
117 border-color: transparent;
118 color: #ffffff;
119 font-weight: 600;
120}
121.btn-primary:hover { filter: brightness(1.1); }
122.btn-ghost { background: transparent; }
123.btn-sm { padding: 3px 9px; font-size: 12px; border-radius: 6px; }
124.btn-danger {
125 background: transparent;
126 border-color: transparent;
127 color: var(--status-critical);
128}
129.btn-danger:hover { border-color: var(--status-critical); }
130
131input, select {
132 background: var(--surface-2);
133 color: var(--text-primary);
134 border: 1px solid var(--border);
135 border-radius: 8px;
136 padding: 7px 10px;
137 font: inherit;
138}
139
140.field { display: flex; flex-direction: column; gap: 4px; }
141.field-grow { flex: 1; min-width: 160px; }
142.field-label { font-size: 12px; color: var(--text-secondary); }
143
144
145
146.card {
147 background: var(--surface-1);
148 border: 1px solid var(--border);
149 border-radius: 12px;
150 padding: 16px 18px;
151}
152
153.card-head {
154 display: flex;
155 align-items: baseline;
156 justify-content: space-between;
157 gap: 10px;
158 margin-bottom: 12px;
159}
160.card-sub { color: var(--text-muted); font-size: 12px; }
161
162
163
164.tiles {
165 display: grid;
166 grid-template-columns: 1.5fr 1fr 1fr;
167 gap: 14px;
168 margin-bottom: 14px;
169}
170
171.tile { display: flex; flex-direction: column; gap: 4px; }
172.tile-label { font-size: 13px; color: var(--text-secondary); }
173.tile-value { font-size: 26px; font-weight: 600; }
174.hero-value { font-size: 48px; font-weight: 650; line-height: 1.1; }
175.tile-delta { font-size: 13px; color: var(--text-secondary); min-height: 1.2em; }
176.tile-delta .delta-good { color: var(--delta-good); }
177.tile-delta .delta-bad { color: var(--status-critical); }
178.tile-value.net-negative { color: var(--status-critical); }
179
180
181
182.filters {
183 display: flex;
184 gap: 10px;
185 align-items: flex-end;
186 flex-wrap: wrap;
187 margin-bottom: 14px;
188}
189
190
191
192.charts-row {
193 display: grid;
194 grid-template-columns: 3fr 2fr;
195 gap: 14px;
196 margin-bottom: 14px;
197}
198
199.chart-wrap { position: relative; }
200#spend-chart { display: block; width: 100%; height: 280px; }
201
202.tooltip {
203 position: absolute;
204 pointer-events: none;
205 background: var(--surface-2);
206 border: 1px solid var(--border);
207 border-radius: 8px;
208 padding: 6px 10px;
209 font-size: 12px;
210 display: flex;
211 flex-direction: column;
212 gap: 2px;
213 box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
214 z-index: 5;
215 white-space: nowrap;
216}
217.tooltip[hidden] { display: none; }
218.tt-label { color: var(--text-muted); }
219.tt-value { color: var(--text-primary); font-weight: 600; font-variant-numeric: tabular-nums; }
220
221
222
223.budget-row {
224 padding: 9px 0;
225 border-bottom: 1px solid var(--grid);
226}
227.budget-row:last-child { border-bottom: none; }
228
229.budget-top {
230 display: flex;
231 align-items: center;
232 justify-content: space-between;
233 gap: 10px;
234 margin-bottom: 6px;
235}
236.budget-name { display: flex; align-items: center; gap: 8px; font-size: 13px; }
237.budget-nums {
238 font-size: 12px;
239 color: var(--text-secondary);
240 display: flex;
241 align-items: center;
242 gap: 4px;
243 font-variant-numeric: tabular-nums;
244}
245.budget-input {
246 width: 72px;
247 padding: 2px 6px;
248 font-size: 12px;
249 border-radius: 6px;
250 text-align: right;
251 font-variant-numeric: tabular-nums;
252}
253
254.cat-dot {
255 width: 9px;
256 height: 9px;
257 border-radius: 50%;
258 flex: 0 0 auto;
259 display: inline-block;
260}
261.cat-dot.cat-0 { background: var(--series-1); }
262.cat-dot.cat-1 { background: var(--series-2); }
263.cat-dot.cat-2 { background: var(--series-3); }
264.cat-dot.cat-3 { background: var(--series-4); }
265.cat-dot.cat-4 { background: var(--series-5); }
266.cat-dot.cat-5 { background: var(--series-6); }
267.cat-dot.cat-6 { background: var(--series-7); }
268.cat-dot.cat-7 { background: var(--series-8); }
269.cat-dot.cat-income { background: var(--text-muted); }
270
271
272
273.budget-track {
274 height: 10px;
275 border-radius: 5px;
276 overflow: hidden;
277 background: var(--surface-2);
278}
279.budget-fill { height: 100%; border-radius: 2px 5px 5px 2px; }
280.budget-track.level-ok { background: color-mix(in srgb, var(--accent) 16%, var(--surface-1)); }
281.budget-track.level-ok .budget-fill { background: var(--accent); }
282.budget-track.level-warning { background: color-mix(in srgb, var(--status-warning) 16%, var(--surface-1)); }
283.budget-track.level-warning .budget-fill { background: var(--status-warning); }
284.budget-track.level-over { background: color-mix(in srgb, var(--status-critical) 18%, var(--surface-1)); }
285.budget-track.level-over .budget-fill { background: var(--status-critical); }
286
287.budget-note {
288 margin-top: 5px;
289 font-size: 12px;
290 color: var(--text-muted);
291 display: flex;
292 align-items: center;
293 gap: 6px;
294}
295.status-ic { font-size: 11px; }
296.status-ic.level-warning { color: var(--status-warning); }
297.status-ic.level-over { color: var(--status-critical); }
298
299
300
301#txn-form {
302 display: flex;
303 gap: 10px;
304 align-items: flex-end;
305 flex-wrap: wrap;
306 margin-bottom: 4px;
307}
308.form-buttons { display: flex; gap: 8px; }
309
310.form-error {
311 color: var(--status-critical);
312 font-size: 13px;
313 min-height: 1.2em;
314 margin: 4px 0;
315}
316.import-status {
317 color: var(--text-secondary);
318 font-size: 13px;
319 margin: 0 0 6px;
320 min-height: 1.2em;
321}
322
323
324
325.table-scroll { overflow-x: auto; }
326
327table { width: 100%; border-collapse: collapse; }
328th {
329 text-align: left;
330 font-size: 12px;
331 font-weight: 600;
332 color: var(--text-secondary);
333 padding: 8px;
334 border-bottom: 1px solid var(--axis);
335}
336td {
337 padding: 9px 8px;
338 border-bottom: 1px solid var(--grid);
339 vertical-align: middle;
340}
341tbody tr:hover { background: color-mix(in srgb, var(--surface-2) 55%, transparent); }
342tbody tr.editing { outline: 2px solid var(--accent); outline-offset: -2px; }
343
344.td-date { white-space: nowrap; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
345.td-category { white-space: nowrap; }
346.td-category .cat-dot { margin-right: 7px; }
347.col-amount, .td-amount { text-align: right; }
348.td-amount { font-variant-numeric: tabular-nums; white-space: nowrap; }
349.td-amount.income { color: var(--delta-good); }
350.col-actions, .td-actions { text-align: right; white-space: nowrap; }
351tr.empty td { color: var(--text-muted); text-align: center; padding: 24px; }
352
353
354
355footer {
356 display: flex;
357 justify-content: space-between;
358 gap: 10px;
359 flex-wrap: wrap;
360 margin-top: 18px;
361 color: var(--text-muted);
362 font-size: 13px;
363}
364
365kbd {
366 background: var(--surface-2);
367 border: 1px solid var(--border);
368 border-bottom-width: 2px;
369 border-radius: 4px;
370 padding: 1px 6px;
371 font-size: 12px;
372 font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
373 color: var(--text-primary);
374}
375
376dialog {
377 background: var(--surface-1);
378 color: var(--text-primary);
379 border: 1px solid var(--border);
380 border-radius: 12px;
381 padding: 20px 24px;
382 max-width: 440px;
383 width: calc(100vw - 48px);
384}
385dialog::backdrop { background: rgba(0, 0, 0, 0.55); }
386dialog p, dialog td { color: var(--text-secondary); font-size: 13px; }
387dialog code, dialog em { color: var(--text-primary); }
388.shortcut-table td { border: none; padding: 4px 10px 4px 0; }
389dialog form { margin-top: 14px; }
390
391
392
393@media (max-width: 900px) {
394 .charts-row { grid-template-columns: 1fr; }
395 .tiles { grid-template-columns: 1fr; }
396 .hero-value { font-size: 38px; }
397}
398
Discussion
1 comment on this trajectory. Recorded by @patrick-toulme.