/* SufYam Home — web console. Light/dark, no framework, no build step. */

:root {
  --bg: #f4f6f8;
  --surface: #ffffff;
  --surface-2: #eef1f4;
  --border: #dde2e8;
  --text: #16202c;
  --text-dim: #62717f;
  --accent: #2e7d5b;
  --accent-soft: #e3f1ea;
  --danger: #c0392b;
  --danger-soft: #fbe9e7;
  --warn: #b7791f;
  --warn-soft: #fdf3e0;
  --shadow: 0 1px 3px rgba(16, 32, 48, .08), 0 4px 16px rgba(16, 32, 48, .05);
  --radius: 10px;
  --sidebar-w: 232px;
}

[data-theme="dark"] {
  --bg: #12171d;
  --surface: #1a2129;
  --surface-2: #222b35;
  --border: #2d3844;
  --text: #e6ecf2;
  --text-dim: #90a0b0;
  --accent: #4cc38a;
  --accent-soft: #17372a;
  --danger: #f0705f;
  --danger-soft: #3a1f1c;
  --warn: #e2b04a;
  --warn-soft: #382d16;
  --shadow: 0 1px 3px rgba(0, 0, 0, .4), 0 4px 16px rgba(0, 0, 0, .25);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 15px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

#app { display: flex; min-height: 100vh; }

/* ---------- Sidebar ---------- */

.sidebar {
  width: var(--sidebar-w);
  flex: 0 0 var(--sidebar-w);
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 18px 18px 14px;
  font-weight: 650;
  font-size: 15px;
}

.brand-mark {
  width: 28px;
  height: 28px;
  border-radius: 7px;
  flex: 0 0 auto;
  object-fit: cover;
}

#nav { flex: 1; padding: 4px 10px; overflow-y: auto; }

/* Grouped nav. A hairline rule rather than whitespace alone, so the groups
   still read when the sidebar is short and the gaps get squeezed. */
.nav-group + .nav-group {
  margin-top: 6px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

.nav-group-label {
  padding: 2px 12px 5px;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-dim);
  opacity: .72;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 12px;
  margin-bottom: 2px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}

.nav-item:hover { background: var(--surface-2); color: var(--text); }

.nav-item.active {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

.nav-icon {
  width: 20px;
  font-size: 19px;
  text-align: center;
  flex: 0 0 auto;
}

.nav-item.active .nav-icon { font-variation-settings: 'FILL' 1, 'wght' 500; }

.sidebar-foot { padding: 12px; border-top: 1px solid var(--border); }

.account {
  font-size: 12px;
  color: var(--text-dim);
  padding: 0 4px 8px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- Main ---------- */

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 24px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  position: sticky;
  top: 0;
  z-index: 20;
}

.topbar h1 { flex: 1; margin: 0; font-size: 17px; font-weight: 650; }

.topbar-actions { display: flex; align-items: center; gap: 6px; }

.sync-status { font-size: 12px; color: var(--text-dim); margin-right: 4px; }

.view { padding: 24px; flex: 1; }

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 14px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 550;
  cursor: pointer;
  white-space: nowrap;
}

.btn:hover { filter: brightness(1.06); }
.btn:disabled { opacity: .55; cursor: not-allowed; filter: none; }

.btn-ghost {
  background: transparent;
  color: var(--text-dim);
  border-color: var(--border);
}

.btn-ghost:hover { background: var(--surface-2); color: var(--text); }

.btn-danger { background: var(--danger); color: #fff; border-color: transparent; }

/* Ghost + danger reads as an outlined destructive action. Without this the
   two classes fight: btn-danger sets the red background while btn-ghost keeps
   its muted text colour, leaving grey text sitting on red. */
.btn-ghost.btn-danger {
  background: transparent;
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 45%, transparent);
}

.btn-ghost.btn-danger:hover {
  background: var(--danger-soft);
  color: var(--danger);
  border-color: var(--danger);
}

.btn-icon { padding: 7px 10px; font-size: 15px; }
.btn-block { width: 100%; }
.btn-sm { padding: 5px 10px; font-size: 13px; }

/* ---------- Cards & layout ---------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px;
}

.card-title {
  margin: 0 0 14px;
  font-size: 14px;
  font-weight: 650;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .04em;
}

.grid { display: grid; gap: 16px; }
.grid-stats { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); }

.stat-value { font-size: 26px; font-weight: 680; letter-spacing: -.02em; }
.stat-label { font-size: 13px; color: var(--text-dim); margin-top: 2px; }
.stat-sub { font-size: 12px; color: var(--text-dim); margin-top: 6px; }

.chart-wrap { position: relative; height: 260px; }

/* The multi-line trend gets the full page width — comparing categories over
   time is the thing a wide screen can show that the phone's layout cannot. */
.chart-wide { height: 340px; }

.card-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}

.card-head .card-title { flex: 1; }

/* ---------- Period bar ---------- */

.period-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.period-label { min-width: 160px; text-align: center; }
.period-month { font-size: 15px; font-weight: 660; letter-spacing: -.01em; }
.period-sub { font-size: 11px; color: var(--text-dim); min-height: 14px; }

/* ---------- Ranked bars ---------- */

.ranked-row { padding: 7px 0; }

.ranked-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 5px;
}

.ranked-name {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ranked-value { font-size: 13px; font-weight: 640; font-variant-numeric: tabular-nums; }

.ranked-track {
  height: 8px;
  border-radius: 6px;
  background: var(--surface-2);
  overflow: hidden;
}

.ranked-fill { height: 100%; border-radius: 6px; transition: width .3s ease; }

/* ---------- Compact list rows ---------- */

.mini-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
}

.mini-row:last-child { border-bottom: 0; }

.mini-title {
  font-weight: 560;
  font-size: 13.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mini-sub { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; }
.mini-amount { font-weight: 640; font-variant-numeric: tabular-nums; font-size: 13.5px; }

/* ---------- Toolbar ---------- */

.toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}

.toolbar .spacer { flex: 1; }

.input, .select, .textarea {
  padding: 8px 11px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  width: 100%;
}

.input:focus, .select:focus, .textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
  border-color: var(--accent);
}

.textarea { min-height: 72px; resize: vertical; }
.search { max-width: 280px; }

/* ---------- Table ---------- */

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

table { width: 100%; border-collapse: collapse; font-size: 14px; }

th {
  text-align: left;
  padding: 11px 14px;
  font-size: 12px;
  font-weight: 650;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .04em;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  white-space: nowrap;
}

td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--surface-2); }

td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
td.actions { text-align: right; white-space: nowrap; }

.empty {
  padding: 48px 24px;
  text-align: center;
  color: var(--text-dim);
}

.empty-icon { font-size: 34px; display: block; margin-bottom: 10px; opacity: .55; }

/* ---------- Chips & badges ---------- */

.chip {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 550;
  margin-right: 4px;
}

.chip-accent { background: var(--accent-soft); color: var(--accent); }
.chip-danger { background: var(--danger-soft); color: var(--danger); }
.chip-warn { background: var(--warn-soft); color: var(--warn); }

/* ---------- Category tree ---------- */

.cat-list {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 6px;
}

.cat-row {
  position: relative; /* anchors the .is-child guide rail to the row */
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 8px;
  margin-left: var(--indent, 0);
  background: var(--surface);
  transition: background .12s ease, margin-left .16s ease;
}

/* Only the rows opening a gap animate. The dragged row tracks the pointer
   directly — transitioning it would make it lag behind the cursor. */
.cat-row.is-shifting { transition: transform .18s cubic-bezier(.2, .7, .3, 1), background .12s ease; }
.cat-row.is-dragging { transition: none; }

.cat-row:hover { background: var(--surface-2); }

/* Each level is keyed to the category's own colour: the top level is filled
   with it and flips its text to black or white for contrast, deeper levels get
   progressively fainter tints of the same hue. Indentation and font weight
   alone were not enough to tell three levels apart. */
.cat-row {
  background: var(--row-bg, var(--surface));
  color: var(--row-fg, var(--text));
}

.cat-row.depth-0 {
  font-size: 15px;
  margin-top: 6px;
  border: 0;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .10);
}

.cat-row.depth-0:first-child { margin-top: 0; }

.cat-row.depth-0 .cat-name {
  font-weight: 680;
  letter-spacing: -.01em;
  color: var(--row-fg);
}

.cat-row.depth-0 .chip {
  background: color-mix(in srgb, var(--row-fg) 20%, transparent);
  color: var(--row-fg);
}

