/* ============================================================================
   upbudget — a ledger, not a dashboard template.
   Neutrals carry a slight blue bias toward the prussian-ink accent; the only
   saturated colours are status (money in, attention, overdue) and the two
   validated chart marks. Tables keep the rule-per-row of a columnar pad.
   ========================================================================= */

@font-face { font-family:"Plex Sans"; src:url("/static/fonts/ibm-plex-sans-400.woff2") format("woff2"); font-weight:400; font-style:normal; font-display:swap }
@font-face { font-family:"Plex Sans"; src:url("/static/fonts/ibm-plex-sans-500.woff2") format("woff2"); font-weight:500; font-style:normal; font-display:swap }
@font-face { font-family:"Plex Sans"; src:url("/static/fonts/ibm-plex-sans-600.woff2") format("woff2"); font-weight:600; font-style:normal; font-display:swap }
@font-face { font-family:"Plex Sans"; src:url("/static/fonts/ibm-plex-sans-700.woff2") format("woff2"); font-weight:700; font-style:normal; font-display:swap }
@font-face { font-family:"Plex Serif"; src:url("/static/fonts/ibm-plex-serif-500.woff2") format("woff2"); font-weight:500; font-style:normal; font-display:swap }
@font-face { font-family:"Plex Serif"; src:url("/static/fonts/ibm-plex-serif-600.woff2") format("woff2"); font-weight:600; font-style:normal; font-display:swap }
@font-face { font-family:"Plex Mono"; src:url("/static/fonts/ibm-plex-mono-400.woff2") format("woff2"); font-weight:400; font-style:normal; font-display:swap }
@font-face { font-family:"Plex Mono"; src:url("/static/fonts/ibm-plex-mono-500.woff2") format("woff2"); font-weight:500; font-style:normal; font-display:swap }

:root {
  color-scheme: light;
  --font-sans:"Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-serif:"Plex Serif", ui-serif, Georgia, "Times New Roman", serif;
  --font-mono:"Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --t-xs:.6875rem; --t-sm:.8125rem; --t-md:.875rem; --t-base:.9375rem; --t-lg:1.0625rem;
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:20px; --s6:28px; --s7:44px;
  --r-sm:5px; --r-md:8px; --r-lg:12px; --rail-w:236px;

  --ground:#EFF3F7;
  --surface:#FFFFFF;
  --surface-2:#F7F9FC;
  --surface-3:#E7EDF4;
  --line:#DCE3EC;
  --line-strong:#C4CEDB;
  --ink:#0F1B2A;
  --ink-2:#4B5B71;
  --ink-3:#7C8CA2;
  --accent:#134A6B;
  --accent-hover:#0D3750;
  --accent-soft:#E2ECF3;
  --accent-ink:#FFFFFF;
  --good:#12775A; --good-soft:#DCF0E8;
  --warn:#8B5A0B; --warn-soft:#FAEED6;
  --bad:#A33529;  --bad-soft:#FAE3E0;
  --chart-1:#1A8F6B; --chart-2:#3B7BC4;
  --shadow-sm:0 1px 2px rgba(15,27,42,.05);
  --shadow-md:0 6px 24px -8px rgba(15,27,42,.22);
  --focus:#2C7CB0;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --ground:#0D141F;
    --surface:#161E2C;
    --surface-2:#1B2434;
    --surface-3:#243044;
    --line:#273347;
    --line-strong:#374559;
    --ink:#E7EDF5;
    --ink-2:#A9B7C9;
    --ink-3:#7E8EA4;
    --accent:#7FB6D9;
    --accent-hover:#9BC8E5;
    --accent-soft:#1D3348;
    --accent-ink:#0B1420;
    --good:#3FBE92; --good-soft:#12312A;
    --warn:#D9A441; --warn-soft:#332713;
    --bad:#E8776B;  --bad-soft:#3A1F1D;
    --chart-1:#22A379; --chart-2:#6293DD;
    --shadow-sm:0 1px 2px rgba(0,0,0,.4);
    --shadow-md:0 8px 28px -10px rgba(0,0,0,.6);
    --focus:#7FB6D9;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --ground:#0D141F;
  --surface:#161E2C;
  --surface-2:#1B2434;
  --surface-3:#243044;
  --line:#273347;
  --line-strong:#374559;
  --ink:#E7EDF5;
  --ink-2:#A9B7C9;
  --ink-3:#7E8EA4;
  --accent:#7FB6D9;
  --accent-hover:#9BC8E5;
  --accent-soft:#1D3348;
  --accent-ink:#0B1420;
  --good:#3FBE92; --good-soft:#12312A;
  --warn:#D9A441; --warn-soft:#332713;
  --bad:#E8776B;  --bad-soft:#3A1F1D;
  --chart-1:#22A379; --chart-2:#6293DD;
  --shadow-sm:0 1px 2px rgba(0,0,0,.4);
  --shadow-md:0 8px 28px -10px rgba(0,0,0,.6);
  --focus:#7FB6D9;
}

