1
2
3:root[data-theme="dark"] {
4 color-scheme: dark;
5 --page: #0d0d0d;
6 --surface-1: #1a1a19;
7 --surface-2: #222221;
8 --text-primary: #ffffff;
9 --text-secondary: #c3c2b7;
10 --text-muted: #898781;
11 --grid: #2c2c2a;
12 --baseline: #383835;
13 --border: rgba(255, 255, 255, 0.10);
14 --series-1: #3987e5;
15 --series-1-track: rgba(57, 135, 229, 0.18);
16 --status-good: #0ca30c;
17 --status-warning: #fab219;
18 --status-warning-track: rgba(250, 178, 25, 0.18);
19 --status-critical: #d03b3b;
20 --status-critical-track: rgba(208, 59, 59, 0.20);
21}
22
23* { box-sizing: border-box; }
24
25html, body {
26 margin: 0;
27 padding: 0;
28}
29
30body {
31 background: var(--page);
32 color: var(--text-primary);
33 font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
34 font-size: 14px;
35 line-height: 1.45;
36}
37
38.app {
39 max-width: 1080px;
40 margin: 0 auto;
41 padding: 24px 20px 48px;
42 display: flex;
43 flex-direction: column;
44 gap: 16px;
45}
46
47
48
49.app-header {
50 display: flex;
51 align-items: center;
52 justify-content: space-between;
53 gap: 16px;
54 flex-wrap: wrap;
55}
56
57.brand {
58 display: flex;
59 align-items: center;
60 gap: 10px;
61}
62
63.brand-mark {
64 width: 14px;
65 height: 14px;
66 border-radius: 4px;
67 background: var(--series-1);
68}
69
70.brand h1 {
71 font-size: 18px;
72 font-weight: 650;
73 margin: 0;
74 letter-spacing: -0.01em;
75}
76
77.header-actions {
78 display: flex;
79 gap: 8px;
80 align-items: center;
81}
82
83
84
85button {
86 font: inherit;
87 cursor: pointer;
88 border-radius: 8px;
89 border: 1px solid transparent;
90 padding: 7px 14px;
91 transition: background 0.12s ease, border-color 0.12s ease;
92}
93
94.btn-primary {
95 background: var(--series-1);
96 color: #ffffff;
97 font-weight: 600;
98}
99.btn-primary:hover { background: #2a78d6; }
100
101.btn-ghost {
102 background: transparent;
103 color: var(--text-secondary);
104 border-color: var(--border);
105}
106.btn-ghost:hover {
107 background: var(--surface-2);
108 color: var(--text-primary);
109}
110
111.btn-icon {
112 padding: 7px 11px;
113 font-weight: 600;
114}
115
116.btn-small {
117 padding: 3px 9px;
118 font-size: 12.5px;
119 border-radius: 6px;
120}
121
122.btn-danger:hover {
123 color: #e66767;
124 border-color: rgba(230, 103, 103, 0.4);
125}
126
127
128
129.stat-row {
130 display: grid;
131 grid-template-columns: 1.6fr 1fr 1fr;
132 gap: 12px;
133}
134
135.stat-tile {
136 background: var(--surface-1);
137 border: 1px solid var(--border);
138 border-radius: 12px;
139 padding: 16px 18px;
140 display: flex;
141 flex-direction: column;
142 gap: 4px;
143}
144
145.stat-label {
146 color: var(--text-muted);
147 font-size: 12.5px;
148}
149
150.stat-value {
151 font-size: 48px;
152 font-weight: 600;
153 letter-spacing: -0.02em;
154 line-height: 1.1;
155}
156
157.stat-value-sm {
158 font-size: 26px;
159}
160
161.stat-value.is-negative { color: var(--status-critical); }
162
163
164
165.grid-2 {
166 display: grid;
167 grid-template-columns: 3fr 2fr;
168 gap: 12px;
169}
170
171.card {
172 background: var(--surface-1);
173 border: 1px solid var(--border);
174 border-radius: 12px;
175 padding: 16px 18px;
176}
177
178.card-head {
179 display: flex;
180 align-items: baseline;
181 justify-content: space-between;
182 gap: 12px;
183 margin-bottom: 12px;
184}
185
186.card-head h2 {
187 font-size: 14.5px;
188 font-weight: 650;
189 margin: 0;
190}
191
192.card-sub {
193 color: var(--text-muted);
194 font-size: 12.5px;
195}
196
197.card-foot {
198 color: var(--text-muted);
199 font-size: 12px;
200 margin: 10px 0 0;
201}
202
203
204
205.chart-wrap {
206 position: relative;
207 height: 260px;
208}
209
210#spending-chart {
211 width: 100%;
212 height: 100%;
213 display: block;
214}
215
216.chart-tooltip {
217 position: absolute;
218 pointer-events: none;
219 background: var(--surface-2);
220 border: 1px solid var(--border);
221 border-radius: 8px;
222 padding: 8px 10px;
223 font-size: 12.5px;
224 color: var(--text-secondary);
225 display: flex;
226 flex-direction: column;
227 gap: 2px;
228 white-space: nowrap;
229 box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
230 z-index: 5;
231}
232
233.chart-tooltip .tt-title {
234 color: var(--text-primary);
235 font-weight: 600;
236}
237
238.chart-tooltip .tt-row { display: flex; align-items: center; gap: 6px; }
239.chart-tooltip .tt-row b { color: var(--text-primary); font-weight: 600; }
240.chart-tooltip .tt-dim { color: var(--text-muted); }
241
242.chart-tooltip .tt-key {
243 width: 8px;
244 height: 8px;
245 border-radius: 50%;
246 background: var(--series-1);
247 display: inline-block;
248}
249
250
251
252.budget-list {
253 display: flex;
254 flex-direction: column;
255 gap: 12px;
256 max-height: 232px;
257 overflow-y: auto;
258 padding-right: 4px;
259}
260
261.budget-row { user-select: none; }
262.budget-editable { cursor: pointer; }
263.budget-editable:hover .budget-name { color: var(--text-primary); }
264
265.budget-head {
266 display: flex;
267 justify-content: space-between;
268 align-items: baseline;
269 gap: 8px;
270 margin-bottom: 4px;
271}
272
273.budget-name {
274 color: var(--text-secondary);
275 font-size: 13px;
276}
277
278.budget-val {
279 color: var(--text-muted);
280 font-size: 12px;
281 font-variant-numeric: tabular-nums;
282}
283
284.budget-val b {
285 color: var(--text-secondary);
286 font-weight: 600;
287}
288
289.budget-pct { margin-right: 4px; }
290
291.badge-over {
292 color: var(--status-critical);
293 font-weight: 600;
294}
295
296
297.budget-track {
298 height: 10px;
299 border-radius: 5px;
300 background: var(--series-1-track);
301 overflow: hidden;
302}
303
304.budget-fill {
305 height: 100%;
306 background: var(--series-1);
307 border-radius: 0 4px 4px 0;
308 min-width: 2px;
309}
310
311.budget-near .budget-track { background: var(--status-warning-track); }
312.budget-near .budget-fill { background: var(--status-warning); }
313.budget-over .budget-track { background: var(--status-critical-track); }
314.budget-over .budget-fill { background: var(--status-critical); border-radius: 0; }
315
316
317
318.filter-row {
319 display: flex;
320 gap: 8px;
321 margin-bottom: 12px;
322 flex-wrap: wrap;
323}
324
325input[type="search"],
326input[type="text"],
327input[type="date"],
328input[type="number"],
329select {
330 font: inherit;
331 color: var(--text-primary);
332 background: var(--surface-2);
333 border: 1px solid var(--border);
334 border-radius: 8px;
335 padding: 7px 10px;
336}
337
338input:focus-visible, select:focus-visible, button:focus-visible {
339 outline: 2px solid var(--series-1);
340 outline-offset: 1px;
341}
342
343#filter-search { flex: 1; min-width: 180px; }
344
345
346
347.table-wrap { overflow-x: auto; }
348
349.tx-table {
350 width: 100%;
351 border-collapse: collapse;
352}
353
354.tx-table th {
355 text-align: left;
356 color: var(--text-muted);
357 font-size: 12px;
358 font-weight: 500;
359 padding: 6px 10px;
360 border-bottom: 1px solid var(--baseline);
361}
362
363.tx-table td {
364 padding: 8px 10px;
365 border-bottom: 1px solid var(--grid);
366 vertical-align: middle;
367}
368
369.tx-table tbody tr:hover { background: var(--surface-2); }
370
371.col-date {
372 color: var(--text-muted);
373 font-variant-numeric: tabular-nums;
374 white-space: nowrap;
375}
376
377.col-desc { color: var(--text-secondary); }
378
379.col-amount {
380 text-align: right;
381 font-variant-numeric: tabular-nums;
382 white-space: nowrap;
383}
384
385th.col-amount { text-align: right; }
386
387.col-amount.is-income { color: var(--status-good); }
388
389.col-actions {
390 text-align: right;
391 white-space: nowrap;
392 width: 120px;
393}
394
395.col-actions button { opacity: 0; }
396.tx-table tr:hover .col-actions button,
397.col-actions button:focus-visible { opacity: 1; }
398
399.cat-chip {
400 display: inline-block;
401 padding: 2px 9px;
402 border-radius: 999px;
403 background: var(--surface-2);
404 border: 1px solid var(--border);
405 color: var(--text-secondary);
406 font-size: 12px;
407}
408
409.empty-note {
410 color: var(--text-muted);
411 text-align: center;
412 padding: 24px 10px;
413}
414
415
416
417.overlay {
418 position: fixed;
419 inset: 0;
420 background: rgba(0, 0, 0, 0.55);
421 display: flex;
422 align-items: flex-start;
423 justify-content: center;
424 padding: 10vh 20px 20px;
425 z-index: 20;
426}
427
428.panel-card {
429 background: var(--surface-1);
430 border: 1px solid var(--border);
431 border-radius: 14px;
432 padding: 20px 22px;
433 width: 100%;
434 max-width: 420px;
435 display: flex;
436 flex-direction: column;
437 gap: 12px;
438 box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
439}
440
441.panel-card h2 {
442 margin: 0;
443 font-size: 16px;
444}
445
446.panel-card label {
447 display: flex;
448 flex-direction: column;
449 gap: 4px;
450}
451
452.panel-card label > span {
453 color: var(--text-muted);
454 font-size: 12.5px;
455}
456
457.panel-card small {
458 color: var(--text-muted);
459 font-size: 11.5px;
460}
461
462.panel-actions {
463 display: flex;
464 justify-content: flex-end;
465 gap: 8px;
466 margin-top: 4px;
467}
468
469.form-error {
470 color: var(--status-critical);
471 background: var(--status-critical-track);
472 border-radius: 8px;
473 padding: 8px 10px;
474 margin: 0;
475 font-size: 13px;
476}
477
478.shortcut-list {
479 margin: 0;
480 display: flex;
481 flex-direction: column;
482 gap: 8px;
483}
484
485.shortcut-list > div {
486 display: flex;
487 align-items: center;
488 gap: 12px;
489}
490
491.shortcut-list dt { min-width: 70px; }
492.shortcut-list dd { margin: 0; color: var(--text-secondary); }
493
494kbd {
495 background: var(--surface-2);
496 border: 1px solid var(--border);
497 border-bottom-width: 2px;
498 border-radius: 5px;
499 padding: 1px 6px;
500 font-family: inherit;
501 font-size: 12px;
502 color: var(--text-secondary);
503}
504
505
506
507.app-footer {
508 display: flex;
509 justify-content: space-between;
510 align-items: center;
511 gap: 12px;
512 color: var(--text-muted);
513 font-size: 12.5px;
514 padding-top: 4px;
515 flex-wrap: wrap;
516}
517
518.app-footer a { color: var(--text-secondary); }
519
520.toast {
521 position: fixed;
522 left: 50%;
523 bottom: 24px;
524 transform: translateX(-50%) translateY(12px);
525 background: var(--surface-2);
526 color: var(--text-primary);
527 border: 1px solid var(--border);
528 border-radius: 10px;
529 padding: 10px 16px;
530 font-size: 13px;
531 opacity: 0;
532 pointer-events: none;
533 transition: opacity 0.18s ease, transform 0.18s ease;
534 z-index: 30;
535 box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
536}
537
538.toast.show {
539 opacity: 1;
540 transform: translateX(-50%) translateY(0);
541}
542
543.visually-hidden {
544 position: absolute;
545 width: 1px;
546 height: 1px;
547 overflow: hidden;
548 clip: rect(0 0 0 0);
549 white-space: nowrap;
550}
551
552
553
554@media (max-width: 820px) {
555 .grid-2 { grid-template-columns: 1fr; }
556 .stat-row { grid-template-columns: 1fr; }
557 .stat-value { font-size: 36px; }
558 .col-actions button { opacity: 1; }
559}
560
Discussion
1 comment on this trajectory. Recorded by @patrick-toulme.