.cat-row.depth-0 .drag-handle,
.cat-row.depth-0 .cat-action { color: var(--row-fg); }
.cat-row.depth-0 .btn-ghost { border-color: color-mix(in srgb, var(--row-fg) 35%, transparent); }
.cat-row.depth-0:hover { background: var(--row-hover, var(--row-bg)); }

.cat-row.depth-1 { margin-top: 2px; }
.cat-row.depth-1 .cat-name { font-weight: 570; }

.cat-row.depth-2 { font-size: 13.5px; margin-top: 1px; }
.cat-row.depth-2 .cat-name { font-weight: 500; color: var(--text-dim); }

.cat-row.depth-1:hover,
.cat-row.depth-2:hover { background: var(--surface-2); }

/* Nested rows get a guide rail in their parent's colour. */
.cat-row.depth-1::before,
.cat-row.depth-2::before {
  content: '';
  position: absolute;
  left: -13px;
  top: -1px;
  bottom: -1px;
  width: 2px;
  border-radius: 2px;
  background: var(--row-accent, var(--border));
  opacity: .5;
}

.cat-row.depth-2::before { opacity: .3; }
.cat-row.is-dragging::before { display: none; }

/* Selection is a ring, not a fill — a fill would hide the category colour. */
.cat-row.is-selected {
  background: var(--row-bg, var(--surface));
  box-shadow: 0 0 0 2px var(--accent), 0 1px 2px rgba(0, 0, 0, .1);
}

.cat-row.depth-1.is-selected,
.cat-row.depth-2.is-selected { background: var(--accent-soft); }
.cat-row.depth-1.is-selected .cat-name,
.cat-row.depth-2.is-selected .cat-name { color: var(--accent); }

.cat-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  border-radius: 8px;
}

.cat-row.depth-1 .cat-badge { border-radius: 7px; }
.cat-row.depth-2 .cat-badge { border-radius: 6px; }

/* ---------- Material Symbols ---------- */

.micon {
  font-family: 'Material Symbols Outlined', sans-serif;
  font-weight: normal;
  font-style: normal;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-block;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
  -webkit-font-feature-settings: 'liga';
  -webkit-font-smoothing: antialiased;
  user-select: none;
}

/* ---------- Icon picker ---------- */

.icon-picker-trigger {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
  text-align: left;
}

.icon-picker-trigger:hover { border-color: var(--accent); }
.icon-picker-trigger > .micon:first-child { font-size: 21px; color: var(--accent); }
.icon-picker-name { color: var(--text-dim); font-size: 13px; }
.icon-picker-caret { margin-left: auto; font-size: 18px; color: var(--text-dim); }

/* The grid lives in its own dialog with a single scroll region — nesting it
   inside the form modal produced two scrollbars fighting over the wheel. */
.modal.is-wide { max-width: 720px; }
.modal.is-xl { max-width: 1060px; }

/* The note editor is a workspace, not a form — give it the height too, so the
   writing area isn't squeezed into a strip. */
.modal.is-xl .modal-body { min-height: min(66vh, 620px); }

.icon-modal-search {
  display: flex;
  gap: 8px;
  align-items: center;
  position: sticky;
  top: 0;
  z-index: 2;
  padding: 6px 0 12px;
  background: var(--surface);
}

.icon-modal-grid { padding-bottom: 4px; }

.icon-group-label {
  font-size: 11px;
  font-weight: 640;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-dim);
  margin: 14px 0 8px;
}

.icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(76px, 1fr));
  gap: 6px;
}

.icon-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 10px 4px 8px;
  border: 1px solid transparent;
  border-radius: 9px;
  background: var(--surface-2);
  color: var(--text-dim);
  cursor: pointer;
}

.icon-cell:hover { background: var(--accent-soft); color: var(--accent); }
.icon-cell .micon { font-size: 22px; }

.icon-cell-name {
  font-size: 10px;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: .8;
}

.icon-cell.is-active {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: var(--accent);
  font-weight: 600;
}

/* ---------- Label picker ---------- */

.label-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 10px;
  /* Exactly two rows of chips, then scroll. Sized off the chip height rather
     than a guessed pixel value so a row is never clipped in half. */
  --chip-h: 30px;
  max-height: calc(var(--chip-h) * 2 + 6px + 12px);
  overflow-y: auto;
  padding: 6px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-2);
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.label-chips::-webkit-scrollbar { width: 8px; }
.label-chips::-webkit-scrollbar-track { background: transparent; }

.label-chips::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 999px;
  border: 2px solid var(--surface-2);
}

.label-chips::-webkit-scrollbar-thumb:hover { background: var(--text-dim); }
.label-chip { height: var(--chip-h, 30px); }

.label-search { position: relative; display: flex; align-items: center; margin-bottom: 8px; }
.label-search .input { padding-left: 32px; }

.label-search-icon {
  position: absolute;
  left: 9px;
  font-size: 16px;
  color: var(--text-dim);
  pointer-events: none;
}

.label-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-dim);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}

.label-chip:hover { border-color: var(--accent); color: var(--text); }

.label-chip.is-on {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 550;
}

.label-chip-count { font-size: 11px; opacity: .65; }

.label-add { display: flex; align-items: center; gap: 10px; }
.label-add .input { flex: 1; }
.label-add .hint { white-space: nowrap; }

.label-backfill {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  padding: 9px 12px;
  border-radius: 8px;
  background: var(--warn-soft);
  border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent);
  font-size: 12.5px;
  flex-wrap: wrap;
}

.cat-row.is-dragging::before { display: none; }

/* ---------- Segmented control ---------- */

.segmented {
  display: inline-flex;
  padding: 3px;
  border-radius: 9px;
  background: var(--surface-2);
  border: 1px solid var(--border);
}

.segmented-btn {
  padding: 6px 15px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: 13.5px;
  font-weight: 560;
  cursor: pointer;
  transition: background .14s ease, color .14s ease;
}

.segmented-btn:hover { color: var(--text); }

.segmented-btn.is-active {
  background: var(--surface);
  color: var(--accent);
  font-weight: 640;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .08);
}

.list-hint {
  margin-bottom: 10px;
  color: var(--text-dim);
  font-size: 12px;
}

/* ---------- Split layout ---------- */

.cat-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}

@media (max-width: 1080px) {
  .cat-split { grid-template-columns: minmax(0, 1fr); }
}

.pane { min-width: 0; }

/* The detail pane follows the tree as it scrolls, so selecting a category
   deep in a long list doesn't mean scrolling back up to read it. */
@media (min-width: 1081px) {
  .cat-split > .pane:last-child {
    position: sticky;
    top: 82px;
    max-height: calc(100vh - 100px);
    overflow-y: auto;
    scrollbar-width: thin;
  }
}

.pane-title {
  font-size: 13px;
  font-weight: 660;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-dim);
}

.pane-count {
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 600;
}

.sort-label { font-size: 12px; color: var(--text-dim); }
.sort-arrow { margin-left: 4px; font-size: 11px; opacity: .8; }


/* ---------- Save bar ---------- */

.save-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  margin-bottom: 12px;
  border-radius: 9px;
  background: var(--warn-soft);
  border: 1px solid color-mix(in srgb, var(--warn) 40%, transparent);
  position: sticky;
  top: 66px;
  z-index: 15;
  animation: slide-in .16s ease-out;
}

.save-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--warn);
  flex: 0 0 auto;
  animation: pulse 1.8s ease-in-out infinite;
}

@keyframes pulse { 50% { opacity: .35; } }

.save-text { font-size: 13px; font-weight: 560; color: var(--text); }

/* ---------- Detail pane ---------- */

.detail-card { padding: 0; overflow: hidden; }
.detail-empty { display: flex; align-items: center; justify-content: center; min-height: 260px; }

.detail-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--border);
}

.detail-title {
  font-size: 17px;
  font-weight: 660;
  letter-spacing: -.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.detail-crumb { font-size: 12px; color: var(--text-dim); margin-top: 2px; }

.detail-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--border);
  border-bottom: 1px solid var(--border);
}

.detail-stats > div { background: var(--surface); padding: 14px 20px; }

.detail-stat-value {
  font-size: 19px;
  font-weight: 650;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}

.detail-stat-label {
  font-size: 11px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .05em;
  margin-top: 3px;
}

.rollup-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 20px;
  font-size: 13px;
  color: var(--text-dim);
  cursor: pointer;
  border-bottom: 1px solid var(--border);
}

/* ---------- Transaction list ---------- */

.txn-list { max-height: 460px; overflow-y: auto; }

.txn-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 18px 12px 20px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background .12s ease;
}

