/* ── Transactions ────────────────────────────────────────── */
.txn-section-label {
  font-size: var(--text-caption);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  margin-bottom: 14px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}

.filters-bar {
  display: flex;
  gap: 12px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.filter-input, .filter-select {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  padding: 8px 12px;
  outline: none;
  transition: border-color 0.15s;
}

.filter-input:focus, .filter-select:focus { border-color: var(--accent); }
.filter-input { flex: 1; min-width: 200px; }

.manage-cat-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: var(--text-caption);
  padding: 8px 14px;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 0.15s, color 0.15s;
}
.manage-cat-btn:hover { border-color: var(--accent); color: var(--accent); }

.manage-cat-btn--primary {
  border-color: var(--text-bright);
  color: var(--text-bright);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}
.manage-cat-btn--primary:hover {
  background: var(--surface2);
  border-color: var(--text-bright);
  color: var(--text-bright);
}

.txn-table-wrap {
  background: var(--surface);
  border: 1px solid var(--border);
  overflow-x: auto;
}

#txnTableWrap {
  max-height: 520px;
  overflow-y: auto;
}

#txnTableWrap thead th {
  position: sticky;
  top: 0;
  background: var(--surface);
  z-index: 1;
}

table { width: 100%; border-collapse: collapse; }

thead th {
  padding: 12px 16px;
  text-align: left;
  font-size: var(--text-caption);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--border);
  background: var(--surface2);
}

tbody tr {
  border-bottom: 1px solid var(--border);
  transition: background 0.1s;
}

tbody tr:last-child { border-bottom: none; }
tbody tr:hover { background: var(--accent-glow); }

td {
  padding: 12px 16px;
  font-size: var(--text-sm);
}

.txn-merchant {
  color: var(--text-bright);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 280px;
}
.txn-account  { color: var(--muted); font-size: var(--text-caption); }
.txn-channel  { color: var(--text-dim); font-size: var(--text-sm); text-transform: lowercase; }
/* position: relative so the "Reviewed" flash can be laid over the date without
   widening the column — see the transaction review block below. */
.txn-date {
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  position: relative;
}

.txn-category-pill {
  display: inline-block;
  padding: 2px 8px;
  font-size: var(--text-caption);
  letter-spacing: 0;
  background: var(--surface2);
  border: 1px solid var(--border);
  color: var(--text-dim);
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
  text-transform: lowercase;
}
.txn-category-pill:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-glow);
}

.txn-amount { font-weight: 500; text-align: right; }
.txn-amount.debit { color: var(--red); }
.txn-amount.credit { color: var(--green); }

.pending-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  background: var(--warning);
  border-radius: 50%;
  margin-left: 6px;
  vertical-align: middle;
}

.txn-ignored-dot {
  display: inline-block;
  margin-left: 5px;
  vertical-align: middle;
  font-size: 11px;
  color: var(--muted);
  line-height: 1;
}

/* ── Transaction review ──────────────────────────────────── */
/* The checkbox is the entire signal: it appears only on rows still waiting to
   be reviewed and vanishes once checked. Reviewed rows are styled no differently
   from any other row — there is nothing left to say about them, and dimming them
   would leave a fully-reviewed table looking uniformly faded.
   It has no column of its own and trails the date instead, so a checked row
   leaves behind no reserved gap to give away that it was ever there. */
.txn-review-check {
  accent-color: var(--accent);
  width: 13px;
  height: 13px;
  margin: 0 0 0 8px;
  cursor: pointer;
  vertical-align: baseline;
}
.txn-review-check:disabled { cursor: default; opacity: 0.45; }

/* Checking it doesn't just cut the control — it lands, then leaves: a quick
   swell while the check reads as registered, then a shrink out. The whole
   sequence below runs to 900ms, matching TXN_REVIEW_ANIM_MS in script.js, which
   holds the repaint until it ends. */
@keyframes txn-review-confirm {
  0%   { transform: scale(1);    opacity: 1; }
  30%  { transform: scale(1.3);  opacity: 1; }
  55%  { transform: scale(1.15); opacity: 1; }
  100% { transform: scale(0.4);  opacity: 0; }
}

.txn-review-check.is-confirming,
.txn-review-dot.is-confirming {
  animation: txn-review-confirm 300ms cubic-bezier(0.34, 1.06, 0.64, 1) forwards;
  pointer-events: none;
}

/* As the box leaves, the date steps aside and the row says what just happened —
   then hands the cell back. The date returns as part of the animation rather
   than on the repaint, so the cell is never left blank if the repaint is
   deferred by another click landing behind this one. */
