/* ---------------------------------------------------------------
   LEDGER theme — an editorial/statement take rather than a dashboard.
   Newsreader (serif) carries money and headings; IBM Plex Sans carries
   the interface; figures are tabular so columns line up.
   --------------------------------------------------------------- */
:root {
  color-scheme: dark;
  --bg: #0a0f1c;
  --panel: #121829;
  --panel-2: #1a2138;
  --text: #eef1f7;
  --muted: #8e9ab3;
  --line: #232c44;
  --button: #e8a33d;
  --button-text: #14100a;
  --danger: #e8735f;
  --shadow: 0 18px 60px rgba(2, 8, 20, 0.45);
  /* Calibri is only installed on Windows/Office machines, so it is listed
     first for them and Carlito — metric-compatible, loaded as a webfont in
     index.html — renders identically everywhere else. */
  --font-display: Calibri, Carlito, Candara, "Segoe UI", system-ui, sans-serif;
  font-family: Calibri, Carlito, Candara, "Segoe UI", system-ui, sans-serif;
}

:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f7f4ee;
  --panel: #ffffff;
  --panel-2: #f1ece3;
  --text: #171a21;
  --muted: #6e6a63;
  --line: #e4ded2;
  --button: #c2701c;
  --button-text: #ffffff;
  --danger: #b4442f;
  --shadow: 0 18px 50px rgba(60, 50, 35, 0.1);
}

* {
  box-sizing: border-box;
}

html {
  background: var(--bg);
}

body {
  min-width: 320px;
  margin: 0;
  background: var(--bg);
  color: var(--text);
}

button,
input {
  font: inherit;
}

input[type="checkbox"] {
  width: 16px;
  min-height: 16px;
  accent-color: var(--button);
}

button {
  min-height: 34px;
  border: 0;
  border-radius: 12px;
  background: var(--button);
  color: var(--button-text);
  cursor: pointer;
  font-weight: 600;
}

button:active {
  transform: translateY(1px);
}

input {
  width: 100%;
  min-height: 38px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  color: var(--text);
  padding: 8px 10px;
  outline: none;
  /* Inputs live inside <label>, which sets font-size: 0.78rem (~12.5px).
     Any focused text input under 16px makes iOS Safari/Chrome auto-zoom
     the whole page in, and it never zooms back out on its own. Forcing
     16px here (overriding the inherited label size) stops that. */
  font-size: 16px;
}

input:focus {
  border-color: var(--text);
}

label {
  display: grid;
  gap: 6px;
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 700;
}

/* PHONE LAYOUT is the default (mobile-first); the desktop rules at the
   bottom of this file layer on top at wider screens. */
.app-shell {
  width: min(760px, 100%);
  max-width: 100%;
  min-height: 100vh;
  margin: 0 auto;
  padding: 18px 14px 30px;
}

/* NOTE: do NOT add `overflow-x: hidden` here as a catch-all. It was tested
   and it breaks `position: sticky` on .sticky-head (the header scrolls away
   instead of pinning), which is the bug the sticky-head wrapper exists to
   fix. The grid `minmax(0, 1fr)` rules are the correct fix; keep it there. */
html,
body {
  max-width: 100%;
}

.auth-panel {
  display: grid;
  gap: 18px;
  max-width: 430px;
  margin: 12vh auto 0;
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--panel);
  box-shadow: var(--shadow);
}

.app-logo {
  width: 58px;
  height: 58px;
  margin: 0 0 10px;
  border-radius: 14px;
  box-shadow: var(--shadow);
}

.eyebrow {
  margin: 0 0 4px;
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0;
  text-transform: uppercase;
}

h1,
h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.015em;
}

h1 {
  font-size: clamp(1.7rem, 9vw, 2.5rem);
  line-height: 1.05;
}

h2 {
  font-size: 1.06rem;
}

.stack {
  display: grid;
  gap: 12px;
}

.button-row,
.actions,
.month-line,
.panel-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.button-row button {
  flex: 1;
}

.ghost {
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text);
}

.danger {
  color: var(--danger);
}

.small {
  min-height: 30px;
  padding: 0 10px;
  font-size: 0.75rem;
}

.icon-button {
  display: grid;
  width: 34px;
  min-width: 34px;
  padding: 0;
  place-items: center;
  font-size: 1.25rem;
}

.hidden {
  display: none !important;
}