.txn-row:last-child { border-bottom: 0; }
.txn-row:hover { background: var(--surface-2); }

/* Amount and date lead: those are what you scan a list of spending for. */
.txn-lead { flex: 0 0 auto; min-width: 96px; }

.txn-amount {
  font-size: 15px;
  font-weight: 660;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  letter-spacing: -.01em;
}

.txn-date { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; }

.txn-body { flex: 1; min-width: 0; }

.txn-top { display: flex; align-items: center; gap: 8px; min-width: 0; }

/* The owning category is a solid outlined pill; labels are soft filled ones.
   Rendering both as identical chips made it impossible to tell them apart. */
.txn-cat {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex: 0 0 auto;
  padding: 2px 8px 2px 6px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text-dim);
  font-size: 11.5px;
  font-weight: 600;
}

.txn-cat .micon { font-size: 13px; }

.txn-note {
  font-size: 13.5px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.txn-note.is-empty { color: var(--text-dim); font-style: italic; opacity: .7; }

.txn-labels { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }

.chip-label {
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 11px;
  padding: 1px 8px;
}

.txn-chevron { color: var(--text-dim); opacity: .4; font-size: 18px; flex: 0 0 auto; }
.txn-row:hover .txn-chevron { opacity: .9; }

/* ---------- Multi-select ---------- */

.txn-check {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  padding: 2px;
  cursor: pointer;
  opacity: .35;
  transition: opacity .12s ease;
}

.txn-check input { cursor: pointer; width: 15px; height: 15px; accent-color: var(--accent); }
.txn-row:hover .txn-check,
.txn-row.is-picked .txn-check { opacity: 1; }

.txn-row.is-picked { background: var(--accent-soft); }
.txn-row.is-picked:hover { background: color-mix(in srgb, var(--accent-soft) 80%, var(--accent)); }

.select-all {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 20px;
  border-bottom: 1px solid var(--border);
  font-size: 12.5px;
  color: var(--text-dim);
  cursor: pointer;
}

.select-all input { accent-color: var(--accent); width: 15px; height: 15px; cursor: pointer; }

.bulk-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  background: var(--accent-soft);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
  animation: slide-in .15s ease-out;
}

.bulk-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-size: 12.5px;
  font-weight: 680;
}

.bulk-text { font-size: 13px; font-weight: 560; color: var(--accent); }

.bulk-preview {
  margin-top: 6px;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}

.bulk-preview-row {
  display: flex;
  gap: 12px;
  padding: 7px 11px;
  font-size: 12.5px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}

.bulk-preview-row:last-child { border-bottom: 0; }
.bulk-preview-amount { font-weight: 620; font-variant-numeric: tabular-nums; min-width: 82px; }

.bulk-preview-note {
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Labels marked for removal in the bulk editor. */
.label-chip.is-removing {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
  text-decoration: line-through;
}

.audit-note {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: 11.5px;
  color: var(--text-dim);
  line-height: 1.7;
}

/* ---------- Orphan recovery ---------- */

.orphan-card {
  margin-bottom: 16px;
  border-color: color-mix(in srgb, var(--warn) 45%, transparent);
  background: color-mix(in srgb, var(--warn-soft) 55%, var(--surface));
}

.orphan-head { display: flex; gap: 12px; margin-bottom: 14px; }

.orphan-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex: 0 0 auto;
  border-radius: 9px;
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 16px;
}

.orphan-title { font-weight: 640; font-size: 14.5px; }
.orphan-sub { font-size: 12.5px; color: var(--text-dim); margin-top: 3px; line-height: 1.5; }

.orphan-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}

.cat-name {
  cursor: text;
  padding: 2px 4px;
  border-radius: 4px;
  transition: background .12s ease;
}

.cat-name:hover { background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--border); }

.cat-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex: 0 0 auto;
  border: 1px solid var(--border);
}

.drag-handle {
  cursor: grab;
  color: var(--text-dim);
  opacity: .45;
  user-select: none;
  touch-action: none;
  padding: 0 2px;
  transition: opacity .12s ease;
}

.cat-row:hover .drag-handle { opacity: 1; }

.cat-row.is-dragging {
  position: relative;
  z-index: 30;
  background: var(--surface);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
  opacity: .96;
  cursor: grabbing;
}

.cat-row.is-dragging .drag-handle { cursor: grabbing; opacity: 1; }

.is-dragging-active .cat-name { pointer-events: none; }
.is-dragging-active .cat-action { opacity: .35; pointer-events: none; }

/* Actions stay quiet until the row is hovered, so the list reads cleanly. */
.cat-action { opacity: 0; transition: opacity .12s ease; }
.cat-row:hover .cat-action,
.cat-row:focus-within .cat-action { opacity: 1; }

@media (hover: none) {
  .cat-action { opacity: 1; }
  .drag-handle { opacity: 1; }
}

.drag-hint {
  position: fixed;
  z-index: 300;
  pointer-events: none;
  padding: 4px 10px;
  border-radius: 6px;
  background: var(--text);
  color: var(--bg);
  font-size: 12px;
  font-weight: 550;
  white-space: nowrap;
  box-shadow: var(--shadow);
}

.drag-hint.is-child { background: var(--accent); color: #fff; }

/* ---------- Modal ---------- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(8, 14, 20, .5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 100;
}

.modal-backdrop {
  animation: fade-in .14s ease-out;
  backdrop-filter: blur(2px);
}

.modal-backdrop.is-closing { animation: fade-out .12s ease-in forwards; }

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes fade-out { to { opacity: 0; } }

.modal {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, .32);
  width: 100%;
  max-width: 540px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  animation: modal-in .18s cubic-bezier(.2, .8, .3, 1);
}

@keyframes modal-in {
  from { opacity: 0; transform: translateY(10px) scale(.985); }
  to { opacity: 1; transform: none; }
}

.modal-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 20px 22px 16px;
  font-size: 17px;
  font-weight: 660;
  letter-spacing: -.01em;
}

.modal-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex: 0 0 auto;
  border-radius: 10px;
  background: var(--surface-2);
  font-size: 17px;
}

.modal-icon.is-danger { background: var(--danger-soft); }

.modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-dim);
  font-size: 14px;
  cursor: pointer;
  line-height: 1;
}

.modal-close:hover { background: var(--surface-2); color: var(--text); }

.modal-body {
  padding: 4px 22px 20px;
  overflow-y: auto;
}

.modal-foot {
  padding: 16px 22px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  background: var(--surface-2);
  border-radius: 0 0 15px 15px;
}

.modal-foot .btn { min-width: 96px; }

/* ---------- Fields ---------- */

.field { margin-bottom: 16px; }

.field label {
  display: block;
  font-size: 12px;
  font-weight: 620;
  text-transform: uppercase;
  letter-spacing: .045em;
  color: var(--text-dim);
  margin-bottom: 6px;
}

.field .req { color: var(--danger); margin-left: 3px; }
.field .hint { font-size: 12px; color: var(--text-dim); margin-top: 5px; }
.field .error { font-size: 12px; color: var(--danger); margin-top: 5px; font-weight: 550; }

.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}

.field-row .field { margin-bottom: 16px; }

.colour-field { display: flex; gap: 8px; align-items: center; }

.colour-swatch {
  width: 42px;
  height: 38px;
  flex: 0 0 auto;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  cursor: pointer;
}

/* ---------- Confirm dialog ---------- */

.confirm-message {
  margin: 0 0 14px;
  font-size: 14.5px;
  line-height: 1.55;
}

.confirm-warnings { display: flex; flex-direction: column; gap: 8px; }

.confirm-warning {
  display: flex;
  gap: 10px;
  padding: 11px 13px;
  border-radius: 9px;
  background: var(--warn-soft);
  color: var(--text);
  font-size: 13px;
  line-height: 1.5;
  border: 1px solid color-mix(in srgb, var(--warn) 28%, transparent);
}

.confirm-warning-icon { flex: 0 0 auto; font-size: 14px; }

.confirm-note {
  margin: 14px 0 0;
  font-size: 12.5px;
  color: var(--text-dim);
  font-style: italic;
}

/* ---------- Banner & toast ---------- */

.banner {
  margin: 16px 24px 0;
  padding: 12px 16px;
  border-radius: 8px;
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 13px;
  border: 1px solid currentColor;
}

.banner.error { background: var(--danger-soft); color: var(--danger); }
.hidden { display: none !important; }

.toast-root {
  position: fixed;
  bottom: 20px;
  right: 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 200;
}