*,*::before,*::after { box-sizing:border-box }
/* .btn sets display, and an author rule beats the browser's own [hidden] rule */
[hidden] { display:none !important }
html { -webkit-text-size-adjust:100% }
body {
  margin:0; min-height:100vh; background:var(--ground); color:var(--ink);
  font:400 var(--t-base)/1.5 var(--font-sans);
  display:grid; grid-template-columns:var(--rail-w) minmax(0,1fr);
  -webkit-font-smoothing:antialiased;
}
a { color:var(--accent); text-decoration:none }
a:hover { text-decoration:underline }
:focus-visible { outline:2px solid var(--focus); outline-offset:2px; border-radius:3px }
h1,h2,h3,h4,h5 { margin:0; font-weight:600; text-wrap:balance }
p { margin:0 }
svg { flex:none }
.sr { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap }

/* ---- rail ---------------------------------------------------------------- */
.rail {
  position:sticky; top:0; height:100vh; overflow-y:auto; z-index:10;
  background:var(--surface); border-right:1px solid var(--line);
  display:flex; flex-direction:column; padding:var(--s5) var(--s3) var(--s3);
}
.rail__brand { display:flex; flex-direction:column; gap:1px; padding:0 var(--s3) var(--s5) }
.rail__mark { font:600 1.15rem/1 var(--font-serif); letter-spacing:-.015em; color:var(--ink) }
.rail__co { font-size:var(--t-xs); letter-spacing:.1em; text-transform:uppercase; color:var(--ink-3); font-weight:600 }
.rail__group { display:flex; flex-direction:column; gap:1px; margin-bottom:var(--s4) }
.rail__legend { font-size:var(--t-xs); letter-spacing:.1em; text-transform:uppercase; color:var(--ink-3); font-weight:600; padding:0 var(--s3) 6px }
.rail__link {
  display:flex; align-items:center; gap:10px; padding:7px var(--s3); border-radius:var(--r-sm);
  color:var(--ink-2); font-size:var(--t-md); font-weight:500; text-decoration:none;
}
.rail__link:hover { background:var(--surface-2); color:var(--ink); text-decoration:none }
.rail__link.is-active { background:var(--accent-soft); color:var(--accent); font-weight:600 }
.rail__link svg { width:16px; height:16px; stroke:currentColor; fill:none; stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round }
.rail__badge {
  margin-left:auto; min-width:20px; height:19px; padding:0 6px; border-radius:999px;
  background:var(--warn-soft); color:var(--warn); font-size:10px; font-weight:700;
  display:grid; place-items:center; font-variant-numeric:tabular-nums;
}
.rail__badge--quiet { background:var(--surface-3); color:var(--ink-3) }
.rail__foot { margin-top:auto; display:flex; align-items:center; gap:var(--s2); padding-top:var(--s4); border-top:1px solid var(--line) }
.rail__user { font-size:var(--t-xs); color:var(--ink-3); margin-right:auto; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }

.rail__logo { display:none; line-height:0 }
.rail__logo svg { width:26px; height:26px; color:var(--accent); stroke:none }
.rail__toggle { flex:none }
.rail__toggle svg { width:16px; height:16px; stroke:currentColor; fill:none; stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round }

/* ---- rail, collapsed ---- */
/* Icons only, at a width the page keeps for itself. Below 900px the rail is already a
   horizontal strip, so collapsing it would mean nothing and the control is hidden. */
@media (min-width: 901px) {
  :root[data-rail="collapsed"] { --rail-w:62px }
  body { transition:grid-template-columns .16s ease }
  [data-rail="collapsed"] .rail { padding-left:var(--s2); padding-right:var(--s2) }
  [data-rail="collapsed"] .rail__brand { padding:0 0 var(--s5); align-items:center }
  [data-rail="collapsed"] .rail__logo { display:block }
  [data-rail="collapsed"] .rail__mark,
  [data-rail="collapsed"] .rail__co,
  [data-rail="collapsed"] .rail__legend,
  [data-rail="collapsed"] .rail__user,
  [data-rail="collapsed"] .rail__label { display:none }
  [data-rail="collapsed"] .rail__link { position:relative; justify-content:center; padding:9px 0 }
  [data-rail="collapsed"] .rail__link svg { width:18px; height:18px }
  /* With the legends gone, a hairline is what is left to keep the groups apart. */
  [data-rail="collapsed"] .rail__group + .rail__group { border-top:1px solid var(--line); padding-top:var(--s3) }
  /* 483 does not fit in 62px, so the count becomes a dot and moves into the title. */
  [data-rail="collapsed"] .rail__badge {
    position:absolute; top:5px; right:11px; margin:0; width:8px; min-width:0; height:8px;
    padding:0; border-radius:50%; font-size:0; color:transparent;
    background:var(--warn); box-shadow:0 0 0 2px var(--surface);
  }
  [data-rail="collapsed"] .rail__link:hover .rail__badge { box-shadow:0 0 0 2px var(--surface-2) }
  [data-rail="collapsed"] .rail__link.is-active .rail__badge { box-shadow:0 0 0 2px var(--accent-soft) }
  [data-rail="collapsed"] .rail__badge--quiet { background:var(--ink-3) }
  [data-rail="collapsed"] .rail__foot { flex-direction:column; gap:2px }
  [data-rail="collapsed"] .rail__toggle svg { transform:rotate(180deg) }
}