/* ---------------------------------------------------------------
   THE LAYOUT FIX (measured, not guessed)

   .budget-view is a grid. A grid's default `auto` track takes its
   MINIMUM from the content's min-content width — grid items refuse to
   shrink below it. `.tabs` has 7 non-shrinking buttons whose min-content
   is 553px, so the track was forced to 553px and dragged the entire page
   with it: on a 375px phone the document rendered 553px wide, which is
   why the whole thing had to be pinched out to be readable.

   It also meant `.tabs` never actually scrolled — it was given all the
   room it asked for instead of being constrained and overflowing, so
   there was nothing to swipe.

   minmax(0, 1fr) floors the track at zero, so the tab strip is held to
   the screen width and scrolls internally. Fixes both symptoms at once.
   --------------------------------------------------------------- */
.budget-view {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
}

.budget-view > * {
  min-width: 0;
}

.sticky-head {
  min-width: 0;
}

.pdf-report {
  display: none;
}

.sticky-head {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--bg);
}

.topbar {
  display: grid;
  gap: 10px;
  padding: 8px 0 2px;
}

@media print {
  :root {
    --bg: #ffffff;
    --panel: #ffffff;
    --panel-2: #ffffff;
    --text: #000000;
    --muted: #4a4a4a;
    --line: #d0d0d0;
  }

  body {
    background: #ffffff;
    color: #000000;
  }

  .budget-view,
  .auth-panel {
    display: none !important;
  }

  .app-shell {
    width: 100%;
    min-height: 0;
    padding: 0;
  }

  .pdf-report {
    display: grid;
    gap: 18px;
    padding: 28px;
    color: #000000;
  }

  .pdf-report header {
    border-bottom: 2px solid #000000;
    padding-bottom: 12px;
  }

  .pdf-report p,
  .pdf-report h1,
  .pdf-report h2 {
    margin: 0;
  }

  .pdf-report header p {
    color: #555555;
    font-size: 0.82rem;
    font-weight: 800;
    text-transform: uppercase;
  }

  .pdf-report h1 {
    margin: 4px 0;
    font-size: 2rem;
  }

  .pdf-report h2 {
    margin-bottom: 8px;
    font-size: 1rem;
  }

  .pdf-report ul {
    margin: 0;
    padding-left: 18px;
  }

  .pdf-report li {
    margin-bottom: 6px;
  }

  .pdf-metrics {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
  }

  .pdf-metrics article {
    border: 1px solid #d0d0d0;
    padding: 10px;
  }

  .pdf-metrics span {
    display: block;
    color: #555555;
    font-size: 0.72rem;
    font-weight: 800;
  }

  .pdf-metrics strong {
    display: block;
    margin-top: 3px;
    font-size: 1.1rem;
  }

  .pdf-report table {
    width: 100%;
    border-collapse: collapse;
  }

  .pdf-report td {
    border-bottom: 1px solid #d0d0d0;
    padding: 7px 0;
  }

  .pdf-report td:nth-child(2),
  .pdf-report td:nth-child(3) {
    text-align: right;
  }
}

.month-line input {
  flex: 1;
  font-variant-numeric: tabular-nums;
  min-width: 0;
  text-align: center;
  font-weight: 800;
}

.month-line .icon-button {
  flex: 0 0 auto;
}

.actions {
  justify-content: flex-end;
}

.tabs {
  display: flex;
  gap: 8px;
  margin: 0 -14px;
  padding: 8px 14px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  /* This bar lives inside a position: sticky header. Without an explicit
     touch-action, some mobile browsers won't reliably treat a horizontal
     swipe here as "scroll this element" once the page itself is no longer
     zoomed in (page-level pinch-zoom used to pan the whole layout, which
     masked this). Being explicit + enabling momentum scrolling fixes it. */
  touch-action: pan-x;
  -webkit-overflow-scrolling: touch;
  /* Snap each tab into place as you swipe, so the strip feels like a
     native sliding control instead of scrolling to an arbitrary offset.
     scroll-padding is required alongside it: without it the snap pulls the
     active tab flush to the container edge, cancelling the padding and
     leaving the strip out of line with the cards below. */
  scroll-snap-type: x proximity;
  scroll-padding-inline: 14px;
}

.tabs::-webkit-scrollbar {
  display: none;
}

.tab {
  flex: 0 0 auto;
  min-height: 44px;
  scroll-snap-align: start;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  padding: 0 17px;
  white-space: nowrap;
  font-size: 0.83rem;
  font-weight: 500;
}