.toast {
  padding: 11px 16px;
  border-radius: 8px;
  background: var(--text);
  color: var(--bg);
  font-size: 14px;
  box-shadow: var(--shadow);
  animation: slide-in .18s ease-out;
  max-width: 380px;
}

.toast.error { background: var(--danger); color: #fff; }

@keyframes slide-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

/* ---------- Setup / signed-out ---------- */

.center-pane {
  max-width: 520px;
  margin: 48px auto;
}

.center-pane h2 { margin: 0 0 8px; font-size: 20px; }
.center-pane p { color: var(--text-dim); margin: 0 0 20px; }

.steps { padding-left: 18px; color: var(--text-dim); font-size: 14px; line-height: 1.8; }
.steps code {
  background: var(--surface-2);
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 13px;
  color: var(--text);
}

.spinner {
  width: 22px;
  height: 22px;
  border: 2.5px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .7s linear infinite;
  margin: 40px auto;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- Responsive ---------- */

.only-mobile { display: none; }

@media (max-width: 820px) {
  .only-mobile { display: inline-flex; }
  .sidebar {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 50;
    transform: translateX(-100%);
    transition: transform .2s ease;
  }
  .sidebar.open { transform: none; }
  .view, .topbar { padding-left: 16px; padding-right: 16px; }
  .banner { margin-left: 16px; margin-right: 16px; }
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #12171d;
    --surface: #1a2129;
    --surface-2: #222b35;
    --border: #2d3844;
    --text: #e6ecf2;
    --text-dim: #90a0b0;
    --accent: #4cc38a;
    --accent-soft: #17372a;
    --danger: #f0705f;
    --danger-soft: #3a1f1c;
    --warn: #e2b04a;
    --warn-soft: #382d16;
    --shadow: 0 1px 3px rgba(0, 0, 0, .4), 0 4px 16px rgba(0, 0, 0, .25);
  }
}


/* ---------- Notes ---------- */

.notes-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
  flex-wrap: wrap;
}

.notes-search {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  max-width: 460px;
}

.notes-search .input { padding-left: 36px; }

.notes-search-icon {
  position: absolute;
  left: 11px;
  font-size: 18px;
  color: var(--text-dim);
  pointer-events: none;
}

.notes-count { font-size: 12.5px; color: var(--text-dim); }

/* Category headers are a distinct band so a wall of cards still reads as
   grouped rather than as one undifferentiated pile. */
.notes-section { margin-bottom: 26px; }

.notes-section-head {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 12px;
  margin-bottom: 12px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  cursor: pointer;
  text-align: left;
}

.notes-section-head:hover { border-color: var(--accent); }

.notes-section-caret {
  font-size: 20px;
  color: var(--text-dim);
  transition: transform .16s ease;
}

.notes-section-head.is-collapsed .notes-section-caret { transform: rotate(-90deg); }

.notes-section-icon { font-size: 18px; color: var(--text-dim); }
.notes-section-icon.is-pinned { color: var(--warn); }

.notes-section-name {
  font-size: 14px;
  font-weight: 680;
  letter-spacing: -.01em;
}

.notes-section-count {
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--border);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-dim);
}

.notes-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 12px;
}

.note-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--note-accent, var(--border));
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  cursor: pointer;
  transition: border-color .12s ease, transform .12s ease, box-shadow .12s ease;
}

.note-card:hover {
  border-color: var(--accent);
  border-left-color: var(--note-accent, var(--accent));
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(16, 32, 48, .10);
}

.note-card-head { display: flex; align-items: center; gap: 8px; }
.note-type-icon { font-size: 17px; color: var(--text-dim); flex: 0 0 auto; }

.note-title {
  flex: 1;
  min-width: 0;
  font-weight: 640;
  font-size: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.note-pin { font-size: 15px; color: var(--warn); flex: 0 0 auto; }

.note-body {
  font-size: 13px;
  color: var(--text-dim);
  line-height: 1.55;
  /* pre-line keeps the paragraph breaks the note was written with, while
     still collapsing the incidental whitespace that markup leaves behind. */
  white-space: pre-line;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 6;
  -webkit-box-orient: vertical;
}

.note-body.is-empty { font-style: italic; opacity: .6; }

.note-progress {
  height: 5px;
  border-radius: 4px;
  background: var(--surface-2);
  overflow: hidden;
}

.note-progress-fill {
  height: 100%;
  border-radius: 4px;
  background: var(--accent);
  transition: width .25s ease;
}

.note-progress-text { font-size: 11px; color: var(--text-dim); }

/* Static checklist preview — see docs on previewBlock for why it isn't live. */
.preview-checks { display: flex; flex-direction: column; gap: 2px; }

.preview-check {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  font-size: 12.5px;
  color: var(--text-dim);
  line-height: 1.45;
}

.preview-check-box { font-size: 15px; flex: 0 0 auto; opacity: .55; margin-top: 1px; }
.preview-check.is-done .preview-check-box { color: var(--accent); opacity: 1; }

.preview-check-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.preview-check.is-done .preview-check-text { text-decoration: line-through; opacity: .6; }

.preview-more {
  font-size: 11.5px;
  color: var(--text-dim);
  opacity: .8;
  padding-left: 21px;
  margin-top: 2px;
  font-style: italic;
}
.note-labels { display: flex; flex-wrap: wrap; gap: 4px; }

/* ---------- Note editor ---------- */

.note-textarea { min-height: 180px; font-size: 14px; line-height: 1.6; }

.checklist-editor {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 300px;
  overflow-y: auto;
  padding: 2px;
}

.checklist-row { display: flex; align-items: center; gap: 8px; }
.checklist-row input[type=checkbox] { accent-color: var(--accent); flex: 0 0 auto; }
.checklist-row.is-done .checklist-text { text-decoration: line-through; opacity: .55; }
.checklist-text { flex: 1; }
.checklist-add { align-self: flex-start; margin-top: 4px; }

.note-pin-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  color: var(--text-dim);
  cursor: pointer;
  margin-top: 4px;
}

.note-pin-toggle input { accent-color: var(--accent); }


/* ---------- Colour picker ---------- */

.colour-picker { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.colour-picker.is-compact { gap: 0; }

.colour-dots { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

.colour-dot {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform .12s ease;
}

.colour-dot:hover { transform: scale(1.12); }

.colour-dot.is-active {
  border-color: var(--text);
  box-shadow: 0 0 0 2px var(--surface) inset;
}

.colour-dot.is-none {
  background: var(--surface-2);
  border: 1px dashed var(--border);
  color: var(--text-dim);
}

.colour-picker .colour-swatch { width: 30px; height: 26px; padding: 2px; }
.colour-picker.is-compact .colour-swatch { width: 32px; height: 32px; }

/* Bigger targets for a page where picking a colour IS the task, not a small
   accent inside a longer form. */
.colour-picker.is-large .colour-dot { width: 36px; height: 36px; }
.colour-picker.is-large .colour-dot .micon { font-size: 19px; }
.colour-picker.is-large .colour-swatch { width: 52px; height: 36px; }

/* ---------- Note blocks ---------- */

.block-list { display: flex; flex-direction: column; gap: 10px; }

.block {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  overflow: hidden;
}

.block-head {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 5px 6px 5px 10px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}

.block-icon { font-size: 16px; color: var(--text-dim); }

.block-kind {
  font-size: 11px;
  font-weight: 640;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-dim);
}

.block-add {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  padding-top: 2px;
}

.checklist-editor, .table-editor { padding: 10px; }

/* ---------- Rich text ---------- */

.rt-toolbar {
  display: flex;
  align-items: center;
  gap: 1px;
  flex-wrap: wrap;
  padding: 5px 8px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  position: sticky;
  top: 0;
  z-index: 2;
}

.rt-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
}

.rt-btn:hover { background: var(--surface-2); color: var(--text); }
.rt-btn.is-active { background: var(--accent-soft); color: var(--accent); }
.rt-btn .micon { font-size: 18px; }

.rt-sep { width: 1px; height: 18px; background: var(--border); margin: 0 4px; }

.rt-surface {
  min-height: 220px;
  height: 260px;
  max-height: 70vh;
  overflow-y: auto;
  padding: 14px 16px;
  font-size: 14.5px;
  line-height: 1.65;
  outline: none;
  /* Drag the bottom-right corner to size the writing area. */
  resize: vertical;
}

.rt-surface:empty::before {
  content: attr(data-placeholder);
  color: var(--text-dim);
  opacity: .7;
}

.rt-surface:focus { box-shadow: inset 0 0 0 2px var(--accent-soft); }