/* ---- page ---------------------------------------------------------------- */
.page { min-width:0; display:flex; flex-direction:column }
.page__head {
  position:sticky; top:0; z-index:6; display:flex; align-items:center; gap:var(--s4);
  padding:var(--s5) var(--s6); background:var(--ground); border-bottom:1px solid var(--line);
}
.page__heading { min-width:0 }
.page__title { font:600 1.4rem/1.15 var(--font-serif); letter-spacing:-.015em }
.page__sub { font-size:var(--t-sm); color:var(--ink-3); margin-top:2px }
.page__actions { margin-left:auto; display:flex; align-items:center; gap:var(--s2); flex-wrap:wrap; justify-content:flex-end }
.page__body { padding:var(--s5) var(--s6) var(--s7); display:flex; flex-direction:column; gap:var(--s5) }

/* ---- flashes ------------------------------------------------------------- */
.flash { display:flex; align-items:flex-start; gap:var(--s2); padding:10px var(--s4); border-radius:var(--r-md); font-size:var(--t-md); border:1px solid transparent }
.flash--ok { background:var(--good-soft); color:var(--good); border-color:color-mix(in srgb, var(--good) 22%, transparent) }
.flash--err { background:var(--bad-soft); color:var(--bad); border-color:color-mix(in srgb, var(--bad) 22%, transparent) }
.flash--warn { background:var(--warn-soft); color:var(--warn); border-color:color-mix(in srgb, var(--warn) 22%, transparent) }
.flash svg { width:16px; height:16px; margin-top:2px; stroke:currentColor; fill:none; stroke-width:1.8 }

/* ---- panels -------------------------------------------------------------- */
.panel { background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg); overflow:hidden }
.panel__head { display:flex; align-items:center; gap:var(--s3); padding:var(--s4) var(--s5); border-bottom:1px solid var(--line) }
.panel__title { font-size:var(--t-base); font-weight:600 }
.panel__note { font-size:var(--t-sm); color:var(--ink-3) }
.panel__actions { margin-left:auto; display:flex; gap:var(--s2); align-items:center }
.panel__body { padding:var(--s5) }
.panel__foot { padding:var(--s3) var(--s5); border-top:1px solid var(--line); font-size:var(--t-sm); color:var(--ink-3) }
.panel--flush > .panel__body { padding:0 }
.cols { display:grid; grid-template-columns:repeat(auto-fit,minmax(340px,1fr)); gap:var(--s5); align-items:start }
.cols--2 { display:grid; grid-template-columns:1.15fr .85fr; gap:var(--s5); align-items:start }
/* the invoice page's right column is a table of candidates; it needs the wider half */
.cols--2.cols--right { grid-template-columns:.8fr 1.2fr }
.cols--right .trunc { max-width:24ch }
.stack { display:flex; flex-direction:column; gap:var(--s5) }

/* ---- tiles (only where the figure is the point) -------------------------- */
.tiles { display:grid; grid-template-columns:repeat(auto-fit,minmax(184px,1fr)); gap:var(--s3) }
.tile { background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg); padding:var(--s4); display:flex; flex-direction:column; gap:5px }
.tile__label { font-size:var(--t-xs); letter-spacing:.08em; text-transform:uppercase; color:var(--ink-3); font-weight:600 }
.tile__value { font:600 1.55rem/1.1 var(--font-serif); font-variant-numeric:tabular-nums; letter-spacing:-.01em }
.tile__foot { font-size:var(--t-xs); color:var(--ink-3) }
.tile--accent { border-left:3px solid var(--accent) }
.tile--good .tile__value { color:var(--good) }
.tile--bad .tile__value { color:var(--bad) }

/* ---- tables -------------------------------------------------------------- */
.scroller { overflow-x:auto }
.table { width:100%; border-collapse:collapse; font-size:var(--t-md) }
.table th {
  position:sticky; top:0; z-index:2; background:var(--surface); text-align:left;
  font-size:var(--t-xs); letter-spacing:.07em; text-transform:uppercase; color:var(--ink-3);
  font-weight:600; padding:var(--s3) var(--s3) var(--s2); border-bottom:1px solid var(--line-strong); white-space:nowrap;
}
.table td { padding:7px var(--s3); border-bottom:1px solid var(--line); vertical-align:top }
.table tbody tr:nth-child(even) td { background:var(--surface-2) }
.table tbody tr:hover td { background:var(--accent-soft) }
.table tbody tr:last-child td { border-bottom:0 }
/* The row you are on. A rule down its left edge, so it reads as a place in the list rather
   than another kind of hover — and it has to beat the hover and the zebra stripe, both of
   which paint the same cells. */