.tab.active {
  border-color: transparent;
  background: var(--button);
  color: var(--button-text);
  font-weight: 600;
}

.message {
  min-height: 20px;
  margin: 0;
  color: var(--muted);
  font-size: 0.82rem;
}

.message.compact {
  min-height: 16px;
  font-size: 0.75rem;
}

.tab-panel {
  display: none;
}

.tab-panel.active {
  display: grid;
  /* Same zero-floor as .budget-view: a wide child (long note text, a
     budget row) must never be able to stretch the page sideways. */
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
}

.tab-panel.active > * {
  min-width: 0;
}

.metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.metrics article,
.budget-row {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}

.metrics article {
  display: grid;
  gap: 5px;
  padding: 13px 14px;
}

.metrics span {
  color: var(--muted);
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.metrics strong {
  min-width: 0;
  overflow-wrap: anywhere;
  font-family: var(--font-display);
  font-size: 1.55rem;
  font-weight: 600;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}

.metrics small {
  min-width: 0;
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.metrics.one-line {
  grid-template-columns: 1fr;
}

.compact-grid {
  display: grid;
  gap: 10px;
}

.panel-head {
  justify-content: space-between;
  padding-top: 2px;
}

.list {
  display: grid;
  gap: 8px;
}

.budget-row {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(82px, 0.6fr) 34px;
  gap: 8px;
  padding: 8px;
}

.budget-row input {
  min-height: 34px;
  background: var(--panel-2);
}

.row-amount {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.paid-control {
  display: none;
  grid-column: 1 / 2;
  grid-template-columns: 16px auto;
  align-items: center;
  align-self: center;
  gap: 7px;
  color: var(--text);
  font-size: 0.78rem;
}

.expense-row .paid-control {
  display: grid;
}

.expense-row:has(.row-paid:checked) .row-name,
.expense-row:has(.row-paid:checked) .row-amount,
.expense-row:has(.row-paid:checked) .row-note {
  color: var(--muted);
  text-decoration: line-through;
}

.row-note {
  grid-column: 1 / 3;
}

.row-delete {
  grid-column: 3;
  /* 1 / -1 so it spans however many rows the entry has (the phone layout
     stacks name / amount / note into three). */
  grid-row: 1 / -1;
  align-self: stretch;
  /* Was an orange button with a red glyph, which read as an alarming blob
     on every row. Now it sits back into the page background and the x is
     muted, so it's discoverable without shouting. */
  background: var(--bg);
  color: var(--muted);
}

.admin-client-list {
  gap: 10px;
}

.admin-client {
  display: grid;
  gap: 8px;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}

.admin-client-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px;
}

.admin-client-head strong {
  overflow-wrap: anywhere;
}

.admin-client-head span {
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 700;
}

.admin-client-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  background: var(--panel-2);
  color: var(--text);
}

.admin-client-badge.status-active {
  color: #1fa971;
}

.admin-client-badge.status-past_due {
  color: var(--danger);
}

.admin-client-badge.status-disabled {
  color: var(--danger);
}

.admin-client-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.admin-client-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.admin-client-actions button {
  flex: 1 1 auto;
}

.admin-billing-panel {
  display: grid;
  gap: 8px;
  padding-top: 4px;
  border-top: 1px solid var(--line);
}

.trial-banner {
  margin: 0;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.78rem;
  font-weight: 600;
  text-align: center;
}

.overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: 18px;
  background: rgba(2, 12, 26, 0.6);
}

.overlay-card {
  display: grid;
  gap: 14px;
  width: min(440px, 100%);
  max-height: 86vh;
  overflow-y: auto;
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--panel);
  box-shadow: var(--shadow);
}

.tutorial-list {
  display: grid;
  gap: 8px;
  margin: 0;
  padding-left: 18px;
  color: var(--text);
  font-size: 0.86rem;
  line-height: 1.4;
}

.toggle-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 10px;
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 600;
}

.toggle-switch {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
}

.toggle-switch input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.toggle-track {
  display: block;
  width: 38px;
  height: 22px;
  border-radius: 999px;
  background: var(--line);
  transition: background 0.15s ease;
}

.toggle-thumb {
  display: block;
  width: 16px;
  height: 16px;
  margin: 3px;
  border-radius: 50%;
  background: var(--panel);
  transition: transform 0.15s ease;
}

.toggle-switch input:checked + .toggle-track {
  background: var(--button);
}