.rt-surface h1, .rt-render h1 { font-size: 21px; margin: .5em 0 .3em; font-weight: 680; }
.rt-surface h2, .rt-render h2 { font-size: 17px; margin: .5em 0 .3em; font-weight: 660; }
.rt-surface h3, .rt-render h3 { font-size: 15px; margin: .5em 0 .3em; font-weight: 640; }
.rt-surface p, .rt-render p { margin: .35em 0; }
.rt-surface ul, .rt-surface ol,
.rt-render ul, .rt-render ol { margin: .4em 0; padding-left: 1.4em; }

.rt-surface blockquote, .rt-render blockquote {
  margin: .5em 0;
  padding-left: 12px;
  border-left: 3px solid var(--border);
  color: var(--text-dim);
}

.rt-surface pre, .rt-render pre {
  background: var(--surface-2);
  padding: 10px 12px;
  border-radius: 8px;
  overflow-x: auto;
  font-size: 13px;
}

.rt-surface code, .rt-render code {
  background: var(--surface-2);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 13px;
}

.rt-surface a, .rt-render a { color: var(--accent); }

/* ---------- Note tables ---------- */

.table-scroll { overflow-x: auto; }

.note-table { width: 100%; border-collapse: collapse; font-size: 13px; }

.note-table th, .note-table td {
  border: 1px solid var(--border);
  padding: 0;
  position: relative;
  min-width: 110px;
}

.note-table th { background: var(--surface-2); }

.table-cell {
  width: 100%;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  padding: 7px 22px 7px 9px;
  outline: none;
}

.table-cell:focus { box-shadow: inset 0 0 0 2px var(--accent-soft); }
.table-head-cell { font-weight: 640; }

.table-del {
  position: absolute;
  top: 50%;
  right: 3px;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  opacity: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

th:hover .table-del, td:hover .table-del, tr:hover .table-row-actions .table-del { opacity: .8; }
.table-del:hover { background: var(--danger-soft); color: var(--danger); opacity: 1; }

.table-add-col, .table-row-actions { border: 0 !important; min-width: 0 !important; width: 34px; }

/* ---------- Note card preview ---------- */

.note-card { background: var(--note-tint, var(--surface)); }
.note-preview { display: flex; flex-direction: column; gap: 7px; }

.note-table-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  max-width: 100%;
  padding: 4px 10px;
  border-radius: 6px;
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: 11.5px;
  font-weight: 550;
}

.note-table-chip-title {
  font-weight: 640;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.note-table-chip-size {
  padding-left: 6px;
  border-left: 1px solid var(--border);
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}

.notes-section-head { border-left: 3px solid var(--section-accent, var(--border)); }

/* ---------- Category manager ---------- */

.cat-manage-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border);
}

.cat-manage-row .input { flex: 1; }

.cat-manage-add {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}

.cat-manage-add .input { flex: 1; }


/* ---------- Switch ---------- */

.switch-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  margin-top: 6px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  cursor: pointer;
  transition: border-color .14s ease, background .14s ease;
}

.switch-row:hover { border-color: var(--accent); }

.switch-row.is-on {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.switch-icon { font-size: 19px; color: var(--text-dim); flex: 0 0 auto; }
.switch-row.is-on .switch-icon { color: var(--accent); }

.switch-text { flex: 1; min-width: 0; }
.switch-title { font-size: 13.5px; font-weight: 600; }
.switch-sub { font-size: 11.5px; color: var(--text-dim); margin-top: 1px; }

.switch { position: relative; flex: 0 0 auto; display: inline-flex; }
.switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }

.switch-track {
  width: 40px;
  height: 23px;
  border-radius: 999px;
  background: var(--border);
  display: inline-flex;
  align-items: center;
  padding: 2px;
  transition: background .16s ease;
}

.switch-thumb {
  width: 19px;
  height: 19px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
  transition: transform .16s cubic-bezier(.3, .8, .4, 1);
}

.switch input:checked + .switch-track { background: var(--accent); }
.switch input:checked + .switch-track .switch-thumb { transform: translateX(17px); }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- Inline add (create a lookup without leaving the form) ---------- */

.select-with-add { display: flex; gap: 6px; align-items: center; }
.select-with-add .select { flex: 1; }

.inline-add {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-top: 6px;
}

.inline-add .input { flex: 1; }


/* ---------- Note viewer ---------- */

.view-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 14px;
}

.view-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 550;
}

.view-chip.is-pinned { background: var(--warn-soft); color: var(--warn); }

.view-body {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-left: 14px;
  border-left: 3px solid var(--note-accent, var(--border));
  font-size: 14.5px;
  line-height: 1.65;
}

.view-checklist { display: flex; flex-direction: column; gap: 6px; }

.view-check {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 14px;
  cursor: pointer;
  padding: 2px 0;
}

.view-check input {
  margin-top: 3px;
  accent-color: var(--accent);
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  cursor: pointer;
}

.view-check.is-done > span { text-decoration: line-through; opacity: .5; }

.note-table.is-view th, .note-table.is-view td { padding: 7px 10px; }
.note-table.is-view th { font-weight: 640; text-align: left; }

.view-labels {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 16px;
}


/* ---------- Table titles ---------- */

.table-title {
  margin-bottom: 8px;
  font-weight: 620;
  border-style: dashed;
}

.table-title:focus { border-style: solid; }

.block-title {
  font-size: 12px;
  font-weight: 620;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 45%;
}

.view-table-title {
  font-size: 13.5px;
  font-weight: 660;
  margin-bottom: 6px;
  color: var(--text);
}


/* ---------- Secure notes ---------- */

.note-secure { font-size: 15px; color: var(--accent); flex: 0 0 auto; }

.note-card.is-locked { border-style: dashed; }
.note-card.is-locked .note-title { color: var(--text-dim); }

.locked-body {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 16px 12px;
  border-radius: 8px;
  background: var(--surface-2);
  color: var(--text-dim);
}

.locked-icon { font-size: 22px; opacity: .55; }
.locked-text { font-size: 12.5px; font-style: italic; }

.view-chip.is-secure { background: var(--accent-soft); color: var(--accent); }

.btn.is-locked { color: var(--accent); border-color: var(--accent); }
.btn.is-locked:hover { background: var(--accent-soft); }


/* ---------- Vault settings ---------- */

.vault-status {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-2);
  margin-bottom: 14px;
}

.vault-actions { display: flex; flex-direction: column; gap: 8px; }
.vault-actions .btn { justify-content: flex-start; gap: 9px; }


/* ---------- Note author ---------- */

.note-author {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 11px;
  color: var(--text-dim);
}

.note-author-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .02em;
  flex: 0 0 auto;
}

.note-author-name {
  font-weight: 550;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.note-author-when { margin-left: auto; flex: 0 0 auto; opacity: .85; }

/* ---------- inventory ---------- */

/* A checkbox and its text as one click target, sharing a baseline. */
.check-row {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: 14px;
}
.check-row input { width: 16px; height: 16px; accent-color: var(--accent); }
.muted-check { font-size: 13px; color: var(--text-dim); }

.stock-group {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  margin-bottom: 14px;
  overflow: hidden;
}

.stock-group-head {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 11px 14px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.stock-group-head h3 { margin: 0; font-size: 14px; font-weight: 700; }
.stock-group-head .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex: 0 0 auto;
}
.stock-group-head .count {
  font-size: 12px;
  color: var(--text-dim);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 1px 8px;
}
.stock-group-head .pill-low { margin-left: auto; }

.stock-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
}
.stock-row:last-child { border-bottom: 0; }
.stock-row.is-deleted { opacity: .5; }

.stock-main { flex: 1; min-width: 0; }

.stock-title {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 7px;
}
.stock-title .name { font-size: 14px; font-weight: 600; }
.stock-title .brand { font-size: 12.5px; color: var(--text-dim); font-weight: 600; }
.stock-title .variant { font-size: 12px; color: var(--text-dim); }

.stock-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 4px;
}
.stock-meta:empty { margin-top: 0; }

