kua-money-trace/web/styles.css

194 lines
10 KiB
CSS

/* money-trace · dark finance-terminal aesthetic */
:root {
--bg: #090b0f;
--bg-grid: rgba(255,255,255,0.022);
--panel: #10141b;
--panel-2: #161b24;
--line: rgba(255,255,255,0.075);
--line-2: rgba(255,255,255,0.13);
--ink: #eaeff7;
--ink-mute: #8b95a6;
--ink-dim: #545d6d;
--c-income: #2ee6a6; /* real money in */
--c-spend: #ff5f73; /* real money out */
--c-person: #b98cff; /* inter-person */
--c-fee: #ffc24b; /* fees & interest*/
--c-internal:#4b5466; /* cycles / noise */
--glow: 1; /* 0..1, multiplied into drop-shadows */
--link-op: 0.62; /* base opacity of real links */
--font-ui: 'Space Grotesk', system-ui, sans-serif;
--font-num: 'IBM Plex Mono', ui-monospace, monospace;
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
background:
radial-gradient(1200px 700px at 78% -8%, rgba(46,230,166,0.05), transparent 60%),
radial-gradient(900px 600px at 6% 110%, rgba(185,140,255,0.045), transparent 55%),
linear-gradient(0deg, var(--bg-grid) 1px, transparent 1px) 0 0 / 100% 34px,
var(--bg);
color: var(--ink);
font-family: var(--font-ui);
-webkit-font-smoothing: antialiased;
overflow: hidden;
}
.num { font-family: var(--font-num); font-feature-settings: 'tnum' 1; letter-spacing: -0.01em; }
/* ---- app frame ---- */
#app { display: flex; flex-direction: column; height: 100vh; }
/* ---- header / summary bar ---- */
header.bar {
display: flex; align-items: stretch; gap: 0;
padding: 14px 22px 13px; border-bottom: 1px solid var(--line);
background: linear-gradient(180deg, rgba(255,255,255,0.018), transparent);
}
.brand { display: flex; flex-direction: column; justify-content: center; min-width: 168px; }
.brand .mark {
font-weight: 600; font-size: 15px; letter-spacing: 0.26em;
text-transform: uppercase; color: var(--ink);
}
.brand .mark b { color: var(--c-income); font-weight: 600; }
.brand .sub { font-size: 11px; color: var(--ink-dim); letter-spacing: 0.04em; margin-top: 3px; }
.stats { display: flex; gap: 30px; margin-left: auto; align-items: center; }
.stat { display: flex; flex-direction: column; gap: 4px; min-width: 132px; }
.stat .lab {
font-size: 10.5px; letter-spacing: 0.14em; text-transform: uppercase;
color: var(--ink-mute); display: flex; align-items: center; gap: 6px;
}
.stat .lab i { width: 7px; height: 7px; border-radius: 2px; display: inline-block; }
.stat .val { font-size: 27px; font-weight: 500; line-height: 1; }
.stat .val small { font-size: 13px; color: var(--ink-dim); margin-left: 2px; }
.stat.income .val { color: var(--c-income); }
.stat.spend .val { color: var(--c-spend); }
.stat.internal .val { color: var(--ink-mute); }
.stat.net .val { color: var(--ink); }
.stat .delta { font-size: 11px; color: var(--ink-dim); }
/* ---- controls strip ---- */
.controls {
display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
padding: 11px 22px; border-bottom: 1px solid var(--line);
background: var(--panel);
}
.seg { display: inline-flex; background: var(--bg); border: 1px solid var(--line); border-radius: 9px; padding: 3px; gap: 2px; }
.seg button {
font-family: var(--font-ui); font-size: 12.5px; color: var(--ink-mute);
background: transparent; border: 0; padding: 7px 15px; border-radius: 6px;
cursor: pointer; display: flex; align-items: center; gap: 7px; transition: .16s;
}
.seg button:hover { color: var(--ink); }
.seg button.on { background: var(--panel-2); color: var(--ink); box-shadow: inset 0 0 0 1px var(--line-2); }
.seg button svg { width: 14px; height: 14px; }
.toggle { display: inline-flex; align-items: center; gap: 9px; cursor: pointer; user-select: none; }
.toggle .track { width: 38px; height: 21px; border-radius: 20px; background: var(--bg); border: 1px solid var(--line-2); position: relative; transition: .18s; }
.toggle .track::after { content: ''; position: absolute; top: 2px; left: 2px; width: 15px; height: 15px; border-radius: 50%; background: var(--ink-mute); transition: .18s; }
.toggle.on .track { background: rgba(46,230,166,0.22); border-color: var(--c-income); }
.toggle.on .track::after { left: 19px; background: var(--c-income); }
.toggle .lbl { font-size: 12.5px; color: var(--ink); }
.toggle .hint { font-size: 11px; color: var(--ink-dim); }
.ctl-label { font-size: 10.5px; letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink-dim); margin-right: -8px; }
/* month scrubber */
.scrub { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 280px; max-width: 560px; }
.scrub .play { width: 30px; height: 30px; border-radius: 8px; border: 1px solid var(--line); background: var(--bg); color: var(--ink); cursor: pointer; display: grid; place-items: center; }
.scrub .play:hover { border-color: var(--line-2); }
.scrub .track-wrap { flex: 1; }
.scrub .months { display: flex; justify-content: space-between; font-size: 10px; color: var(--ink-dim); margin-bottom: 5px; }
.scrub .months b { color: var(--c-income); font-weight: 500; font-family: var(--font-num); }
.bars { display: flex; gap: 2px; align-items: flex-end; height: 30px; }
.bars .b { flex: 1; background: var(--line); border-radius: 2px 2px 0 0; cursor: pointer; transition: .14s; min-height: 2px; }
.bars .b:hover { background: var(--ink-dim); }
.bars .b.active { background: linear-gradient(180deg, var(--c-income), rgba(46,230,166,0.35)); }
/* bank filter */
.dropdown { position: relative; }
.dropdown > .btn {
font-family: var(--font-ui); font-size: 12.5px; color: var(--ink); background: var(--bg);
border: 1px solid var(--line); border-radius: 8px; padding: 8px 13px; cursor: pointer;
display: flex; align-items: center; gap: 8px;
}
.dropdown > .btn .cnt { color: var(--ink-dim); font-family: var(--font-num); font-size: 11px; }
.dropdown .menu {
position: absolute; top: calc(100% + 6px); right: 0; z-index: 40;
background: var(--panel-2); border: 1px solid var(--line-2); border-radius: 10px;
padding: 8px; width: 220px; box-shadow: 0 18px 50px rgba(0,0,0,0.55); display: none;
max-height: 360px; overflow: auto;
}
.dropdown.open .menu { display: block; }
.dropdown .menu .row { display: flex; align-items: center; gap: 9px; padding: 7px 9px; border-radius: 7px; cursor: pointer; font-size: 12.5px; }
.dropdown .menu .row:hover { background: var(--panel); }
.dropdown .menu .row .ck { width: 15px; height: 15px; border-radius: 4px; border: 1px solid var(--line-2); display: grid; place-items: center; color: var(--bg); }
.dropdown .menu .row.on .ck { background: var(--c-income); border-color: var(--c-income); }
.dropdown .menu .row .n { color: var(--ink-dim); margin-left: auto; font-family: var(--font-num); font-size: 11px; }
.dropdown .menu .sep { height: 1px; background: var(--line); margin: 6px 4px; }
.dropdown .menu .all { font-size: 11px; color: var(--c-income); padding: 6px 9px; cursor: pointer; }
/* ---- legend ---- */
.legend { display: flex; align-items: center; gap: 16px; margin-left: auto; }
.legend .item { display: flex; align-items: center; gap: 7px; font-size: 11.5px; color: var(--ink-mute); }
.legend .item i { width: 16px; height: 3px; border-radius: 2px; display: inline-block; }
.legend .item.dash i { height: 0; border-top: 2px dashed var(--c-internal); width: 18px; }
/* ---- view area ---- */
.view { position: relative; flex: 1; overflow: hidden; }
.view svg { width: 100%; height: 100%; display: block; }
/* sankey */
.node-rect { transition: opacity .18s; }
.node-label { fill: var(--ink); font-size: 12.5px; font-family: var(--font-ui); }
.node-sub { fill: var(--ink-dim); font-size: 10px; font-family: var(--font-num); }
.node-val { fill: var(--ink-mute); font-size: 10.5px; font-family: var(--font-num); }
.colhead { fill: var(--ink-dim); font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase; font-family: var(--font-ui); }
.link { fill: none; transition: opacity .18s, stroke-opacity .18s; }
.link.real { opacity: var(--link-op); }
.link.internal { opacity: 0.4; }
.link.income { stroke: var(--c-income); }
.link.inter_in, .link.inter_out { stroke: var(--c-person); }
.link.expense { stroke: var(--c-spend); }
.link.fee { stroke: var(--c-fee); }
.link.internal_card, .link.internal_line, .link.internal_self { stroke: var(--c-internal); stroke-dasharray: 5 5; }
.glow-real { filter: drop-shadow(0 0 calc(5px * var(--glow)) currentColor); }
.dim { opacity: 0.07 !important; }
.hl { opacity: 0.95 !important; }
/* ---- tooltip ---- */
#tip {
position: fixed; z-index: 80; pointer-events: none; max-width: 320px;
background: rgba(13,17,23,0.96); border: 1px solid var(--line-2); border-radius: 11px;
padding: 12px 13px; box-shadow: 0 16px 44px rgba(0,0,0,0.6); backdrop-filter: blur(8px);
opacity: 0; transform: translateY(4px); transition: opacity .12s, transform .12s; font-size: 12.5px;
}
#tip.show { opacity: 1; transform: translateY(0); }
#tip .t-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
#tip .t-dot { width: 9px; height: 9px; border-radius: 3px; }
#tip .t-title { font-weight: 600; font-size: 13px; }
#tip .t-amt { font-family: var(--font-num); font-size: 19px; margin: 2px 0 9px; }
#tip .t-meta { color: var(--ink-mute); font-size: 11px; margin-bottom: 9px; }
#tip .t-rows { display: flex; flex-direction: column; gap: 5px; border-top: 1px solid var(--line); padding-top: 9px; max-height: 200px; overflow: hidden; }
#tip .t-row { display: flex; gap: 10px; font-size: 11.5px; align-items: baseline; }
#tip .t-row .d { color: var(--ink-dim); font-family: var(--font-num); font-size: 10.5px; width: 42px; flex: none; }
#tip .t-row .desc { color: var(--ink-mute); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#tip .t-row .a { font-family: var(--font-num); color: var(--ink); }
#tip .t-more { color: var(--ink-dim); font-size: 10.5px; margin-top: 7px; }
/* orbit view */
.orbit-ring { fill: none; stroke: var(--line); stroke-width: 1; }
.orbit-node-label { fill: var(--ink); font-size: 11.5px; font-family: var(--font-ui); }
.orbit-sub { fill: var(--ink-dim); font-size: 9.5px; font-family: var(--font-num); }
.orbit-center-lab { fill: var(--ink); font-size: 14px; font-family: var(--font-ui); font-weight: 600; }
/* empty state */
.empty { position: absolute; inset: 0; display: grid; place-items: center; color: var(--ink-dim); font-size: 14px; }
/* loading */
#loading { position: fixed; inset: 0; display: grid; place-items: center; background: var(--bg); z-index: 200; color: var(--ink-mute); font-family: var(--font-num); font-size: 13px; letter-spacing: 0.1em; }