.toggle-switch input:checked + .toggle-track .toggle-thumb {
  transform: translateX(16px);
}

.native-app #installBtn {
  display: none !important;
}

.native-app .app-shell {
  padding-top: max(18px, env(safe-area-inset-top));
  padding-bottom: max(30px, env(safe-area-inset-bottom));
}

/* ===============================================================
   PHONE LAYOUT  (up to 619px)
   Everything above this is the shared mobile-first base; these are
   the phone-specific refinements. Goal: the whole screen is usable
   at 100% zoom on a ~375px handset, with the tab strip swiping
   horizontally rather than widening the page.
   =============================================================== */
@media (max-width: 619px) {
  .app-shell {
    padding: 14px 16px 26px;
  }

  .tabs {
    margin-inline: -16px;
    padding-inline: 16px;
    scroll-padding-inline: 16px;
  }

  /* Stack the month stepper so the month field keeps a comfortable
     tap size instead of being squeezed between the two arrows. */
  .month-line input {
    text-align: center;
  }

  /* Two metric tiles per row reads better than four on a narrow screen. */
  .metrics {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* The entry name gets the full width of its own line. Sharing a line with
     the amount field left it around 100px on a phone — "Car Insurance
     Payment" needs ~188px, so names were being cut off. Stacked, the field
     is ~304px and the whole name is readable.
     Line 1: name   Line 2: paid + amount   Line 3: note   (x spans all) */
  .budget-row {
    grid-template-columns: minmax(0, 1fr) minmax(90px, auto) 34px;
  }

  .row-name {
    grid-column: 1 / 3;
    grid-row: 1;
  }

  .paid-control {
    grid-column: 1 / 2;
    grid-row: 2;
  }

  .row-amount {
    grid-column: 2 / 3;
    grid-row: 2;
  }

  .row-label {
    grid-column: 1 / 2;
    grid-row: 3;
  }

  .row-remaining {
    grid-column: 2 / 3;
    grid-row: 3;
  }

  .row-note {
    grid-column: 1 / 3;
    grid-row: 4;
  }

  .row-drag {
    grid-column: 3;
    grid-row: 2;
  }

  /* Month controls centre on their own line, every action sits beneath. */
  .topbar {
    justify-items: center;
  }

  .month-line {
    width: 100%;
    justify-content: center;
  }

  .actions {
    flex-wrap: wrap;
    justify-content: center;
  }

  /* Full-width actions are far easier to hit with a thumb. */
  .admin-client-actions button {
    flex: 1 1 100%;
  }
}

/* ===============================================================
   DESKTOP / TABLET LAYOUT  (620px and up)
   More horizontal room: the topbar becomes a single row, metrics go
   four across, and the tab strip wraps instead of scrolling since it
   comfortably fits.
   =============================================================== */
@media (min-width: 620px) {
  .app-shell {
    padding-inline: 22px;
  }

  .topbar {
    grid-template-columns: 1fr auto;
    align-items: center;
  }

  .tabs {
    margin-inline: -22px;
    padding-inline: 22px;
    scroll-padding-inline: 22px;
    /* There's room here, so let the tabs wrap onto a second line rather
       than hiding some behind a horizontal scroll. */
    flex-wrap: wrap;
  }

  .compact-grid {
    grid-template-columns: 180px 1fr;
  }

  /* ENTRY LAYOUT from tablet width up.
     This deliberately starts at 620px, not 900px. Previously the stacked
     phone rules stopped at 619px and the wide rules only began at 900px,
     so between those widths NO row rules applied and the base
     `.row-note { grid-column: 1 / 3 }` dropped the note onto its own line
     under the name — the stacking bug.

     Shape: category / name / note stacked down the left, cost and payments
     left stacked down the right, grip and controls on the outer edges. */
  .budget-row {
    grid-template-columns: 28px minmax(0, 1fr) 150px 64px 40px;
    grid-template-rows: auto auto auto;
    align-items: center;
    column-gap: 12px;
    row-gap: 6px;
    padding: 12px 14px;
  }

  .row-drag { grid-column: 1; grid-row: 1 / span 3; align-self: center; }

  .row-label { grid-column: 2; grid-row: 1; }
  .row-name { grid-column: 2; grid-row: 2; }
  .row-note { grid-column: 2; grid-row: 3; }

  .row-amount { grid-column: 3; grid-row: 1; text-align: right; }
  .row-remaining { grid-column: 3; grid-row: 2; text-align: right; }

  /* With no countdown to show, the cost centres against the whole entry
     instead of hanging at the top. */
  .budget-row:not(.countdown-row) .row-amount {
    grid-row: 1 / span 2;
  }

  .paid-control {
    grid-column: 4;
    grid-row: 1 / span 3;
    justify-self: center;
    align-self: center;
  }

  .row-delete { grid-column: 5; grid-row: 1 / span 3; align-self: center; }

  /* The category reads as a tag above the name. Font size stays at 16px:
     dropping below it makes iPad Safari zoom in on focus. */
  .row-label {
    min-height: 34px;
    padding: 4px 10px;
    color: var(--muted);
    background: var(--panel-2);
  }

  .row-remaining {
    min-height: 34px;
    padding: 4px 8px;
  }

  .metrics {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* ===============================================================
   HERO — "Left to spend"
   The single headline number, shown above the tabs on every section
   so the answer to "how am I doing this month" is never more than a
   glance away.
   =============================================================== */
.hero-card {
  display: grid;
  gap: 10px;
  padding: 16px 18px 18px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--panel);
}

.hero-label {
  color: var(--muted);
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.hero-amount {
  font-family: var(--font-display);
  font-size: 2.4rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.hero-meter,
.bar {
  display: flex;
  height: 6px;
  border-radius: 99px;
  background: var(--panel-2);
  overflow: hidden;
}

.hero-meter-fill,
.bar-fill {
  width: 0;
  border-radius: 99px;
  background: var(--button);
  transition: width 0.25s ease;
}

.hero-sub {
  margin: 0;
  color: var(--muted);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

/* Month-summary sidebar (desktop; stacks under the tiles on phones) */
.month-summary {
  display: grid;
  gap: 14px;
  align-content: start;
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--panel);
}

.bar-block {
  display: grid;
  gap: 7px;
}

.bar-row {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  color: var(--muted);
  font-size: 0.78rem;
}

.bar-row b {
  color: var(--text);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.bar-fill.is-income {
  background: var(--muted);
}

.bar-fill.is-left {
  background: var(--line);
}

/* ===============================================================
   DESKTOP TABLE LAYOUT  (900px and up)
   The tab strip stays the same horizontal pill row as mobile; this
   breakpoint only widens the shell and splits the Monthly tab into
   two columns once there's room for it.
   =============================================================== */
@media (min-width: 900px) {
  .app-shell {
    width: min(1280px, 100%);
  }

  /* Monthly tab: tiles full width, then form beside the summary card. */
  #summary.tab-panel.active {
    grid-template-columns: minmax(0, 1fr) 320px;
    align-items: start;
    column-gap: 20px;
  }

  #summary > .metrics {
    grid-column: 1 / -1;
  }

  #summary > .month-summary {
    grid-column: 2;
    grid-row: 2 / span 2;
  }
}


/* ===============================================================
   CATEGORY LABELS, PAYOFF COUNTDOWN, ACCENTS, COLLAPSIBLE RAIL
   =============================================================== */

/* A countdown only applies to things that recur, not to cash on hand. */
.budget-row:not(.countdown-row) .row-remaining {
  display: none;
}

.row-remaining {
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* Subtotals per category, shown under a list once anything is categorised. */
.label-totals {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding-top: 2px;
}

.label-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--text);
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
}

.label-chip em {
  color: var(--muted);
  font-style: normal;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.64rem;
}

.settings-block {
  display: grid;
  gap: 8px;
}

.settings-label {
  color: var(--muted);
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.accent-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.accent-swatch {
  width: 44px;
  height: 44px;
  min-height: 44px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 50%;
  background: var(--swatch);
  cursor: pointer;
}

.accent-swatch.is-active {
  border-color: var(--text);
  box-shadow: 0 0 0 3px var(--bg) inset;
}

/* ===============================================================
   DRAG TO REORDER
   =============================================================== */

/* Only income and the expense lists are hand-orderable. */
.budget-row:not(.reorder-row) .row-drag {
  display: none;
}

.row-drag {
  width: 28px;
  min-width: 28px;
  background: transparent;
  color: var(--muted);
  cursor: grab;
  /* Critical: tells touch browsers this gesture belongs to us, not to page
     scrolling. Without it the drag is cancelled the moment the finger moves. */
  touch-action: none;
}

.row-drag:active {
  cursor: grabbing;
  transform: none;
}

.budget-row.is-dragging {
  position: relative;
  z-index: 3;
  border-color: var(--button);
  box-shadow: var(--shadow);
  opacity: 0.96;
}

.list.is-reordering {
  cursor: grabbing;
}

.list.is-reordering .budget-row:not(.is-dragging) {
  transition: transform 0.12s ease;
}

/* ===============================================================
   MONTH PICKER
   The native month field is kept in the DOM but hidden, so all the
   existing month logic keeps working; this is the visible control.
   =============================================================== */
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.month-display {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: transparent;
  color: var(--text);
  font-family: var(--font-display);
  font-size: 1.12rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
}

.month-card {
  width: min(360px, 100%);
}

.year-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.year-line strong {
  font-family: var(--font-display);
  font-size: 1.3rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.month-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}

.month-cell {
  position: relative;
  min-height: 48px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: transparent;
  color: var(--text);
  font-size: 0.9rem;
  font-weight: 500;
}

.month-cell.is-current {
  border-color: transparent;
  background: var(--button);
  color: var(--button-text);
  font-weight: 700;
}

/* A dot marks a month that already holds a budget. */
.month-cell.has-data::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 7px;
  width: 5px;
  height: 5px;
  margin-left: -2.5px;
  border-radius: 50%;
  background: var(--muted);
}

.month-cell.is-current.has-data::after {
  background: var(--button-text);
}

.month-legend {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  color: var(--muted);
  font-size: 0.72rem;
}

.month-legend .dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--muted);
}