@keyframes txn-date-swap {
  0%   { opacity: 1; }
  25%  { opacity: 0; }
  70%  { opacity: 0; }
  100% { opacity: 1; }
}
.txn-date-text.is-swapping {
  animation: txn-date-swap 900ms ease forwards;
}

@keyframes txn-review-flash {
  0%   { opacity: 0; transform: translateY(3px); }
  25%  { opacity: 1; transform: translateY(0); }
  70%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(-2px); }
}
.txn-review-flash {
  position: absolute;
  /* Spans the cell and re-applies its padding, so the word starts on exactly the
     same left edge as the date it replaces. Inheriting rather than hardcoding
     the offset keeps it right in both layouts — the cell is padded 16px on
     desktop and 12px on mobile. */
  inset: 0;
  padding: inherit;
  /* Deliberately not flex-centred. Rows are two lines tall (merchant over
     account), while the date is a single line sitting at the top of the cell —
     centring would drop the word below it, badly on mobile where the account
     line carries tags. Laid out as an ordinary block it becomes the first line
     box of the same padding box the date occupies, and inherits the same
     line-height, so the two land on the same baseline in both layouts. */
  /* A word, not a figure — Karla, never the mono the rest of this cell uses. */
  font-family: var(--font-sans);
  font-size: var(--text-caption);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--accent-text);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  animation: txn-review-flash 720ms 180ms ease forwards;
}
/* The dot has no checked state of its own, so it fills to signal the same thing
   the checkbox's tick does before it goes. */
.txn-review-dot.is-confirming {
  background: var(--accent);
  border-color: var(--accent);
}

/* When the table is filtered to unreviewed, the row leaves too — held back until
   the word has had its moment, so the row doesn't fade out from under it. */
@keyframes txn-row-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}
tr.txn-row-leaving {
  animation: txn-row-out 280ms 620ms ease forwards;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .txn-review-check.is-confirming,
  .txn-review-dot.is-confirming,
  .txn-date-text.is-swapping,
  .txn-review-flash,
  tr.txn-row-leaving { animation: none; }
  .txn-review-flash { display: none; }
}

/* Mobile has no date column to hang it off, so it trails the merchant name. */
.txn-review-dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  margin-left: 7px;
  border: 1.5px solid var(--muted);
  border-radius: 50%;
  vertical-align: middle;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.txn-review-dot.is-static { cursor: default; opacity: 0.6; }
.txn-review-dot:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.txn-mark-reviewed-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: var(--text-caption);
  padding: 4px 10px;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 0.15s, color 0.15s;
}
.txn-mark-reviewed-btn:hover { border-color: var(--accent); color: var(--accent-text); }
.txn-mark-reviewed-btn.is-confirming {
  border-color: var(--accent);
  color: var(--accent-text);
  background: var(--accent-glow);
}

.txn-review-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: var(--text-caption);
  padding: 7px 14px;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  transition: border-color 0.15s, color 0.15s;
  white-space: nowrap;
}
.txn-review-btn:hover { border-color: var(--accent); color: var(--accent-text); }
.txn-review-btn.active {
  border-color: var(--accent-border);
  color: var(--accent-text);
  background: var(--accent-glow);
}

/* ── Ignored transaction row ─────────────────────────────── */
tr.txn-ignored td { opacity: 0.45; }
tr.txn-ignored .txn-amount { text-decoration: line-through; }

.txn-ignored-badge {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 5px;
  font-size: var(--text-caption);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--border);
  vertical-align: middle;
}

/* ── Transaction detail modal ────────────────────────────── */
.txn-detail-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 20px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--border);
}

.txn-detail-merchant {
  font-size: var(--text-lg);
  color: var(--text-bright);
  font-weight: 500;
}

.txn-detail-amount-wrap {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
}

.txn-detail-amount {
  font-size: var(--text-xl);
  font-weight: 500;
  display: inline-flex;
  align-items: baseline;
}
.txn-detail-amount.debit { color: var(--red); }
.txn-detail-amount.credit { color: var(--green); }

.txn-amount-sign { margin-right: 1px; }

.txn-amount-input {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  color: inherit;
  font: inherit;
  font-family: var(--font-mono);
  text-align: right;
  width: 9ch;
  padding: 0 2px 1px;
  -moz-appearance: textfield;
}
.txn-amount-input::-webkit-outer-spin-button,
.txn-amount-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.txn-amount-input:focus { outline: none; border-bottom-color: var(--accent); }

