1
2
3
4
5
6@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
7
8:root {
9
10 --font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
11
12
13 --bg-primary: #f8fafc;
14 --bg-secondary: #ffffff;
15 --bg-card: rgba(255, 255, 255, 0.85);
16 --bg-card-hover: #ffffff;
17 --bg-input: #f1f5f9;
18 --bg-modal: rgba(255, 255, 255, 0.95);
19
20 --border-color: rgba(226, 232, 240, 0.8);
21 --border-focus: #6366f1;
22
23 --text-primary: #0f172a;
24 --text-secondary: #475569;
25 --text-muted: #94a3b8;
26
27 --brand-primary: #6366f1;
28 --brand-primary-hover: #4f46e5;
29 --brand-primary-light: rgba(99, 102, 241, 0.1);
30
31 --income-color: #10b981;
32 --income-bg: rgba(16, 185, 129, 0.1);
33 --expense-color: #f43f5e;
34 --expense-bg: rgba(244, 63, 94, 0.1);
35
36 --warning-color: #f59e0b;
37 --warning-bg: rgba(245, 158, 11, 0.1);
38
39 --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.05);
40 --shadow-md: 0 4px 12px -2px rgba(0, 0, 0, 0.05), 0 2px 6px -1px rgba(0, 0, 0, 0.03);
41 --shadow-lg: 0 12px 24px -4px rgba(0, 0, 0, 0.08), 0 4px 8px -2px rgba(0, 0, 0, 0.04);
42 --shadow-glow: 0 0 20px rgba(99, 102, 241, 0.25);
43
44 --radius-sm: 6px;
45 --radius-md: 10px;
46 --radius-lg: 16px;
47 --radius-full: 9999px;
48
49 --backdrop-blur: blur(12px);
50}
51
52[data-theme="dark"] {
53
54 --bg-primary: #0b0f17;
55 --bg-secondary: #111827;
56 --bg-card: rgba(17, 24, 39, 0.75);
57 --bg-card-hover: rgba(31, 41, 55, 0.85);
58 --bg-input: #1e293b;
59 --bg-modal: rgba(15, 23, 42, 0.95);
60
61 --border-color: rgba(255, 255, 255, 0.08);
62 --border-focus: #818cf8;
63
64 --text-primary: #f8fafc;
65 --text-secondary: #cbd5e1;
66 --text-muted: #64748b;
67
68 --brand-primary: #6366f1;
69 --brand-primary-hover: #818cf8;
70 --brand-primary-light: rgba(99, 102, 241, 0.2);
71
72 --income-color: #34d399;
73 --income-bg: rgba(52, 211, 153, 0.15);
74 --expense-color: #fb7185;
75 --expense-bg: rgba(251, 113, 133, 0.15);
76
77 --warning-color: #fbbf24;
78 --warning-bg: rgba(251, 191, 36, 0.15);
79
80 --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);
81 --shadow-md: 0 4px 14px -2px rgba(0, 0, 0, 0.4);
82 --shadow-lg: 0 16px 32px -4px rgba(0, 0, 0, 0.6);
83 --shadow-glow: 0 0 25px rgba(99, 102, 241, 0.35);
84}
85
86
87
88
89
90* {
91 box-sizing: border-box;
92 margin: 0;
93 padding: 0;
94}
95
96body {
97 font-family: var(--font-sans);
98 background-color: var(--bg-primary);
99 color: var(--text-primary);
100 min-height: 100vh;
101 line-height: 1.5;
102 -webkit-font-smoothing: antialiased;
103 transition: background-color 0.3s ease, color 0.3s ease;
104}
105
106
107body::before {
108 content: '';
109 position: fixed;
110 top: -150px;
111 right: -150px;
112 width: 500px;
113 height: 500px;
114 background: radial-gradient(circle, rgba(99, 102, 241, 0.15) 0%, rgba(0, 0, 0, 0) 70%);
115 pointer-events: none;
116 z-index: 0;
117}
118
119body::after {
120 content: '';
121 position: fixed;
122 bottom: -150px;
123 left: -150px;
124 width: 500px;
125 height: 500px;
126 background: radial-gradient(circle, rgba(16, 185, 129, 0.1) 0%, rgba(0, 0, 0, 0) 70%);
127 pointer-events: none;
128 z-index: 0;
129}
130
131#app {
132 position: relative;
133 z-index: 1;
134 max-width: 1380px;
135 margin: 0 auto;
136 padding: 24px;
137}
138
139
140
141
142
143.app-header {
144 display: flex;
145 align-items: center;
146 justify-content: space-between;
147 padding: 16px 24px;
148 background: var(--bg-card);
149 backdrop-filter: var(--backdrop-blur);
150 -webkit-backdrop-filter: var(--backdrop-blur);
151 border: 1px solid var(--border-color);
152 border-radius: var(--radius-lg);
153 margin-bottom: 24px;
154 box-shadow: var(--shadow-md);
155}
156
157.brand-container {
158 display: flex;
159 align-items: center;
160 gap: 12px;
161}
162
163.brand-logo {
164 width: 42px;
165 height: 42px;
166 background: linear-gradient(135deg, #6366f1, #a855f7);
167 border-radius: var(--radius-md);
168 display: flex;
169 align-items: center;
170 justify-content: center;
171 color: #ffffff;
172 font-size: 22px;
173 box-shadow: 0 4px 10px rgba(99, 102, 241, 0.4);
174}
175
176.brand-title h1 {
177 font-size: 20px;
178 font-weight: 700;
179 letter-spacing: -0.02em;
180 background: linear-gradient(135deg, var(--text-primary), var(--text-secondary));
181 -webkit-background-clip: text;
182 -webkit-text-fill-color: transparent;
183}
184
185.brand-title p {
186 font-size: 12px;
187 color: var(--text-muted);
188}
189
190.header-actions {
191 display: flex;
192 align-items: center;
193 gap: 12px;
194}
195
196
197
198
199
200.btn {
201 display: inline-flex;
202 align-items: center;
203 justify-content: center;
204 gap: 8px;
205 padding: 9px 16px;
206 font-family: var(--font-sans);
207 font-size: 13px;
208 font-weight: 600;
209 border-radius: var(--radius-md);
210 border: 1px solid transparent;
211 cursor: pointer;
212 transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
213 text-decoration: none;
214 white-space: nowrap;
215}
216
217.btn:active {
218 transform: scale(0.97);
219}
220
221.btn-primary {
222 background: linear-gradient(135deg, #6366f1, #4f46e5);
223 color: #ffffff;
224 box-shadow: 0 4px 12px rgba(99, 102, 241, 0.35);
225}
226
227.btn-primary:hover {
228 background: linear-gradient(135deg, #4f46e5, #4338ca);
229 box-shadow: 0 6px 16px rgba(99, 102, 241, 0.5);
230 transform: translateY(-1px);
231}
232
233.btn-secondary {
234 background: var(--bg-input);
235 color: var(--text-primary);
236 border-color: var(--border-color);
237}
238
239.btn-secondary:hover {
240 background: var(--bg-card-hover);
241 border-color: var(--text-muted);
242 transform: translateY(-1px);
243}
244
245.btn-danger {
246 background: linear-gradient(135deg, #f43f5e, #e11d48);
247 color: #ffffff;
248}
249
250.btn-danger:hover {
251 background: linear-gradient(135deg, #e11d48, #be123c);
252}
253
254.btn-icon {
255 width: 38px;
256 height: 38px;
257 padding: 0;
258 border-radius: var(--radius-md);
259 background: var(--bg-input);
260 color: var(--text-secondary);
261 border: 1px solid var(--border-color);
262}
263
264.btn-icon:hover {
265 color: var(--text-primary);
266 background: var(--bg-card-hover);
267}
268
269kbd {
270 display: inline-block;
271 padding: 2px 6px;
272 font-family: monospace;
273 font-size: 11px;
274 font-weight: 600;
275 color: var(--text-secondary);
276 background: var(--bg-input);
277 border: 1px solid var(--border-color);
278 border-radius: 4px;
279 box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
280}
281
282
283
284
285
286.summary-grid {
287 display: grid;
288 grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
289 gap: 20px;
290 margin-bottom: 24px;
291}
292
293.summary-card {
294 background: var(--bg-card);
295 backdrop-filter: var(--backdrop-blur);
296 -webkit-backdrop-filter: var(--backdrop-blur);
297 border: 1px solid var(--border-color);
298 border-radius: var(--radius-lg);
299 padding: 20px;
300 box-shadow: var(--shadow-md);
301 transition: transform 0.2s ease, box-shadow 0.2s ease;
302 position: relative;
303 overflow: hidden;
304}
305
306.summary-card:hover {
307 transform: translateY(-2px);
308 box-shadow: var(--shadow-lg);
309}
310
311.summary-card::before {
312 content: '';
313 position: absolute;
314 top: 0;
315 left: 0;
316 width: 100%;
317 height: 4px;
318}
319
320.card-net-worth::before { background: linear-gradient(90deg, #6366f1, #8b5cf6); }
321.card-income::before { background: linear-gradient(90deg, #10b981, #059669); }
322.card-expenses::before { background: linear-gradient(90deg, #f43f5e, #e11d48); }
323.card-savings::before { background: linear-gradient(90deg, #06b6d4, #0891b2); }
324
325.card-header {
326 display: flex;
327 align-items: center;
328 justify-content: space-between;
329 margin-bottom: 12px;
330}
331
332.card-title {
333 font-size: 13px;
334 font-weight: 500;
335 color: var(--text-muted);
336 text-transform: uppercase;
337 letter-spacing: 0.05em;
338}
339
340.card-icon {
341 width: 32px;
342 height: 32px;
343 border-radius: var(--radius-sm);
344 display: flex;
345 align-items: center;
346 justify-content: center;
347 font-size: 16px;
348}
349
350.icon-net-worth { background: rgba(99, 102, 241, 0.15); color: #6366f1; }
351.icon-income { background: rgba(16, 185, 129, 0.15); color: #10b981; }
352.icon-expenses { background: rgba(244, 63, 94, 0.15); color: #f43f5e; }
353.icon-savings { background: rgba(6, 182, 212, 0.15); color: #06b6d4; }
354
355.card-amount {
356 font-size: 26px;
357 font-weight: 700;
358 letter-spacing: -0.02em;
359 color: var(--text-primary);
360 margin-bottom: 4px;
361}
362
363.card-subtext {
364 font-size: 12px;
365 color: var(--text-secondary);
366}
367
368.trend-badge {
369 display: inline-flex;
370 align-items: center;
371 gap: 4px;
372 padding: 2px 8px;
373 border-radius: var(--radius-full);
374 font-size: 11px;
375 font-weight: 600;
376}
377
378.trend-positive { background: var(--income-bg); color: var(--income-color); }
379.trend-negative { background: var(--expense-bg); color: var(--expense-color); }
380
381
382
383
384
385.dashboard-layout {
386 display: grid;
387 grid-template-columns: 1fr 1fr;
388 gap: 24px;
389 margin-bottom: 24px;
390}
391
392@media (max-width: 1024px) {
393 .dashboard-layout {
394 grid-template-columns: 1fr;
395 }
396}
397
398.section-card {
399 background: var(--bg-card);
400 backdrop-filter: var(--backdrop-blur);
401 -webkit-backdrop-filter: var(--backdrop-blur);
402 border: 1px solid var(--border-color);
403 border-radius: var(--radius-lg);
404 padding: 20px;
405 box-shadow: var(--shadow-md);
406}
407
408.section-header {
409 display: flex;
410 align-items: center;
411 justify-content: space-between;
412 margin-bottom: 16px;
413}
414
415.section-title {
416 font-size: 16px;
417 font-weight: 600;
418 color: var(--text-primary);
419 display: flex;
420 align-items: center;
421 gap: 8px;
422}
423
424
425.canvas-wrapper {
426 position: relative;
427 width: 100%;
428 height: 260px;
429}
430
431canvas {
432 width: 100% !important;
433 height: 100% !important;
434 display: block;
435}
436
437
438
439
440
441.budget-list {
442 display: flex;
443 flex-direction: column;
444 gap: 14px;
445 max-height: 260px;
446 overflow-y: auto;
447 padding-right: 6px;
448}
449
450.budget-item {
451 display: flex;
452 flex-direction: column;
453 gap: 6px;
454}
455
456.budget-info {
457 display: flex;
458 align-items: center;
459 justify-content: space-between;
460 font-size: 13px;
461}
462
463.budget-label {
464 display: flex;
465 align-items: center;
466 gap: 8px;
467 font-weight: 500;
468 color: var(--text-primary);
469}
470
471.budget-values {
472 font-weight: 600;
473 font-size: 12px;
474 color: var(--text-secondary);
475}
476
477.progress-track {
478 width: 100%;
479 height: 8px;
480 background: var(--bg-input);
481 border-radius: var(--radius-full);
482 overflow: hidden;
483 position: relative;
484}
485
486.progress-fill {
487 height: 100%;
488 border-radius: var(--radius-full);
489 transition: width 0.6s cubic-bezier(0.16, 1, 0.3, 1);
490}
491
492.fill-good { background: linear-gradient(90deg, #10b981, #34d399); }
493.fill-warning { background: linear-gradient(90deg, #f59e0b, #fbbf24); }
494.fill-danger { background: linear-gradient(90deg, #f43f5e, #fb7185); }
495
496
497
498
499
500.transactions-container {
501 background: var(--bg-card);
502 backdrop-filter: var(--backdrop-blur);
503 -webkit-backdrop-filter: var(--backdrop-blur);
504 border: 1px solid var(--border-color);
505 border-radius: var(--radius-lg);
506 padding: 20px;
507 box-shadow: var(--shadow-md);
508}
509
510.toolbar {
511 display: flex;
512 align-items: center;
513 justify-content: space-between;
514 flex-wrap: wrap;
515 gap: 14px;
516 margin-bottom: 16px;
517}
518
519.search-box {
520 position: relative;
521 flex: 1;
522 min-width: 200px;
523}
524
525.search-box input {
526 width: 100%;
527 padding: 9px 12px 9px 36px;
528 background: var(--bg-input);
529 border: 1px solid var(--border-color);
530 border-radius: var(--radius-md);
531 color: var(--text-primary);
532 font-size: 13px;
533 outline: none;
534 transition: border-color 0.2s, box-shadow 0.2s;
535}
536
537.search-box input:focus {
538 border-color: var(--border-focus);
539 box-shadow: 0 0 0 3px var(--brand-primary-light);
540}
541
542.search-icon {
543 position: absolute;
544 left: 12px;
545 top: 50%;
546 transform: translateY(-50%);
547 color: var(--text-muted);
548 font-size: 14px;
549 pointer-events: none;
550}
551
552.filter-group {
553 display: flex;
554 align-items: center;
555 gap: 10px;
556 flex-wrap: wrap;
557}
558
559.select-control {
560 padding: 9px 12px;
561 background: var(--bg-input);
562 border: 1px solid var(--border-color);
563 border-radius: var(--radius-md);
564 color: var(--text-primary);
565 font-size: 13px;
566 outline: none;
567 cursor: pointer;
568}
569
570.select-control:focus {
571 border-color: var(--border-focus);
572}
573
574.table-wrapper {
575 overflow-x: auto;
576 border-radius: var(--radius-md);
577 border: 1px solid var(--border-color);
578}
579
580.tx-table {
581 width: 100%;
582 border-collapse: collapse;
583 text-align: left;
584 font-size: 13px;
585}
586
587.tx-table th {
588 background: var(--bg-input);
589 padding: 12px 16px;
590 font-weight: 600;
591 color: var(--text-secondary);
592 border-bottom: 1px solid var(--border-color);
593 white-space: nowrap;
594}
595
596.tx-table th.sortable {
597 cursor: pointer;
598 user-select: none;
599}
600
601.tx-table th.sortable:hover {
602 color: var(--text-primary);
603}
604
605.tx-table td {
606 padding: 12px 16px;
607 border-bottom: 1px solid var(--border-color);
608 color: var(--text-primary);
609}
610
611.tx-table tbody tr {
612 transition: background-color 0.15s ease;
613}
614
615.tx-table tbody tr:hover {
616 background-color: var(--bg-input);
617}
618
619.badge {
620 display: inline-flex;
621 align-items: center;
622 gap: 6px;
623 padding: 4px 10px;
624 border-radius: var(--radius-full);
625 font-size: 12px;
626 font-weight: 500;
627}
628
629.badge-income { background: var(--income-bg); color: var(--income-color); }
630.badge-expense { background: var(--expense-bg); color: var(--expense-color); }
631
632.amount-income { color: var(--income-color); font-weight: 600; }
633.amount-expense { color: var(--text-primary); font-weight: 600; }
634
635.table-actions {
636 display: flex;
637 align-items: center;
638 gap: 6px;
639}
640
641.btn-xs {
642 padding: 4px 8px;
643 font-size: 11px;
644 border-radius: var(--radius-sm);
645}
646
647.empty-state {
648 text-align: center;
649 padding: 40px 20px;
650 color: var(--text-muted);
651}
652
653.empty-state p {
654 margin-top: 8px;
655 font-size: 13px;
656}
657
658
659
660
661
662.modal-backdrop {
663 position: fixed;
664 inset: 0;
665 background: rgba(0, 0, 0, 0.5);
666 backdrop-filter: blur(4px);
667 display: flex;
668 align-items: center;
669 justify-content: center;
670 z-index: 1000;
671 opacity: 0;
672 pointer-events: none;
673 transition: opacity 0.25s ease;
674}
675
676.modal-backdrop.active {
677 opacity: 1;
678 pointer-events: auto;
679}
680
681.modal-content {
682 background: var(--bg-modal);
683 border: 1px solid var(--border-color);
684 border-radius: var(--radius-lg);
685 width: 90%;
686 max-width: 500px;
687 padding: 24px;
688 box-shadow: var(--shadow-lg);
689 transform: translateY(20px) scale(0.95);
690 transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
691}
692
693.modal-backdrop.active .modal-content {
694 transform: translateY(0) scale(1);
695}
696
697.modal-header {
698 display: flex;
699 align-items: center;
700 justify-content: space-between;
701 margin-bottom: 20px;
702}
703
704.modal-title {
705 font-size: 18px;
706 font-weight: 700;
707}
708
709.form-group {
710 margin-bottom: 16px;
711}
712
713.form-label {
714 display: block;
715 font-size: 12px;
716 font-weight: 600;
717 color: var(--text-secondary);
718 margin-bottom: 6px;
719 text-transform: uppercase;
720 letter-spacing: 0.03em;
721}
722
723.form-control {
724 width: 100%;
725 padding: 10px 12px;
726 background: var(--bg-input);
727 border: 1px solid var(--border-color);
728 border-radius: var(--radius-md);
729 color: var(--text-primary);
730 font-size: 14px;
731 outline: none;
732 font-family: inherit;
733}
734
735.form-control:focus {
736 border-color: var(--border-focus);
737 box-shadow: 0 0 0 3px var(--brand-primary-light);
738}
739
740.form-row {
741 display: grid;
742 grid-template-columns: 1fr 1fr;
743 gap: 16px;
744}
745
746.modal-footer {
747 display: flex;
748 align-items: center;
749 justify-content: flex-end;
750 gap: 12px;
751 margin-top: 24px;
752}
753
754
755
756
757
758#toast-container {
759 position: fixed;
760 bottom: 24px;
761 right: 24px;
762 display: flex;
763 flex-direction: column;
764 gap: 10px;
765 z-index: 2000;
766 pointer-events: none;
767}
768
769.toast {
770 pointer-events: auto;
771 min-width: 260px;
772 padding: 12px 16px;
773 background: var(--bg-modal);
774 border: 1px solid var(--border-color);
775 border-radius: var(--radius-md);
776 box-shadow: var(--shadow-lg);
777 color: var(--text-primary);
778 font-size: 13px;
779 font-weight: 500;
780 display: flex;
781 align-items: center;
782 gap: 10px;
783 transform: translateX(100%);
784 opacity: 0;
785 transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
786}
787
788.toast.show {
789 transform: translateX(0);
790 opacity: 1;
791}
792
793.toast-success { border-left: 4px solid var(--income-color); }
794.toast-error { border-left: 4px solid var(--expense-color); }
795.toast-info { border-left: 4px solid var(--brand-primary); }
796
797
798.shortcut-list {
799 display: flex;
800 flex-direction: column;
801 gap: 12px;
802}
803
804.shortcut-item {
805 display: flex;
806 align-items: center;
807 justify-content: space-between;
808 font-size: 13px;
809 padding-bottom: 8px;
810 border-bottom: 1px solid var(--border-color);
811}
812
Discussion
No comments yet. Start the discussion. Recorded by @patrick-toulme.