/* Deliberately a near-copy of categorize.css's base rather than a shared
   stylesheet: the two pages are visually the same family, but categorize.css
   is already the odd one out against app.css, and factoring a third shared
   file out of two 200-line sheets would cost more than it saves. Only the
   filter bar, sortable headers, pagination and split dialog below are new. */

* {
  box-sizing: border-box;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  max-width: 1100px;
  margin: 40px auto;
  padding: 0 16px 40px;
  color: #1b1b1b;
  font-size: 14px;
}

h1 {
  font-size: 18px;
  margin-bottom: 4px;
}

h2 {
  font-size: 16px;
  margin: 0 0 4px;
}

a {
  color: #6b2c81;
}

.intro {
  font-size: 13px;
  line-height: 1.5;
  color: #555;
  margin-top: 0;
}

.status {
  font-size: 12px;
  color: #6b2c81;
  min-height: 18px;
  margin: 12px 0;
}

.status-error {
  color: #eb5757;
}

.muted {
  font-size: 12px;
  color: #888;
}

.hidden {
  display: none !important;
}

.empty {
  font-size: 13px;
  color: #888;
}

button {
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 600;
  color: #fff;
  background: #6b2c81;
  border: none;
  border-radius: 6px;
  cursor: pointer;
}

button:hover:not(:disabled) {
  background: #582269;
}

button:disabled {
  background: #ccc;
  cursor: default;
}

button.secondary {
  background: #f2f2f2;
  color: #444;
}

button.secondary:hover:not(:disabled) {
  background: #e6e6e6;
}

.link-button {
  background: none;
  border: none;
  padding: 0;
  color: #6b2c81;
  font-weight: 500;
  font-size: 13px;
  text-decoration: underline;
  cursor: pointer;
}

.link-button:hover:not(:disabled) {
  background: none;
  color: #582269;
}

/* --- filters ------------------------------------------------------------ */

.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  padding: 12px 0;
  border-top: 1px solid #eee;
  border-bottom: 1px solid #eee;
}

.filters-spacer {
  flex: 1;
}

/* --- bulk edit ---------------------------------------------------------- */

/* As tight as a tap target allows: this column was added for bulk editing and
   pushed the table 13px past its container on real data, which put the row
   buttons behind a horizontal scroll. The default 8px cell padding is trimmed
   on the inner side for the same reason. */
.col-select {
  width: 18px;
  padding-left: 6px;
  padding-right: 2px;
}
.col-select input { margin: 0; accent-color: #6b2c81; }

.bulk-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin: 12px 0;
  padding: 12px 14px;
  border: 1px solid #d9c7e2;
  border-radius: 8px;
  background: #f8f4fa;
}

.bulk-count {
  font-size: 13px;
  font-weight: 700;
  color: #6b2c81;
  align-self: center;
}

.bulk-labels { display: flex; gap: 6px; }
.bulk-mode { max-width: 110px; }

.bulk-bar .field input[type="text"] { min-width: 160px; }
/* The picker sets its own width from the toggle, which needs a floor here or
   it collapses to the width of "- leave unchanged -" minus the caret. */
.bulk-bar .ss { min-width: 180px; }

.export-group {
  display: flex;
  align-items: center;
  gap: 12px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #888;
  font-weight: 700;
}

.field select,
.field input {
  font-family: inherit;
  font-size: 13px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: #1b1b1b;
  padding: 6px 7px;
  border: 1px solid #ccc;
  border-radius: 5px;
  background: #fff;
  max-width: 220px;
}

/* --- category multi-select ----------------------------------------------
   A button plus an absolutely-positioned checkbox tree, styled to sit level
   with the plain <select> filters beside it. Not a <select multiple>: this
   needs indentation, tri-state parents and a whole-branch tick, none of
   which a native multi-select can do. */

.multiselect { position: relative; }