.pill {
  font-size: 11px;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-dim);
  border: 1px solid var(--border);
  white-space: nowrap;
}
.pill-group { background: var(--surface-2); color: var(--text); }
.pill-refill { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.pill-winding { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.pill-low { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
.pill-ok { background: var(--accent-soft); color: var(--accent); border-color: transparent; }

/* The stepper. Fixed width on the count so the +/- buttons don't shuffle
   sideways every time a number gains a digit. */
.stock-count {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: 0 0 auto;
}
.stock-count .step {
  width: 30px;
  padding: 0;
  font-size: 17px;
  line-height: 1;
}
.stock-count .qty {
  min-width: 66px;
  text-align: center;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  padding: 0 4px;
}
.qty-low, .qty-out { color: var(--danger); font-weight: 700; }
.qty-winding { color: var(--text-dim); }

.stock-actions { display: flex; gap: 4px; flex: 0 0 auto; }

@media (max-width: 620px) {
  .stock-row { flex-wrap: wrap; }
  .stock-main { flex: 1 0 100%; }
  .stock-actions { margin-left: auto; }
}

/* ---------- toggle switch (bool fields) ---------- */

/* A row you click anywhere on, rather than a 16px tickbox with a label beside
   it. These read as settings, and they were the ugliest thing in the form. */
.toggle-row {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 11px 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  transition: border-color .15s, background .15s;
}
.toggle-row:hover { border-color: var(--text-dim); }
.toggle-row.is-on { border-color: var(--accent); background: var(--accent-soft); }

.toggle-text { flex: 1; min-width: 0; }
.toggle-label { display: block; font-size: 13.5px; font-weight: 600; }
.toggle-hint {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-dim);
}
.toggle-row.is-on .toggle-hint { color: var(--text-dim); }

.switch {
  flex: 0 0 auto;
  position: relative;
  width: 40px;
  height: 23px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  transition: background .15s, border-color .15s;
}
.switch::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: var(--text-dim);
  transition: transform .15s, background .15s;
}
.toggle-row.is-on .switch { background: var(--accent); border-color: var(--accent); }
.toggle-row.is-on .switch::after { transform: translateX(17px); background: #fff; }

/* The bool field supplies its own label and hint inside the switch row, so the
   generic ones the form wraps every field in would just repeat them. */
.field:has(> .toggle-row) > label,
.field:has(> .toggle-row) > .hint { display: none; }

/* ---------- category picker + inventory category tree ---------- */

.taxonomy-select .hint { margin-top: 5px; }

.cat-icon { font-size: 20px; flex: 0 0 auto; color: var(--text-dim); }

/* Subcategory headings sit inside the parent's card, indented and quieter than
   the parent's own heading. */
.stock-group-head.depth-1 {
  padding-left: 30px;
  border-top: 1px solid var(--border);
}

/* A colour stripe so the category reads at a glance while scrolling a long
   list, without tinting the whole heading so hard the text stops being
   readable in either theme. */
.stock-group-head[style*="--cat-colour"] {
  box-shadow: inset 3px 0 0 var(--cat-colour);
}
.stock-group-head.depth-1 h4 {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
}
.stock-group-head.depth-1 .cat-icon { font-size: 17px; }

.stock-empty-sub {
  padding: 9px 14px 11px 30px;
  font-size: 12px;
  color: var(--text-dim);
}

/* ---------- stock category detail pane ---------- */

/* The card's head and stats blocks bring their own padding; the form fields
   inside it don't, so they'd otherwise sit flush against the edge. */
.cat-detail-body { padding: 16px 20px 4px; }
.cat-detail-body .field { margin-bottom: 14px; }

.detail-note {
  margin: 0 20px 16px;
  padding: 9px 12px;
  border-radius: var(--radius);
  font-size: 12.5px;
  line-height: 1.45;
}
.detail-note.is-ok { background: var(--accent-soft); color: var(--accent); }
.detail-note.is-low { background: var(--danger-soft); color: var(--danger); }

.detail-items {
  padding: 14px 20px;
  border-top: 1px solid var(--border);
}
.detail-items .pane-title { margin-bottom: 8px; }
.detail-items .hint { margin: 0; }

/* A card of its own, not a section tacked onto the edit card — editing a
   label and seeing where it's used are different jobs. */
.tax-usage-card { margin-top: 14px; }

.usage-group + .usage-group { margin-top: 16px; }

.usage-group-label {
  font-size: 13px;
  font-weight: 660;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: 8px;
}

/* Rows reuse .txn-row from the Categories transaction list — amount/title
   and date lead, boxed as one bordered group per source rather than a bare
   list, and not clickable here so the pointer cursor is turned back off. */
.txn-list.is-boxed {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  /* Scrolls rather than truncating: every match stays reachable, and a label
     used on 40 things doesn't push the rest of the pane off-screen. */
  max-height: 264px;
  overflow-y: auto;
  scrollbar-width: thin;
}
.txn-row.is-static { cursor: default; }
.txn-row.is-static:hover { background: none; }

.detail-actions {
  display: flex;
  justify-content: flex-end;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
}

/* ---------- inventory tree ---------- */

/* Three kinds of row share one list, so each has to read as its own kind
   before you've read a word of it. Indentation alone stopped working halfway
   down a long list — by then you've lost track of what level you're on. */

/* A category heading sticks to the top while you scroll its contents, so the
   answer to "what am I looking at" is always on screen. Subcategories stick
   just below the parent's height. */
.inv-tree .cat-row.is-cat {
  position: sticky;
  z-index: 2;
}
.inv-tree .cat-row.is-cat.depth-0 { top: 0; }
.inv-tree .cat-row.is-cat.depth-1 { top: 42px; z-index: 1; }

/* Dragging must not leave a row pinned mid-gesture. */
.inv-tree.is-dragging-active .cat-row.is-cat { position: relative; top: auto; }

/* Items: no fill of their own, a thin edge in the parent's colour, and a
   background one step back from the surface so a run of them reads as a block
   sitting inside the category above rather than as more headings. */
.cat-row.stock-item {
  background: var(--surface);
  border-left: 3px solid var(--item-accent, var(--border));
  box-shadow: inset 0 -1px 0 var(--border);
  font-size: 13px;
  min-height: 38px;
  border-radius: 0;
  margin-top: 0;
}
.cat-row.stock-item:hover { background: var(--surface-2); }

/* Rounds off the last item of a run, so each category's block has an end. */
.cat-row.stock-item:last-child,
.cat-row.stock-item:has(+ .cat-row.is-cat) {
  border-bottom-left-radius: var(--radius);
  border-bottom-right-radius: var(--radius);
  box-shadow: none;
  margin-bottom: 10px;
}

.cat-row.stock-item .item-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex: 0 0 auto;
  background: var(--item-accent, var(--border));
  opacity: .8;
}

.item-name {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  min-width: 0;
}
.item-label { font-weight: 500; }
.item-name .variant { font-size: 11.5px; color: var(--text-dim); }

/* Brand as a gold badge: it's the thing you scan for when two rows are
   otherwise the same item, so it gets a colour nothing else in the row uses. */
.brand-badge {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .01em;
  padding: 1px 8px;
  border-radius: 999px;
  white-space: nowrap;
  background: color-mix(in srgb, #b8860b 16%, transparent);
  color: #8a6508;
  border: 1px solid color-mix(in srgb, #b8860b 34%, transparent);
}
:root[data-theme="dark"] .brand-badge { background: color-mix(in srgb, #e8b93a 15%, transparent); color: #e8b93a; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-badge {
    background: color-mix(in srgb, #e8b93a 15%, transparent);
    color: #e8b93a;
  }
}

/* The collapse twisty. */
.twisty {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: 11px;
  line-height: 1;
  border-radius: 5px;
  opacity: .7;
  transition: transform .15s ease, opacity .15s ease;
}
.twisty:hover { opacity: 1; background: color-mix(in srgb, currentColor 14%, transparent); }
.twisty.is-collapsed { transform: rotate(-90deg); }

.chip-muted { background: var(--surface-2); color: var(--text-dim); }

/* The selected row has to stand out against three different backgrounds. */
.cat-row.is-selected { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Two fields side by side — stock and its unit belong together. */
.field-row { display: grid; grid-template-columns: 1fr 110px; gap: 10px; }
.field-row .field { margin-bottom: 14px; }

.cat-detail-body .toggle-row { margin-bottom: 10px; }

/* ---------- Taxonomy (labels / note categories / record types) ---------- */

/* A grouped segmented control, not floating pills — this switches which bank
   a whole settings page is editing, a different job from the toggleable
   .label-chip pills used to pick labels onto a transaction or note, so it
   deliberately doesn't borrow that look. */
.tax-tabs {
  display: flex;
  padding: 3px;
  border-radius: 9px;
  background: var(--surface-2);
  gap: 2px;
}

.tax-tab {
  padding: 6px 12px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: 13px;
  font-weight: 560;
  cursor: pointer;
  white-space: nowrap;
}

.tax-tab:hover { color: var(--text); }

.tax-tab.is-active {
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
}

/* Plain label text in the list row — unlike .cat-name this isn't an inline
   rename target (renaming happens in the detail pane), so it skips that
   class's text-cursor/hover affordance. */
.tax-row-name { font-weight: 610; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* Rows take the soft subcategory tint (rowTint depth 1) rather than a
   full-strength fill, plus a solid bar of the actual chosen colour so the
   pick still reads at a glance against the wash. The tree's own nested rows
   draw their rail outside the row via ::before at a negative offset, which
   depends on an indent these flat rows don't have — hence a border here. */
.cat-row.tax-row {
  border-left: 3px solid var(--row-accent, var(--border));
  margin-top: 4px;
}
.cat-row.tax-row:first-child { margin-top: 0; }

/* Beats the plain .cat-row:hover grey, which would wash the tint out entirely
   on the one interaction where you most want to see which row you're on. */
.cat-row.tax-row:hover {
  background: color-mix(in srgb, var(--row-accent) 28%, var(--surface));
}

.save-bar .spacer { flex: 1; }

/* ---------- Label scope ---------- */

.label-search .label-scope-toggle { flex: 0 0 auto; white-space: nowrap; }
.label-search .label-scope-toggle.is-on {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: transparent;
}

.scope-list {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden auto;
  max-height: 40vh;
}

/* Indented to mirror the category tree — ticking a parent covers its
   children, so the nesting is the explanation. */
.scope-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px 8px calc(12px + var(--indent, 0px));
  border-bottom: 1px solid var(--border);
  font-size: 13.5px;
  cursor: pointer;
}
.scope-row:last-child { border-bottom: 0; }
.scope-row:hover { background: var(--surface-2); }
.scope-name { flex: 1; min-width: 0; }

/* A row ticked because an ancestor is ticked: it reads as on, but it isn't
   the thing that's stored, so it's locked and says where it came from. */
.scope-row.is-covered { cursor: default; color: var(--text-dim); }
.scope-row.is-covered:hover { background: none; }

.scope-via {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--text-dim);
  opacity: .8;
  font-style: italic;
}

/* The native tickbox is 13px, differently shaped on every platform, and does
   not take the accent colour. Drawn here instead so it matches the buttons
   and switches the rest of the app uses. */
.scope-row input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  width: 19px;
  height: 19px;
  margin: 0;
  border: 1.5px solid var(--border);
  border-radius: 5px;
  background: var(--surface);
  cursor: pointer;
  display: grid;
  place-content: center;
  transition: background .12s ease, border-color .12s ease;
}

.scope-row input[type="checkbox"]:hover { border-color: var(--accent); }

.scope-row input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent);
}

/* The tick itself: two borders of an empty box, rotated into a checkmark. */
.scope-row input[type="checkbox"]:checked::after {
  content: '';
  width: 10px;
  height: 5.5px;
  border-left: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(-45deg) translate(1px, -1.5px);
}

.scope-row input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.scope-row input[type="checkbox"]:disabled { cursor: default; opacity: .5; }

/* ---------------------------------------------------------------- Food ---
   Ingredients (a cattree.js tree, so .cat-row and friends do most of the
   work) and Recipes. Only the genuinely new shapes live here. */

.icon-btn {
  background: none;
  border: 0;
  border-radius: 6px;
  padding: 3px 6px;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
}

.icon-btn:hover { background: var(--border); color: var(--text); }
.icon-btn:disabled { opacity: .35; cursor: default; }
.icon-btn:disabled:hover { background: none; }

/* The per-category "tick everything here" box. Sized up from the row's own
   checkboxes because it acts on all of them. */
.tick-all { width: 15px; height: 15px; cursor: pointer; }
.tick-all:disabled { opacity: .3; cursor: default; }

.chip-row { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 14px; align-items: center; }
.chip-row.is-static { margin-bottom: 6px; }
.chip-filter { cursor: pointer; }
.chip.is-static { cursor: default; }
.chip-filter.is-on {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  font-weight: 620;
}

.food-chip { border-style: solid; border-width: 1px; }

/* Picker plus its inline "add a new one" button. */
.food-picker { display: flex; gap: 6px; align-items: center; }
.food-picker .select { flex: 1; min-width: 0; }
.food-picker-add { font-size: 16px; padding: 4px 8px; }

.food-inline {
  display: flex;
  align-items: center;
  gap: 8px;
  text-transform: none !important;
  letter-spacing: 0 !important;
  font-size: 14px !important;
  white-space: nowrap;
}

/* Golden, because a favourite star that is merely the text colour reads as
   decoration rather than state. */
.star.is-on, .star-btn.is-on { color: #f0b429; }
.star-btn.is-on { border-color: color-mix(in srgb, #f0b429 45%, transparent); }

.match-list { display: flex; flex-direction: column; }

.match-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 14px;
  background: none;
  border: 0;
  border-top: 1px solid var(--border);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.match-row:hover { background: var(--accent-soft); }
.match-main { flex: 1; min-width: 0; }
.match-title { font-weight: 600; }
.match-ok { color: var(--accent); }
.match-score { text-align: right; white-space: nowrap; }

.recipe-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
}

.recipe-card {
  display: block;
  padding: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.recipe-card:hover { border-color: var(--accent); }
.recipe-card-title { font-weight: 620; margin-bottom: 6px; }
.recipe-card-chips { margin-bottom: 4px; }

.detail-lines { display: flex; flex-direction: column; }

.detail-line {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 6px 2px;
  border-bottom: 1px solid var(--border);
}

.detail-tick { color: var(--text-dim); }
.detail-line.is-have .detail-tick { color: var(--accent); }
.detail-name { flex: 1; }
.detail-measure { color: var(--text-dim); white-space: nowrap; }

.detail-steps { padding-left: 20px; }
.detail-steps li { margin-bottom: 10px; line-height: 1.55; }

.edit-head {
  margin: 20px 0 8px;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-dim);
}

.edit-line {
  display: grid;
  grid-template-columns: minmax(90px, 1.2fr) 68px 96px minmax(90px, 1.4fr) auto auto;
  gap: 6px;
  align-items: center;
  margin-bottom: 6px;
}

.edit-line-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 550; }
.edit-opt { display: flex; align-items: center; gap: 4px; font-size: 12px; color: var(--text-dim); }

.edit-add { display: flex; gap: 8px; margin-top: 8px; }
.edit-add .select { flex: 1; }

.edit-step {
  display: grid;
  grid-template-columns: auto 1fr auto auto auto;
  gap: 6px;
  align-items: start;
  margin-bottom: 6px;
}

.edit-step-n { padding-top: 9px; color: var(--text-dim); font-size: 12px; }

.is-slim { padding: 5px 7px; font-size: 13px; }

.merge-list { display: flex; flex-direction: column; max-height: 320px; overflow-y: auto; margin-top: 10px; }

.merge-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  background: none;
  border: 0;
  border-top: 1px solid var(--border);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.merge-row:hover { background: var(--accent-soft); }

@media (max-width: 640px) {
  .edit-line { grid-template-columns: 1fr 1fr; }
  .edit-line-name { grid-column: 1 / -1; }
}

/* Cuisine kicker: one-of-a-kind, so it reads as a label above the title
   rather than as one more chip in a row of many. */
.cuisine-eyebrow {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 3px;
}

.cuisine-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }

.tag-picker { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }
.tag-picker .chip { user-select: none; }

/* The Manage shortcut sits inside a field's label, which is uppercase and
   letter-spaced; neither suits a button. */
.field label .btn-sm {
  margin-left: 8px;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 600;
  padding: 1px 8px;
}

optgroup { font-weight: 700; font-style: normal; }
optgroup option { font-weight: 400; padding-left: 12px; }

/* Two short numeric fields side by side. Deliberately not .field-row: an
   unscoped rule further up narrows that to '1fr 110px' for the Inventory
   detail pane, which is wrong for a pair of equal-weight numbers. */
.food-row { display: grid; grid-template-columns: 160px 160px; gap: 14px; }

/* ------------------------------------------------- Recipe detail (rd-) ---
   A recipe laid out to be cooked from: hero, then what you need and how it
   goes, side by side. No new palette — the photo and the cuisine's own hue
   carry the colour, everything else comes from the console's tokens. */

.rd-hero {
  position: relative;
  margin: -4px -4px 16px;
  border-radius: 14px;
  overflow: hidden;
  min-height: 190px;
  display: flex;
  align-items: flex-end;
  background: var(--cuisine, var(--text-dim));
}

/* No photo is a colour field in the cuisine's hue, not a grey box — an
   untouched recipe still gets an identity. */
.rd-hero.is-plain {
  min-height: 128px;
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--cuisine) 88%, #000) 0%,
      color-mix(in srgb, var(--cuisine) 55%, #000) 100%);
}

.rd-hero.is-plain .rd-hero-img { display: none; }

.rd-hero-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.rd-hero-text {
  position: relative;
  width: 100%;
  padding: 46px 22px 18px;
  /* Scrim rather than a flat overlay: the top of a food photo is usually the
     part worth seeing. */
  background: linear-gradient(to top, rgba(0, 0, 0, .82) 0%, rgba(0, 0, 0, .45) 45%, transparent 100%);
  color: #fff;
}

.rd-hero-eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  opacity: .85;
  margin-bottom: 4px;
}

