Files
money/internal/web/static/style.css
T
nikolaandClaude Opus 5.5 7f5b4846ef Show which legs a transfer cannot pair, and what would pair them
The transfers screen counted unpaired legs per definition but never said
which transactions they were; finding them meant retyping the definition
into the builder. A ⚠ row now opens onto its legs, newest first, each
naming the missing side and what that side would have had to be:

  revolut → ?  arriving leg  +250.00 in other matching *FROM REVOLUT*,
                             dated 2026-02-01 to 2026-02-11

That description comes from transfers.Engine.Want, next to
bestCounterpart, so it is stated in the terms the pairing actually uses:
the other half of the definition, the window, and the amount -- exact,
widened only by the definition's own tolerance, and "any amount" across
currencies, where amounts are not compared. When the other account has
nothing imported at all, the line says so, since that is the usual cause.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 19:43:13 +02:00

213 lines
6.9 KiB
CSS

:root {
--bg: #f7f7f5;
--surface: #ffffff;
--text: #1d1d1f;
--muted: #6b6b70;
--border: #e2e2de;
--accent: #4b46c8;
--accent-text: #ffffff;
--accent-soft: #ecebfb;
--negative: #b3261e;
--positive: #1d7a3a;
--warn: #9a5b00;
--warn-soft: #fff4e0;
--error-soft: #fdecea;
--row-hover: #f2f2ef;
--mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
color-scheme: light;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #161618;
--surface: #1e1e21;
--text: #e8e8ea;
--muted: #9a9aa2;
--border: #333338;
--accent: #8f8cf0;
--accent-text: #111114;
--accent-soft: #2a2950;
--negative: #f2867d;
--positive: #6fcf8e;
--warn: #f0b45a;
--warn-soft: #3a2c14;
--error-soft: #3d1c1a;
--row-hover: #26262a;
color-scheme: dark;
}
}
* { box-sizing: border-box; }
body {
margin: 0;
background: var(--bg);
color: var(--text);
font: 14px/1.45 system-ui, -apple-system, "Segoe UI", sans-serif;
}
button, input, select { font: inherit; color: inherit; }
.top {
display: flex;
align-items: center;
gap: 16px;
padding: 10px 16px;
background: var(--surface);
border-bottom: 1px solid var(--border);
flex-wrap: wrap;
position: sticky;
top: 0;
z-index: 2;
}
.brand { font-weight: 700; font-size: 16px; color: var(--text); text-decoration: none; }
#nav { display: flex; gap: 2px; flex-wrap: wrap; flex: 1; }
#nav a {
padding: 5px 10px;
border-radius: 6px;
color: var(--muted);
text-decoration: none;
white-space: nowrap;
}
#nav a:hover { color: var(--text); background: var(--row-hover); }
#nav a.active { color: var(--accent); background: var(--accent-soft); font-weight: 600; }
#nav kbd { font-family: var(--mono); font-size: 11px; opacity: .6; margin-right: 4px; }
.actions { display: flex; gap: 8px; }
button {
padding: 5px 12px;
border-radius: 6px;
border: 1px solid var(--border);
background: var(--surface);
cursor: pointer;
}
button:hover:not(:disabled) { border-color: var(--muted); }
button:disabled { opacity: .5; cursor: default; }
button.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
button.danger { color: var(--negative); }
button.link { border: none; background: none; padding: 0 4px; color: var(--accent); }
#banners { padding: 0 16px; }
.banner {
margin-top: 10px;
padding: 8px 12px;
border-radius: 6px;
display: flex;
gap: 12px;
align-items: center;
justify-content: space-between;
white-space: pre-wrap;
}
.banner.info { background: var(--accent-soft); }
.banner.warn { background: var(--warn-soft); color: var(--warn); }
.banner.error { background: var(--error-soft); color: var(--negative); }
.banner button { flex: none; }
main { padding: 16px; max-width: 1400px; }
h2 { font-size: 16px; margin: 0 0 12px; font-weight: 600; }
h2 .sub { color: var(--muted); font-weight: 400; }
.toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 12px; }
.toolbar input[type=search] { min-width: 220px; }
input[type=text], input[type=search], select {
padding: 5px 8px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--surface);
}
input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: transparent; }
label.check { display: inline-flex; gap: 6px; align-items: center; cursor: pointer; }
.panel {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
overflow: auto;
}
table { border-collapse: collapse; width: 100%; }
th, td { padding: 5px 10px; text-align: left; white-space: nowrap; }
th {
position: sticky;
top: 0;
background: var(--surface);
border-bottom: 1px solid var(--border);
font-weight: 600;
z-index: 1;
}
tbody tr:hover { background: var(--row-hover); }
tbody tr.clickable { cursor: pointer; }
td.num, th.num { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }
td.desc { white-space: normal; min-width: 240px; }
td.mark { width: 1em; text-align: center; padding-right: 0; }
.neg { color: var(--negative); }
.muted { color: var(--muted); }
.warn { color: var(--warn); }
th.sortable { cursor: pointer; user-select: none; }
th.sortable:hover { color: var(--accent); }
tr.total td { font-weight: 600; border-top: 1px solid var(--border); }
tr.excluded td { color: var(--muted); }
tr.excluded.first td { border-top: 1px dashed var(--border); }
td.actions { text-align: right; }
tr.legs > td { padding: 0 10px 10px 36px; background: var(--bg); }
tr.legs:hover { background: none; }
table.sub th { background: var(--bg); font-weight: 500; color: var(--muted); }
td.actions button { padding: 1px 8px; font-size: 12px; }
.empty { padding: 32px 16px; color: var(--muted); white-space: pre-line; text-align: center; }
.more { padding: 10px; text-align: center; }
.report { display: grid; grid-template-columns: 220px 1fr; gap: 12px; align-items: start; }
.periods { padding: 6px; }
.periods button {
display: block;
width: 100%;
text-align: left;
border: none;
background: none;
padding: 4px 8px;
border-radius: 5px;
color: var(--muted);
}
.periods button:hover { background: var(--row-hover); color: var(--text); }
.periods button.active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.periods .head { font-weight: 600; padding: 4px 8px; }
.builder { display: grid; grid-template-columns: 320px 1fr; gap: 16px; align-items: start; }
.form { padding: 14px; display: flex; flex-direction: column; gap: 12px; }
.field label { display: block; font-weight: 600; margin-bottom: 3px; }
.field input { width: 100%; font-family: var(--mono); }
.field .hint { color: var(--muted); font-size: 12px; margin-top: 2px; }
.form .summary { font-weight: 600; white-space: pre-line; }
.form .buttons { display: flex; gap: 8px; }
.kept { font-size: 12px; color: var(--muted); font-family: var(--mono); }
.preview { max-height: calc(100vh - 170px); }
.upload { margin-top: 16px; padding: 14px; overflow: visible; }
.upload h3 { font-size: 14px; margin: 0 0 10px; }
.upload .toolbar { margin-bottom: 10px; }
.dropzone {
border: 2px dashed var(--border);
border-radius: 8px;
padding: 22px 16px;
text-align: center;
color: var(--muted);
cursor: pointer;
}
.dropzone:hover, .dropzone:focus, .dropzone.over {
border-color: var(--accent);
color: var(--accent);
background: var(--accent-soft);
outline: none;
}
.upload .chosen { margin-top: 8px; font-family: var(--mono); font-size: 12px; overflow-wrap: anywhere; }
.upload .hint { margin-top: 8px; font-size: 12px; }
.import-files { margin-top: 6px; font-size: 13px; }
.import-files li { font-family: var(--mono); }
@media (max-width: 760px) {
.report, .builder { grid-template-columns: 1fr; }
.periods { display: flex; flex-wrap: wrap; gap: 2px; }
.periods button { width: auto; }
.periods .head { width: 100%; }
.toolbar input[type=search] { min-width: 0; flex: 1; }
.preview { max-height: none; }
}