.multiselect-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  /* Matches .field select's metrics so the filter row stays on one baseline. */
  min-width: 150px;
  max-width: 220px;
  padding: 6px 7px;
  border: 1px solid #ccc;
  border-radius: 5px;
  background: #fff;
  font-family: inherit;
  font-size: 13px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: #1b1b1b;
  cursor: pointer;
}
.multiselect-toggle:hover { background: #fafafa; }
/* An active filter is worth seeing without opening the panel - the summary
   text alone ("3 categories") is easy to skim past. */
.multiselect-toggle.multiselect-toggle-active {
  border-color: #6b2c81;
  color: #6b2c81;
  font-weight: 600;
}

.multiselect-toggle > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.multiselect-caret {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-right: 1.5px solid #888;
  border-bottom: 1.5px solid #888;
  transform: rotate(45deg);
}

.multiselect-panel {
  position: absolute;
  z-index: 30;
  top: calc(100% + 4px);
  left: 0;
  min-width: min(240px, calc(100vw - 24px));
  max-width: min(320px, calc(100vw - 24px));
  background: #fff;
  border: 1px solid #ccc;
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
  overflow: hidden;
}

/* Sits above Select all / Clear because those two act on whatever the search
   has narrowed the list to, so it reads top-down as "narrow, then act". */
.multiselect-search {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  border: 0;
  border-bottom: 1px solid #eee;
  border-radius: 0;
  font: inherit;
  font-size: 13px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: #1b1b1b;
}
.multiselect-search::placeholder { color: #999; }
.multiselect-search:focus {
  outline: 2px solid #6b2c81;
  outline-offset: -2px;
}

.multiselect-actions {
  display: flex;
  gap: 14px;
  padding: 8px 10px;
  border-bottom: 1px solid #eee;
  background: #fafafa;
}

/* Capped so a deep category tree scrolls inside the panel rather than
   running off the bottom of a phone screen. */
.multiselect-options {
  max-height: 280px;
  overflow-y: auto;
  padding: 4px 0;
}

.multiselect-option {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 6px 8px;
  font-size: 13px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: #1b1b1b;
  cursor: pointer;
}
.multiselect-option:hover { background: #f4eef6; }
.multiselect-option input { flex: 0 0 auto; margin: 0; accent-color: #6b2c81; }

.multiselect-option-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.multiselect-empty {
  margin: 0;
  padding: 12px 10px;
  font-size: 13px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: #888;
}

/* ---- Searchable single-select (searchable-select.js) ----
   Used where one transaction gets one category: the inline edit row and both
   category fields in the split dialog. Deliberately shares the panel/option
   look above so the page has one dropdown vocabulary, not two. */

.ss { position: relative; }

.ss-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  width: 100%;
  text-align: left;
  cursor: pointer;
  background: #fff;
}

.ss-toggle-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ss-placeholder { color: #888; }

/* Fixed, not absolute: the inline edit row's <td> sets overflow:hidden and
   would clip an absolutely-positioned panel. searchable-select.js sets
   top/left from the toggle's viewport rect and closes on scroll. */
.ss-panel {
  position: fixed;
  z-index: 40;
  top: 0;
  left: 0;
  min-width: min(260px, calc(100vw - 24px));
  max-width: min(340px, calc(100vw - 24px));
  background: #fff;
  border: 1px solid #ccc;
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
  overflow: hidden;
}

.ss-search {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  border: 0;
  border-bottom: 1px solid #eee;
  border-radius: 0;
  font: inherit;
  font-size: 13px;
  color: #1b1b1b;
}
.ss-search:focus { outline: 2px solid #6b2c81; outline-offset: -2px; }

.ss-options {
  max-height: 280px;
  overflow-y: auto;
  padding: 4px 0;
}

.ss-option {
  display: block;
  width: 100%;
  padding: 7px 10px;
  border: 0;
  background: none;
  font: inherit;
  font-size: 13px;
  text-align: left;
  color: #1b1b1b;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Hover and keyboard highlight are the same colour on purpose: with one
   highlight per list there is no ambiguity about what Enter will pick. */
.ss-option:hover,
.ss-option-active { background: #f4eef6; }
.ss-option-selected { font-weight: 600; color: #6b2c81; }

/* --- totals -------------------------------------------------------------- */

.totals {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 12px;
}

/* One row per currency. Wraps rather than scrolls, so on a phone the three
   tiles stack instead of hiding the net figure off the right edge. */
.totals-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.total-tile {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1 1 150px;
  padding: 8px 12px;
  background: #faf7fb;
  border-radius: 8px;
}

/* The net figure leads: it's the answer to "what did this filter cost me",
   with money in/out as the supporting breakdown. */
.total-tile.total-net {
  background: #f1e7f5;
  flex-basis: 220px;
}

.total-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #888;
  font-weight: 700;
}

.total-value {
  font-size: 16px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.total-tile.total-net .total-value {
  font-size: 20px;
  color: #6b2c81;
}

/* Beats .total-net's purple when the net is positive, since "you came out
   ahead" is worth the same green the credit amounts in the table use. */
.total-tile.amount-credit .total-value {
  color: #22875a;
}

/* --- table -------------------------------------------------------------- */

/* The table is the widest thing on the page, so it scrolls inside its own
   container on narrow screens rather than pushing the body sideways. */
.txn-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 8px;
  display: block;
  overflow-x: auto;
}

.txn-table thead th {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #888;
  text-align: left;
  font-weight: 700;
  padding: 8px 8px 6px;
  white-space: nowrap;
}

.txn-table th.sortable {
  cursor: pointer;
  user-select: none;
}

.txn-table th.sortable:hover {
  color: #6b2c81;
}

/* The arrow is always in the DOM for the sorted column only, but every
   sortable header reserves its width via padding-right so the row doesn't
   reflow by a few pixels each time you re-sort. */
.txn-table th.sortable::after {
  content: "";
  display: inline-block;
  width: 10px;
}

.txn-table th.sorted {
  color: #6b2c81;
}

.txn-table th.sorted-asc::after {
  content: " \2191";
}

.txn-table th.sorted-desc::after {
  content: " \2193";
}

.txn-table td {
  padding: 6px 8px;
  border-top: 1px solid #f0f0f0;
  vertical-align: middle;
}

.txn-table tbody tr:hover {
  background: #faf7fb;
}

.col-date {
  white-space: nowrap;
  color: #888;
  font-size: 12px;
}

.col-payee {
  min-width: 180px;
  /* 280, not 300: the payee is the widest flexible column, so it is where
     the headroom that keeps the row buttons on screen comes from. Long
     payees still ellipsise, and the title attribute carries the full text. */
  max-width: 280px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.col-amount {
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.amount-credit {
  color: #22875a;
}

.col-account,
.col-category {
  font-size: 12px;
  white-space: nowrap;
  max-width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.col-labels {
  white-space: nowrap;
}

.col-actions {
  text-align: right;
}

.label-chip {
  display: inline-block;
  padding: 2px 7px;
  margin-right: 4px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 600;
  background: #f1e7f5;
  color: #6b2c81;
}

.col-actions {
  white-space: nowrap;
}

.row-button {
  padding: 4px 9px;
  margin-left: 3px;
  font-size: 12px;
}

/* --- inline row editing -------------------------------------------------- */

.row-editing td {
  background: #faf7fb;
}

.row-input {
  width: 100%;
  min-width: 140px;
  padding: 5px 6px;
  font-family: inherit;
  font-size: 13px;
  border: 1px solid #ccc;
  border-radius: 5px;
  background: #fff;
  color: #1b1b1b;
}

/* min-width was 180px, which made the labels column the widest thing in an
   editing row (196px against 139px when read-only) and pushed Save/Cancel
   off the right edge. Chips wrap, so a narrower floor costs height on a row
   with many labels rather than costing access to the buttons. */
.label-editor {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  min-width: 130px;
}

.label-chip-editable {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding-right: 4px;
}

.label-chip-remove {
  padding: 0 3px;
  border: none;
  border-radius: 8px;
  background: none;
  color: #6b2c81;
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}

.label-chip-remove:hover:not(:disabled) {
  background: #e3d2ea;
}

/* Grows with what's typed but never pushes the row wider than the column -
   the chips beside it wrap instead. */
.label-input {
  flex: 1 1 80px;
  min-width: 70px;
  max-width: 120px;
  padding: 4px 6px;
  font-family: inherit;
  font-size: 12px;
  border: 1px dashed #ccc;
  border-radius: 5px;
  background: #fff;
  color: #1b1b1b;
}

.label-input:focus {
  border-style: solid;
  border-color: #6b2c81;
  outline: none;
}

.row-error-message {
  font-size: 12px;
  color: #eb5757;
}

/* --- pagination --------------------------------------------------------- */

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: 16px;
}

.pagination button {
  padding: 6px 12px;
  font-size: 12px;
}

/* --- split dialog ------------------------------------------------------- */

.split-dialog {
  border: none;
  border-radius: 10px;
  padding: 20px;
  max-width: 560px;
  width: calc(100% - 32px);
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.2);
}

.split-dialog::backdrop {
  background: rgba(0, 0, 0, 0.35);
}

.split-original {
  font-size: 12px;
  color: #555;
  margin: 0 0 14px;
  padding: 8px 10px;
  background: #faf7fb;
  border-radius: 6px;
}

.split-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.split-fields .field-wide {
  flex: 1 1 100%;
}

.split-fields .field-wide select,
.split-fields .field-wide input {
  max-width: none;
  width: 100%;
}

.split-note {
  font-size: 12px;
  line-height: 1.5;
  color: #666;
  margin: 14px 0 0;
}

.split-preview {
  margin-top: 12px;
  max-height: 240px;
  overflow-y: auto;
  border-top: 1px solid #eee;
  padding-top: 10px;
}

.split-summary {
  font-size: 12px;
  font-weight: 600;
  color: #6b2c81;
  margin: 0 0 8px;
}

.split-warning {
  font-size: 12px;
  line-height: 1.5;
  color: #b56a1c;
  background: #fdf0e3;
  border-radius: 6px;
  padding: 8px 10px;
  margin: 0 0 10px;
}

.preview-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.preview-table td {
  padding: 3px 6px;
  border-top: 1px solid #f4f4f4;
  color: #555;
}

.split-error {
  font-size: 12px;
  line-height: 1.5;
  color: #eb5757;
  margin: 10px 0 0;
}

.split-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 16px;
}

.page-footer {
  margin-top: 24px;
  text-align: right;
}

.page-footer a {
  margin-left: 12px;
  font-size: 13px;
}