.table tbody tr[data-row] { cursor:default }
.table tbody tr.is-current td { background:var(--accent-soft) !important }
.table tbody tr.is-current td:first-child { box-shadow:inset 3px 0 0 var(--accent) }
.table tbody tr.is-current td:first-child.note-cell { box-shadow:inset 3px 0 0 var(--accent) }
.table td:first-child, .table th:first-child { padding-left:var(--s5) }
.table td:last-child, .table th:last-child { padding-right:var(--s5) }
.table--tight td { padding:5px var(--s3) }
.num { text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap }
.nowrap { white-space:nowrap }
.table a { color:var(--ink); text-decoration:none }
.table a:hover { color:var(--accent); text-decoration:underline }
.table .code a, a.code { color:var(--accent) }
.code { font-family:var(--font-mono); font-size:.78rem; letter-spacing:-.02em }
.muted { color:var(--ink-3) }
.strong { font-weight:600 }
.pos { color:var(--good) }
.neg { color:var(--bad) }
.wrap-any { word-break:break-word }
.trunc { display:block; max-width:32ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }

/* ---- pills --------------------------------------------------------------- */
.pill {
  display:inline-flex; align-items:center; gap:5px; padding:2px 9px; border-radius:999px;
  font-size:var(--t-xs); font-weight:600; background:var(--surface-3); color:var(--ink-2); white-space:nowrap;
}
.pill--dot::before { content:""; width:5px; height:5px; border-radius:50%; background:currentColor; flex:none }
.pill--good { background:var(--good-soft); color:var(--good) }
.pill--warn { background:var(--warn-soft); color:var(--warn) }
.pill--bad { background:var(--bad-soft); color:var(--bad) }
.pill--accent { background:var(--accent-soft); color:var(--accent) }
.pill--out { background:var(--good-soft); color:var(--good) }
.pill--in { background:var(--surface-3); color:var(--ink-2) }

/* ---- buttons ------------------------------------------------------------- */
.btn {
  display:inline-flex; align-items:center; justify-content:center; gap:6px; height:34px; padding:0 14px;
  border:1px solid transparent; border-radius:var(--r-sm); background:var(--accent); color:var(--accent-ink);
  font:600 var(--t-md)/1 var(--font-sans); cursor:pointer; white-space:nowrap; text-decoration:none;
}
.btn:hover { background:var(--accent-hover); text-decoration:none }
.btn svg { width:15px; height:15px; stroke:currentColor; fill:none; stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round }
.btn--ghost { background:var(--surface); color:var(--ink); border-color:var(--line-strong) }
.btn--ghost:hover { background:var(--surface-2); border-color:var(--ink-3) }
.btn--quiet { background:transparent; color:var(--ink-2) }
.btn--quiet:hover { background:var(--surface-3); color:var(--ink) }
.btn--danger { background:transparent; color:var(--bad); border-color:transparent }
.btn--danger:hover { background:var(--bad-soft) }
.btn--sm { height:26px; padding:0 9px; font-size:var(--t-xs); border-radius:4px }
.btn[disabled] { opacity:.5; cursor:not-allowed }
.inline { display:inline }

/* A fallback for a browser running no script: with one, changing the control is the whole
   gesture. Hidden in CSS, not by a pass over the document — the rows carrying these are
   re-rendered on every in-place update, and the pass only ever ran once. */
.js [data-inline-submit], .js [data-live-submit] { display:none !important }

/* ---- forms --------------------------------------------------------------- */
.input,.select,textarea {
  width:100%; min-height:34px; padding:6px 10px; border:1px solid var(--line-strong); border-radius:var(--r-sm);
  background:var(--surface); color:var(--ink); font:400 var(--t-md)/1.4 var(--font-sans);
}
textarea { resize:vertical }
.select { appearance:none; padding-right:26px;
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 14px) 15px, calc(100% - 9px) 15px; background-size:5px 5px,5px 5px; background-repeat:no-repeat }
.input:focus,.select:focus,textarea:focus { outline:2px solid var(--focus); outline-offset:-1px; border-color:var(--focus) }
/* A control that does not apply to the current view must read as inert, or it states a
   setting the page is not on. */
.input:disabled,.select:disabled,textarea:disabled {
  background:var(--surface-2); color:var(--ink-3); border-color:var(--line); cursor:not-allowed }
/* A filter you can put down again. Whether there is anything to clear is read off the
   placeholder rather than kept as state, so it survives the rows being re-rendered. */