/* ===============================================================
   DASHBOARD, GOALS, CATEGORIES
   =============================================================== */

.dash-card {
  display: grid;
  gap: 10px;
  padding: 16px 18px 18px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--panel);
  margin-bottom: 12px;
}

.dash-card h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 600;
}

.chart-box {
  display: grid;
  gap: 10px;
}

.chart-box svg {
  width: 100%;
  max-width: 420px;
  height: auto;
  display: block;
  margin: 0 auto;
  overflow: visible;
}

.chart-legend {
  display: grid;
  gap: 6px;
}

.chart-legend-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.78rem;
  color: var(--muted);
}

.chart-legend-row .swatch {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex: 0 0 auto;
}

.chart-legend-row b {
  margin-left: auto;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.chart-empty {
  color: var(--muted);
  font-size: 0.82rem;
  margin: 0;
}

/* Upcoming bills */
.upcoming-list {
  display: grid;
  gap: 8px;
}

.upcoming-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel-2);
  font-size: 0.82rem;
}

.upcoming-item .upcoming-when {
  color: var(--muted);
  font-size: 0.72rem;
}

.upcoming-item b {
  font-variant-numeric: tabular-nums;
}

/* Spending limits */
.limits-list {
  display: grid;
  gap: 12px;
}

.limit-item {
  display: grid;
  gap: 6px;
}