.rd-hero-title {
  margin: 0 0 8px;
  font-size: 30px;
  line-height: 1.1;
  font-weight: 700;
  letter-spacing: -.02em;
  text-wrap: balance;
}

.rd-hero-meta { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

.rd-tag, .rd-fact {
  font-size: 11.5px;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .34);
  backdrop-filter: blur(2px);
}

.rd-tag { background: rgba(255, 255, 255, .17); font-weight: 600; }
.rd-fact { background: transparent; opacity: .85; }

.rd-intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 32px;
  align-items: start;
  margin-bottom: 22px;
}

/* Label over value, in a quiet column. Not badges: these are looked up, not
   scanned, and badges over the photo competed with the title. */
.rd-facts {
  display: grid;
  grid-template-columns: auto auto;
  gap: 4px 14px;
  margin: 0;
  padding-left: 22px;
  border-left: 1px solid var(--border);
  white-space: nowrap;
}

.rd-facts dt {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-dim);
  align-self: center;
}

.rd-facts dd {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.rd-lede {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.62;
  color: var(--text-dim);
  max-width: 66ch;
}

.rd-split { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 28px; }
.rd-col { min-width: 0; }

.rd-head {
  margin: 0 0 12px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* ---- what you need ---- */

.rd-lines { list-style: none; margin: 0; padding: 0; }

.rd-line {
  display: grid;
  grid-template-columns: 14px 1fr auto;
  gap: 9px;
  align-items: baseline;
  padding: 7px 0;
  border-bottom: 1px solid var(--border);
}

.rd-line-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1.5px solid var(--text-dim);
  align-self: center;
  opacity: .5;
}

.rd-line.is-have .rd-line-dot {
  background: var(--accent);
  border-color: var(--accent);
  opacity: 1;
}

.rd-line-name { line-height: 1.4; }
.rd-line.is-have .rd-line-name { font-weight: 600; }
.rd-line-note, .rd-line-opt { color: var(--text-dim); font-size: 12.5px; }
.rd-line-opt { font-style: italic; }

.rd-line-measure {
  color: var(--text-dim);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.rd-shortfall, .rd-ready { margin: 14px 0 0; font-size: 13.5px; line-height: 1.5; }
.rd-shortfall { color: var(--warn); }
.rd-ready { color: var(--accent); font-weight: 600; }

/* ---- how it goes ---- */

/* Plain numbered prose. The filled, bordered cards read as five separate
   alerts rather than one method — the steps are something to read straight
   through, so they get typography and space, not chrome. */
.rd-rail { list-style: none; margin: 0; padding: 0; }

.rd-step {
  display: grid;
  grid-template-columns: 26px 1fr;
  gap: 14px;
  align-items: start;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}

.rd-step:last-child { border-bottom: 0; padding-bottom: 0; }
.rd-step:first-child { padding-top: 0; }

.rd-step-mark {
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
  line-height: 1.65;
  text-align: right;
}

.rd-step-text { min-width: 0; line-height: 1.65; }

.rd-source { margin: 22px 0 0; font-size: 12px; color: var(--text-dim); word-break: break-all; }

@media (max-width: 860px) {
  .rd-split { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .rd-hero-title { font-size: 24px; }
}

@media (prefers-reduced-motion: reduce) {
  
}

/* ---- typed marks (textmarks.js) ---- */

.tm > :first-child { margin-top: 0; }
.tm > :last-child { margin-bottom: 0; }
.tm-p { margin: 0 0 8px; }
.tm-h { margin: 10px 0 5px; font-size: 13.5px; font-weight: 700; letter-spacing: .01em; }
.tm ul { margin: 6px 0 8px; padding-left: 20px; }
.tm li { margin-bottom: 3px; }

.tm-q {
  margin: 8px 0;
  padding: 2px 0 2px 11px;
  border-left: 3px solid color-mix(in srgb, var(--accent) 45%, transparent);
  color: var(--text-dim);
}

.tm code {
  font-family: ui-monospace, 'Cascadia Code', 'SF Mono', Menlo, monospace;
  font-size: .9em;
  padding: 1px 5px;
  border-radius: 5px;
  background: color-mix(in srgb, var(--text) 9%, transparent);
}

/* The legend under the step editor: the syntax has to be visible somewhere,
   and a plain textarea gives no hint that it exists. */
.tm-legend { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; margin-bottom: 8px; }
.tm-legend code {
  font-family: ui-monospace, 'Cascadia Code', 'SF Mono', Menlo, monospace;
  font-size: 11.5px;
  padding: 1px 5px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--text) 8%, transparent);
}

/* Recipe card footer: how close you are, then how long it takes. The stock
   line is the useful half in an app built around "what can I cook tonight",
   so it leads and the timing follows. */
.recipe-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 10px;
  padding-top: 9px;
  border-top: 1px solid var(--border);
  font-size: 12.5px;
}