.clearable { position:relative; display:block; min-width:0 }
.clearable .input { width:100%; padding-right:30px }
.clearable .input::-webkit-search-cancel-button { display:none }  /* ours, not the browser's */
.clearable__x {
  position:absolute; right:5px; top:50%; transform:translateY(-50%);
  display:none; place-items:center; width:22px; height:22px; padding:0;
  border:0; border-radius:var(--r-sm); background:transparent; color:var(--ink-3); cursor:pointer;
}
.clearable .input:not(:placeholder-shown) ~ .clearable__x { display:grid }
.clearable__x:hover { background:var(--surface-3); color:var(--ink) }
.clearable__x svg { width:14px; height:14px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round }

.field { display:flex; flex-direction:column; gap:5px; min-width:0 }
.field > .label { font-size:var(--t-xs); font-weight:600; letter-spacing:.05em; text-transform:uppercase; color:var(--ink-3) }
.field__hint { font-size:var(--t-xs); color:var(--ink-3) }
.grid-form { display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); gap:var(--s4) }
.check { display:flex; align-items:center; gap:8px; font-size:var(--t-md); color:var(--ink-2) }
.check input { width:15px; height:15px; accent-color:var(--accent) }
.form-actions { display:flex; gap:var(--s2); align-items:center; flex-wrap:wrap; padding-top:var(--s2) }
.toolbar { display:flex; flex-wrap:wrap; gap:var(--s3); align-items:flex-end; padding:var(--s4) var(--s5); border-bottom:1px solid var(--line); background:var(--surface-2) }
.toolbar .field { flex:0 1 150px }
.toolbar .field--grow { flex:1 1 200px }
.toolbar .select,.toolbar .input { height:32px }
.cell-select { width:auto; max-width:100%; height:26px; padding:0 22px 0 7px; font-size:var(--t-xs); border-color:transparent; background-color:transparent; background-position:calc(100% - 11px) 12px, calc(100% - 6px) 12px }
.cell-select:hover { border-color:var(--line-strong); background-color:var(--surface) }

/* ---- empty state --------------------------------------------------------- */
.empty { display:flex; flex-direction:column; align-items:center; gap:var(--s3); padding:var(--s7) var(--s5); text-align:center; color:var(--ink-3) }
.empty svg { width:26px; height:26px; stroke:currentColor; fill:none; stroke-width:1.4 }
.empty__title { font-size:var(--t-base); font-weight:600; color:var(--ink-2) }
.empty p { max-width:44ch; font-size:var(--t-md) }

/* ---- charts -------------------------------------------------------------- */
.chart { position:relative }
.chart svg { display:block; width:100%; height:auto; overflow:visible }
.chart .axis { font:500 10px var(--font-sans); fill:var(--ink-3) }
.chart .rule { stroke:var(--line); stroke-width:1 }
.chart .rule--zero { stroke:var(--line-strong) }
.chart .mark { cursor:default }
.chart .mark--0 { fill:var(--chart-1) }
.chart .mark--1 { fill:var(--chart-2) }
.chart--net .mark--0 { fill:var(--good) }
.chart--net .mark--1 { fill:var(--bad) }
.chart .mark:hover { opacity:.82 }
.legend { display:flex; gap:var(--s4); align-items:center; font-size:var(--t-sm); color:var(--ink-2) }
.legend span { display:inline-flex; align-items:center; gap:6px }
.legend i { width:9px; height:9px; border-radius:2px; display:inline-block }
.tip {
  position:fixed; z-index:50; pointer-events:none; opacity:0; transform:translate(-50%,-118%);
  background:var(--ink); color:var(--surface); padding:5px 9px; border-radius:5px;
  font-size:var(--t-xs); font-weight:500; white-space:nowrap; box-shadow:var(--shadow-md); transition:opacity .1s;
}
.tip.is-on { opacity:1 }