.txn-original-amount {
  font-size: var(--text-caption);
  font-family: var(--font-mono);
  color: var(--muted);
  font-weight: 400;
}

.txn-detail-rows { display: flex; flex-direction: column; gap: 10px; }

.txn-detail-row {
  display: flex;
  gap: 16px;
  font-size: var(--text-base);
  align-items: center;
}

.txn-detail-label {
  color: var(--muted);
  min-width: 90px;
  font-size: var(--text-caption);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}

.txn-detail-value { color: var(--text); }

.txn-date-input {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  padding: 0 2px 1px;
  cursor: pointer;
}
.txn-date-input:focus { outline: none; border-bottom-color: var(--accent); }

.txn-original-date {
  display: block;
  font-size: var(--text-caption);
  color: var(--muted);
  margin-top: 3px;
}

/* ── Transaction notes ───────────────────────────────────── */
.txn-detail-row--note { align-items: flex-start; }
.txn-detail-row--note .txn-detail-label { padding-top: 3px; }
.txn-detail-row--note .txn-detail-value { flex: 1; min-width: 0; }

.txn-note-input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  resize: none;
  overflow: hidden;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.45;
  padding: 2px 2px 3px;
}
.txn-note-input::placeholder { color: var(--muted); }
.txn-note-input:focus { outline: none; border-bottom-color: var(--accent); }
/* iOS zooms into any input under 16px on focus */
@media (hover: none) and (pointer: coarse) {
  .txn-note-input { font-size: 16px; }
}

.txn-note-text { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.45; }
.txn-note-text.is-empty { color: var(--muted); }

/* Sits under the NOTE label, so confirming a save never shifts the rows */
.txn-note-status {
  display: block;
  margin-top: 3px;
  color: var(--accent-text);
  opacity: 0;
  transition: opacity 0.2s;
}
.txn-note-status.is-visible { opacity: 1; }

.txn-note-line {
  color: var(--text-dim);
  font-size: var(--text-caption);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 280px;
}

@media (prefers-reduced-motion: reduce) {
  .txn-note-status { transition: none; }
}

.txn-detail-ignore {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.txn-ignore-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: var(--text-caption);
  padding: 7px 14px;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  transition: border-color 0.15s, color 0.15s;
  white-space: nowrap;
}
.txn-ignore-btn:hover { border-color: var(--accent); color: var(--accent); }
.txn-ignore-btn.active { border-color: var(--red); color: var(--red); }
.txn-ignore-btn.active:hover { border-color: var(--red); color: var(--red); }

.txn-detail-ignore-note {
  font-size: var(--text-caption);
  color: var(--muted);
}

/* ── Pagination ──────────────────────────────────────────── */
.pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  background: var(--surface2);
  font-size: var(--text-caption);
  color: var(--muted);
}

.page-btns { display: flex; gap: 4px; }

.page-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: var(--font-sans);
  font-size: var(--text-caption);
  padding: 4px 10px;
  cursor: pointer;
  transition: all 0.15s;
}

.page-btn:hover, .page-btn.active {
  background: var(--accent-dim);
  border-color: var(--accent);
  color: var(--accent);
}

/* ── Recurring widget ────────────────────────────────────── */
.rec-subtitle .rec-figure { color: var(--text-bright); }
.rec-figure {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
.rec-body { max-height: 320px; overflow-y: auto; padding-top: 4px; }
.rec-empty {
  padding: 32px 16px;
  text-align: center;
  color: var(--muted);
  font-size: var(--text-base);
}
.rec-empty--error { color: var(--red); }
.rec-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 4px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  min-width: 0;
}
.rec-row:last-child { border-bottom: none; }
.rec-row:hover { background: var(--surface2); }
.rec-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.rec-swatch {
  width: 6px;
  height: 6px;
  flex-shrink: 0;
}
.rec-main { flex: 1; min-width: 0; }
.rec-name,
.rec-meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rec-name { color: var(--text-bright); font-size: var(--text-base); }
.rec-meta { color: var(--muted); font-size: var(--text-caption); margin-top: 2px; }
.rec-side { text-align: right; flex-shrink: 0; }
.rec-amt {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-sm);
  color: var(--text-bright);
}
.rec-amt.credit { color: var(--green); }
.rec-next { color: var(--muted); font-size: var(--text-caption); margin-top: 2px; }
.rec-next--due { color: var(--accent-text); }