.rc-stock { display: inline-flex; align-items: center; gap: 6px; color: var(--text-dim); }
.rc-stock-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--border);
  flex: 0 0 auto;
}
.rc-stock.is-ready { color: var(--accent); font-weight: 620; }
.rc-stock.is-ready .rc-stock-dot { background: var(--accent); }

.rc-time { color: var(--text-dim); white-space: nowrap; display: inline-flex; align-items: center; gap: 7px; }
.rc-sep { width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: .5; }

/* !highlight! — the mark people reach for when a step carries a warning.
   Solid, and with its ink pinned dark in both themes: a highlighter is always
   a light wash, so inheriting the theme's text colour put near-white type on
   pale cyan the moment dark mode was on. */
.tm mark {
  background: #a7e8e4;
  color: #10171e;
  padding: 0 3px;
  border-radius: 3px;
}

@media (max-width: 720px) {
  .rd-intro { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .rd-facts { padding-left: 0; border-left: 0; grid-template-columns: repeat(4, auto); justify-content: start; }
}

/* ---- matches pane ---- */

.mp { padding: 0; }

.mp-head { padding: 16px 18px 12px; }
.mp-title { font-size: 16px; font-weight: 680; }
.mp-sub { font-size: 13px; color: var(--text-dim); margin-top: 2px; }

.mp-picked { padding: 0 18px 14px; }

.mp-label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 8px;
}

.mp-label .btn-sm {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 600;
  padding: 1px 8px;
}

.mp-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.mp-chip { cursor: pointer; }
.mp-chip:hover { text-decoration: line-through; opacity: .7; }

.mp-allow {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 18px 14px;
  border-bottom: 1px solid var(--border);
}

.mp-allow .mp-label { margin-bottom: 0; }

/* Segmented buttons rather than a <select>: .select is width:100% here, so a
   dropdown in this row swallowed the header. */
.seg { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }

.seg-btn {
  padding: 4px 11px;
  background: var(--surface);
  border: 0;
  border-right: 1px solid var(--border);
  color: var(--text-dim);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}

.seg-btn:last-child { border-right: 0; }
.seg-btn:hover { background: var(--accent-soft); color: var(--text); }
.seg-btn.is-on { background: var(--accent); color: #fff; }

.mp-empty { padding: 18px; }
.mp .match-row:first-of-type { border-top: 0; }

/* The ingredients toolbar follows the list down: ticking something near the
   bottom used to mean scrolling back to the top to act on it. 67.5px is the
   topbar, which is itself sticky. */
.toolbar.is-sticky {
  position: sticky;
  top: 67.5px;
  z-index: 10;
  background: var(--bg);
  padding: 10px 0;
  margin-bottom: 8px;
  /* Bleeds to the gutter edges so rows don't slide out from under it. */
  box-shadow: 0 0 0 12px var(--bg), 0 10px 12px -10px rgba(0, 0, 0, .25);
}

.surprise-btn { white-space: nowrap; }

/* Above the modal (100) so a burst thrown as a recipe opens lands in front
   of it, and never intercepts a click. */
.confetti-canvas {
  position: fixed;
  inset: 0;
  z-index: 500;
  pointer-events: none;
}