.limit-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  font-size: 0.82rem;
}

.limit-head button {
  margin-left: auto;
  flex: 0 0 auto;
}

.bar-fill.is-over {
  background: var(--danger);
}

/* Accounts breakdown */
.accounts-list {
  display: grid;
  gap: 8px;
}

.account-item {
  display: flex;
  justify-content: space-between;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel-2);
  font-size: 0.82rem;
}

.account-item.is-debt strong {
  color: var(--danger);
}

.account-total {
  display: flex;
  justify-content: space-between;
  padding: 10px 2px 0;
  font-weight: 600;
  border-top: 1px solid var(--line);
  margin-top: 4px;
}

/* Goals */
.goals-list {
  display: grid;
  gap: 12px;
}

.goal-card {
  display: grid;
  gap: 8px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel-2);
}

.goal-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}

.goal-head strong {
  font-size: 0.9rem;
}

.goal-meta {
  color: var(--muted);
  font-size: 0.72rem;
}

.goal-actions {
  display: flex;
  gap: 8px;
}

.goal-actions input {
  flex: 1;
  min-width: 0;
}

.goal-actions button {
  flex: 0 0 auto;
}

/* Category manager (Settings overlay) */
.category-manage-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.category-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel-2);
  font-size: 0.75rem;
}

.category-chip .swatch {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex: 0 0 auto;
}

.category-chip button {
  border: 0;
  background: none;
  padding: 0;
  color: var(--muted);
  cursor: pointer;
  font-size: 0.9rem;
  line-height: 1;
}

input[type="color"] {
  padding: 3px;
  height: 40px;
  cursor: pointer;
}