/* What an action says back. Fixed, so filing a line never moves the line below it. */
.toast {
  position:fixed; z-index:60; left:50%; bottom:var(--s5); transform:translate(-50%, 12px);
  max-width:min(90vw, 44ch); padding:9px 14px; border-radius:var(--r-md);
  background:var(--ink); color:var(--surface); font-size:var(--t-md); font-weight:500;
  box-shadow:var(--shadow-md); opacity:0; pointer-events:none;
  transition:opacity .14s ease, transform .14s ease;
}
.toast.is-on { opacity:1; transform:translate(-50%, 0) }
.toast--err { background:var(--bad); color:#fff }
.tip b { font-variant-numeric:tabular-nums }

/* One row of a proposed set: the invoices, then their sum on the same grid so the
   arithmetic is readable down the column rather than asserted in prose. */
.setline { display:grid; grid-template-columns:minmax(7ch,auto) 1fr minmax(9ch,auto); gap:var(--s3);
  align-items:baseline; padding:2px 0 }
.setline .num { font-variant-numeric:tabular-nums; text-align:right }
.setline--sum { border-top:1px solid var(--line); margin-top:3px; padding-top:4px }

.table th.pick, .table td.pick { width:28px; padding-right:0 }
.panel__foot { display:flex; align-items:center; gap:var(--s3); flex-wrap:wrap;
  padding:var(--s3) var(--s4); border-top:1px solid var(--line) }

/* ---- the record on the other end of a match ----------------------------- */
/* A number and an amount say a link exists. They do not say whether it is the right one,
   which is the only question worth asking here. */
.linked { border:1px solid var(--line); border-radius:var(--r-md); background:var(--surface-2) }
.linked__head { display:flex; align-items:baseline; gap:var(--s3); padding:10px var(--s4);
  border-bottom:1px solid var(--line) }
.linked__name { font-weight:600; min-width:0; overflow-wrap:anywhere }
.linked__amount { margin-left:auto; font-weight:700; font-variant-numeric:tabular-nums; white-space:nowrap }
.linked__meta { display:grid; grid-template-columns:minmax(8em,auto) 1fr; gap:3px var(--s4);
  margin:0; padding:10px var(--s4) }
.linked__meta dt { font-size:var(--t-xs); letter-spacing:.04em; text-transform:uppercase; color:var(--ink-3); font-weight:600 }
.linked__meta dd { margin:0; font-size:var(--t-sm); min-width:0; overflow-wrap:anywhere }
.linked__note { padding:0 var(--s4) 10px; font-size:var(--t-xs); color:var(--ink-3) }

.note-title { font-weight:600 }
.table tbody tr.is-done .note-title { color:var(--ink-3); font-weight:500 }

/* ---- the list that follows you ------------------------------------------- */
.drawer__veil { position:fixed; inset:0; z-index:39; background:rgba(11,20,32,.28) }
.drawer {
  position:fixed; z-index:40; top:0; right:0; bottom:0; width:min(380px, 92vw);
  display:flex; flex-direction:column;
  background:var(--surface); border-left:1px solid var(--line); box-shadow:var(--shadow-md);
}
.drawer__head { display:flex; align-items:center; gap:var(--s3); padding:var(--s5) var(--s5) var(--s4) }
.drawer__title { font:600 1.1rem/1 var(--font-serif); letter-spacing:-.01em; margin-right:auto; min-width:0 }
.drawer__add { display:flex; gap:var(--s2); padding:0 var(--s5) var(--s4) }
.drawer__add .input { flex:1 1 auto; min-width:0 }
.drawer__body { flex:1 1 auto; overflow-y:auto; padding:0 var(--s5) var(--s5) }
.drawer__empty { padding:var(--s5) 0 }
.drawer__done { margin-top:var(--s5); border-top:1px solid var(--line); padding-top:var(--s4) }

/* The record panel is the same drawer, wider, and its content is a page written for two
   columns — which it does not have here. */
.drawer--wide { width:min(760px, 96vw) }
.drawer--wide .drawer__body { padding:0 var(--s5) var(--s6) }
.drawer--wide .drawer__body .cols--2,
.drawer--wide .drawer__body .cols--2.cols--right,
.drawer--wide .drawer__body .cols { grid-template-columns:1fr }
.drawer--wide .page__title { font-size:1.15rem }
.drawer--wide .page__sub { font-size:var(--t-sm) }
.drawer__title { min-width:0; margin-right:auto }
.drawer__full { flex:none }
.drawer__full svg { width:15px; height:15px; fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round }

.todo-list { list-style:none; margin:0; padding:0; display:flex; flex-direction:column }
.todo-item { display:flex; align-items:flex-start; gap:10px; padding:8px 0; border-bottom:1px solid var(--line) }
.todo-item:last-child { border-bottom:0 }
.todo-text { flex:1 1 auto; min-width:0; font-size:var(--t-md); line-height:1.45; overflow-wrap:anywhere }
.todo-item.is-done .todo-text { color:var(--ink-3); text-decoration:line-through }
.todo-where { display:block; margin-top:2px; font-size:var(--t-xs); color:var(--ink-3) }
.todo-tick {
  flex:none; margin-top:2px; width:17px; height:17px; padding:0; border-radius:4px; cursor:pointer;
  border:1.5px solid var(--line-strong); background:var(--surface);
  display:grid; place-items:center; color:var(--surface);
}
.todo-tick:hover { border-color:var(--accent) }
.todo-tick.is-on { background:var(--accent); border-color:var(--accent) }
.todo-tick svg { width:12px; height:12px; fill:none; stroke:currentColor; stroke-width:2.6; stroke-linecap:round; stroke-linejoin:round }
.todo-drop {
  flex:none; border:0; background:transparent; color:var(--ink-3); cursor:pointer; padding:2px;
  opacity:0; transition:opacity .12s ease;
}
.todo-drop svg { width:14px; height:14px; fill:none; stroke:currentColor; stroke-width:1.8; stroke-linecap:round }
.todo-item:hover .todo-drop, .todo-drop:focus-visible { opacity:1 }
.todo-drop:hover { color:var(--bad) }
/* The rail entry is a button, not a link, so it has to be told to look like one. */
.rail__link { border:0; background:transparent; width:100%; text-align:left; font-family:inherit; cursor:pointer }

/* ---- results sheet ------------------------------------------------------- */
.sheet td:first-child, .sheet th:first-child { position:sticky; left:0; z-index:1; background:var(--surface); min-width:210px }
.sheet tbody tr:nth-child(even) td:first-child { background:var(--surface-2) }
.sheet tbody tr:hover td:first-child { background:var(--accent-soft) }
.sheet .row-section td { background:var(--surface-3) !important; font-size:var(--t-xs); letter-spacing:.08em; text-transform:uppercase; font-weight:700; color:var(--ink-2) }
.sheet .row-total td { font-weight:700; border-top:1px solid var(--line-strong) }
.sheet .row-net td { font-weight:700; background:var(--surface-2) !important; border-top:2px solid var(--ink) }
.sheet .col-now { background:color-mix(in srgb, var(--accent-soft) 60%, transparent) }

/* ---- a figure you can open ------------------------------------------------ */
.figure {
  border:0; background:none; padding:0; margin:0; font:inherit; color:inherit; cursor:pointer;
  font-variant-numeric:tabular-nums; border-bottom:1px dotted var(--line-strong);
}
.figure:hover { color:var(--accent); border-bottom-color:var(--accent) }
.sheet .row-net .figure, .sheet .row-total .figure { font-weight:700 }

.dialog {
  width:min(920px, 94vw); max-height:86vh; padding:0; border:1px solid var(--line);
  border-radius:var(--r-lg); background:var(--surface); color:var(--ink); box-shadow:var(--shadow-md);
  overflow:hidden;
}
.dialog::backdrop { background:rgba(15,27,42,.45) }
.dialog__close {
  position:absolute; top:10px; right:12px; z-index:2; border:0; background:none; cursor:pointer;
  font-size:1.5rem; line-height:1; color:var(--ink-3); padding:2px 6px; border-radius:var(--r-sm);
}
.dialog__close:hover { background:var(--surface-3); color:var(--ink) }
.dialog__body { max-height:86vh; overflow:auto }
.detail__head { display:flex; align-items:baseline; gap:var(--s4); padding:var(--s5) var(--s6) var(--s4); border-bottom:1px solid var(--line) }
.detail__title { font:600 1.1rem/1.2 var(--font-serif) }
.detail__sub { font-size:var(--t-sm); color:var(--ink-3) }
.detail__total { margin-left:auto; text-align:right; font:600 1.15rem/1 var(--font-serif); font-variant-numeric:tabular-nums; padding-right:var(--s5) }
/* A results sheet marks a qualified figure the way a printed one does: a footnote mark,
   not a badge that pushes the row open. */
/* ---- notes on a row ---- */
/* An empty note must not read as content: it is a faint outline the row reveals, while a
   note that exists carries the accent and stays visible at rest. */
.note-cell { width:30px; padding-left:6px !important; padding-right:0 !important }
.note {
  display:inline-flex; align-items:center; justify-content:center; width:26px; height:26px;
  border:0; border-radius:var(--r-sm); background:transparent; color:var(--ink-3);
  cursor:pointer; opacity:0; transition:opacity .12s ease, color .12s ease;
}
.note svg { width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round }
.note:hover { background:var(--surface-2); color:var(--ink) }
.note:focus-visible { opacity:1; outline:2px solid var(--focus); outline-offset:-1px }
tr:hover .note { opacity:1 }
.note--set { opacity:1; color:var(--accent) }
.note--set:hover { color:var(--accent) }
.dialog--narrow { max-width:36rem }
.note-form { display:flex; flex-direction:column; gap:var(--s4); padding:var(--s5) }
.note-form textarea { resize:vertical; min-height:6rem; font:400 var(--t-md)/1.5 var(--font-sans) }

.footmark { color:var(--warn); font-weight:700; cursor:help; padding-left:2px }
.detail__caveat { margin-top:5px; font:400 var(--t-xs)/1.4 var(--font-sans); color:var(--ink-3); max-width:24ch }

/* ---- vault --------------------------------------------------------------- */
.drop {
  display:flex; flex-direction:column; align-items:center; gap:6px; padding:var(--s5);
  border:1.5px dashed var(--line-strong); border-radius:var(--r-md); background:var(--surface-2); text-align:center;
}
.drop input[type=file]::file-selector-button {
  font:600 var(--t-sm)/1 var(--font-sans); padding:7px 12px; margin-right:10px; cursor:pointer;
  border:1px solid var(--line-strong); border-radius:var(--r-sm); background:var(--surface); color:var(--ink);
}
.drop.is-over { border-color:var(--accent); background:var(--accent-soft) }
.drop svg { width:24px; height:24px; stroke:var(--ink-3); fill:none; stroke-width:1.4 }
.drop__title { font-weight:600; font-size:var(--t-base) }
.drop__hint { font-size:var(--t-sm); color:var(--ink-3); max-width:52ch }
.drop input[type=file] { font-size:var(--t-sm); color:var(--ink-2); max-width:100% }
.gap-list { display:flex; flex-direction:column }
.gap { display:flex; gap:var(--s3); padding:var(--s4) var(--s5); border-bottom:1px solid var(--line) }
.gap:last-child { border-bottom:0 }
.gap__icon { width:26px; height:26px; border-radius:50%; display:grid; place-items:center; flex:none; background:var(--warn-soft); color:var(--warn) }
.gap__icon svg { width:14px; height:14px; stroke:currentColor; fill:none; stroke-width:1.8 }
.gap--quiet .gap__icon { background:var(--surface-3); color:var(--ink-3) }
.gap__body { min-width:0; display:flex; flex-direction:column; gap:2px }
.gap__title { font-size:var(--t-md); font-weight:600 }
.gap__detail { font-size:var(--t-sm); color:var(--ink-2) }
.gap__meta { font-size:var(--t-xs); color:var(--ink-3) }
.gap__act { margin-left:auto; align-self:center }

[aria-busy="true"] { opacity:.5; transition:opacity .12s ease }
@media (prefers-reduced-motion: reduce) { [aria-busy="true"] { transition:none } }

/* ---- misc ---------------------------------------------------------------- */
.meta { display:grid; grid-template-columns:auto 1fr; gap:7px var(--s4); font-size:var(--t-md); align-items:baseline }
.meta dt { font-size:var(--t-xs); letter-spacing:.05em; text-transform:uppercase; color:var(--ink-3); font-weight:600; white-space:nowrap }
.meta dd { margin:0; min-width:0 }
.row { display:flex; align-items:center; gap:var(--s2); flex-wrap:wrap }
.row--tight { gap:var(--s1) }
.between { display:flex; align-items:center; justify-content:space-between; gap:var(--s3) }
details.reveal > summary { cursor:pointer; font-size:var(--t-sm); color:var(--ink-2); font-weight:500; padding:var(--s2) 0 }
details.reveal > summary::marker { color:var(--ink-3) }
pre.raw { margin:0; padding:var(--s3); background:var(--surface-2); border:1px solid var(--line); border-radius:var(--r-sm);
  font:400 var(--t-xs)/1.6 var(--font-mono); white-space:pre-wrap; word-break:break-word; color:var(--ink-2); max-height:280px; overflow:auto }
.score { display:inline-flex; align-items:center; gap:6px; font-size:var(--t-xs); color:var(--ink-3) }
.score__bar { width:38px; height:5px; border-radius:3px; background:var(--surface-3); overflow:hidden }
.score__fill { display:block; height:100%; background:var(--accent) }

/* ---- login --------------------------------------------------------------- */
body.is-login { display:block; background:var(--ground) }
.login { min-height:100vh; display:grid; place-items:center; padding:var(--s5) }
.login__card { width:100%; max-width:360px; background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg); padding:var(--s6); box-shadow:var(--shadow-md) }
.login__mark { font:600 1.3rem/1 var(--font-serif); letter-spacing:-.015em }
.login__co { font-size:var(--t-xs); letter-spacing:.1em; text-transform:uppercase; color:var(--ink-3); font-weight:600; margin-bottom:var(--s5) }
.login form { display:flex; flex-direction:column; gap:var(--s4) }

/* ---- responsive ---------------------------------------------------------- */
@media (max-width: 1120px) { .cols--2, .cols--2.cols--right { grid-template-columns:1fr } }
@media (max-width: 900px) {
  body { grid-template-columns:1fr }
  .rail { position:static; height:auto; flex-direction:row; align-items:center; gap:var(--s3);
          overflow-x:auto; border-right:0; border-bottom:1px solid var(--line); padding:var(--s3) var(--s4) }
  .rail__brand { padding:0; margin-right:var(--s3) }
  .rail__group { flex-direction:row; margin:0; gap:2px }
  .rail__legend { display:none }
  .rail__foot { margin:0 0 0 auto; padding-top:0; border:0 }
  .rail__link { white-space:nowrap }
  .rail__toggle { display:none }
  .page__head { position:static; padding:var(--s4) var(--s4) }
  .page__body { padding:var(--s4) var(--s4) var(--s6) }
  .table td:first-child,.table th:first-child { padding-left:var(--s4) }
}
@media (prefers-reduced-motion: reduce) { *,*::before,*::after { animation:none !important; transition:none !important } }
