/* cmloans.net — phone first.
   Built to be added to a home screen on iOS and Android and to feel like an
   app once it is there: standalone display, safe-area insets honoured, 44px
   touch targets, no hover-only affordances, and nothing wider than the
   viewport at any width. */

/* ---- palette -------------------------------------------------------------
   Three states, not two: an explicit choice stamps data-theme on <html>, and
   the default ("system") stamps nothing and follows prefers-color-scheme. So
   every colour is defined once on bare :root, redefined for system-dark, and
   redefined again for the explicit toggle — otherwise forcing light on a
   phone set to dark does nothing.

   The dark theme is a true black ground. On an OLED phone #000 is pixels that
   are off: deeper, and it costs nothing. Surfaces step up from it in small
   increments rather than one grey slab, so cards separate without borders
   doing all the work, and the reds and greens are lifted well clear of the
   4.5:1 line against that ground — a balance you cannot read is not a
   balance. */
:root {
  color-scheme: light dark;

  --bg: #f6f4f1;
  --surface: #ffffff;
  --surface-2: #faf8f6;
  --line: #e5e1db;
  --line-strong: #d3cdc4;
  --ink: #1b1917;
  --ink-2: #5c554e;
  --ink-3: #8a827a;
  --accent: #1b1917;
  --on-accent: #f6f4f1;
  --bad: #a8322b;
  --bad-bg: #fdf1f0;
  --good: #2d6a4f;
  --good-bg: #eff6f1;
  --warn: #8a5a11;
  --warn-bg: #fdf6e9;
  --forgive: #6b4fc4;
  --forgive-bg: #f1eefb;
  --scrim: rgba(20, 18, 16, 0.45);

  --r: 16px;
  --r-sm: 11px;
  --shadow: 0 1px 2px rgba(27, 25, 23, 0.05), 0 8px 24px -12px rgba(27, 25, 23, 0.14);

  --tap: 44px;
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);

  --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
    sans-serif;
  --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
}

/* One definition of dark, used by both the system default and the toggle. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    color-scheme: dark;
    --bg: #000000;
    --surface: #0e0e0f;
    --surface-2: #17171a;
    --line: #25252a;
    --line-strong: #3a3a41;
    --ink: #f4f4f5;
    --ink-2: #bcbcc4;
    --ink-3: #8b8b94;
    --accent: #f4f4f5;
    --on-accent: #000000;
    --bad: #ff6b61;
    --bad-bg: #23100e;
    --good: #4ade80;
    --good-bg: #0c2016;
    --warn: #f2c14e;
    --warn-bg: #231b08;
    --forgive: #a68cff;
    --forgive-bg: #1c1630;
    --scrim: rgba(0, 0, 0, 0.66);
    --shadow: 0 1px 0 rgba(255, 255, 255, 0.04), 0 10px 30px -14px rgba(0, 0, 0, 0.9);
  }
}
:root[data-theme='dark'] {
  color-scheme: dark;
  --bg: #000000;
  --surface: #0e0e0f;
  --surface-2: #17171a;
  --line: #25252a;
  --line-strong: #3a3a41;
  --ink: #f4f4f5;
  --ink-2: #bcbcc4;
  --ink-3: #8b8b94;
  --accent: #f4f4f5;
  --on-accent: #000000;
  --bad: #ff6b61;
  --bad-bg: #23100e;
  --good: #4ade80;
  --good-bg: #0c2016;
  --warn: #f2c14e;
  --warn-bg: #231b08;
  --forgive: #a68cff;
  --forgive-bg: #1c1630;
  --scrim: rgba(0, 0, 0, 0.66);
  --shadow: 0 1px 0 rgba(255, 255, 255, 0.04), 0 10px 30px -14px rgba(0, 0, 0, 0.9);
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
/* The html background is what shows under the status bar in a home-screen
   app with a translucent status bar, and behind rubber-band overscroll. */
html { -webkit-text-size-adjust: 100%; background: var(--bg); }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.5 var(--font);
  /* Nothing may scroll the page sideways. Anything genuinely wider than the
     screen gets its own overflow container. */
  overflow-x: hidden;
  -webkit-tap-highlight-color: transparent;
}

/* Stop iOS bouncing the whole document behind a standalone app. */
@media (display-mode: standalone) {
  body { overscroll-behavior-y: none; }
}

h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -0.015em; }
h1 { font-size: 22px; }
h2 { font-size: 16px; letter-spacing: 0.01em; }
h3 { font-size: 14.5px; letter-spacing: 0.01em; }
p { margin: 0 0 12px; }
a { color: inherit; }

.num { font-variant-numeric: tabular-nums; }

/* ---- chrome ------------------------------------------------------------- */
.app {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.top {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(12px);
  -webkit-backdrop-filter: saturate(1.6) blur(12px);
  border-bottom: 1px solid var(--line);
  padding: calc(var(--safe-t) + 10px) calc(var(--safe-r) + 16px) 10px
    calc(var(--safe-l) + 16px);
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: calc(var(--safe-t) + 52px);
}
.top .brand {
  font-weight: 650;
  letter-spacing: -0.02em;
  font-size: 16px;
  display: flex;
  align-items: center;
  gap: 8px;
  margin-right: auto;
  min-width: 0;
}
.top .brand span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The mark in the chrome IS the app icon file, so the two can never drift
   apart: change icon.svg and the header, the sign-in screen and the home
   screen all move together. */
.mark {
  width: 26px;
  height: 26px;
  flex: 0 0 26px;
  border-radius: 8px;
  display: block;
  object-fit: contain;
}

main {
  flex: 1;
  width: 100%;
  max-width: 860px;
  margin: 0 auto;
  padding: 16px calc(var(--safe-r) + 16px) calc(var(--safe-b) + 96px)
    calc(var(--safe-l) + 16px);
}

/* The tab bar sits at the bottom on a phone, where a thumb is. */
.tabs {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  display: flex;
  gap: 2px;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: saturate(1.6) blur(12px);
  -webkit-backdrop-filter: saturate(1.6) blur(12px);
  border-top: 1px solid var(--line);
  padding: 6px calc(var(--safe-r) + 8px) calc(var(--safe-b) + 6px)
    calc(var(--safe-l) + 8px);
}
.tabs button {
  flex: 1 1 0;
  min-width: 0;
  min-height: var(--tap);
  border: 0;
  background: transparent;
  color: var(--ink-3);
  font: 500 11px/1.2 var(--font);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  border-radius: var(--r-sm);
  cursor: pointer;
  padding: 4px 2px;
}
.tabs button svg { width: 21px; height: 21px; }
.tabs button[aria-current='true'] { color: var(--ink); background: var(--surface-2); }
.tabs button span {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* On a wide screen app.js moves the tab bar into the header, so brand, tabs,
   search and sign-out are one bar, the way the desktop Loans app has it.
   These rules only apply while it lives there. */
.top .tabs {
  position: static;
  flex: 0 1 auto;
  margin: 0 auto;
  padding: 3px;
  gap: 2px;
  border: 0;
  border-radius: 999px;
  background: var(--surface-2);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.top .tabs button { flex: 0 0 auto; flex-direction: row; min-height: 34px; font-size: 13.5px; padding: 0 16px; gap: 7px; border-radius: 999px; }
.top .tabs button svg { display: none; }
.top .tabs button[aria-current='true'] { background: var(--surface); box-shadow: var(--shadow); }
.top .brand:has(+ .tabs) { margin-right: 0; }
@media (min-width: 760px) {
  main { padding-bottom: 64px; max-width: none; padding-left: 24px; padding-right: 24px; }
}
@media (min-width: 1400px) {
  main { max-width: 1360px; }
}

/* ---- header search -------------------------------------------------------- */
.topsearch { position: relative; flex: 0 1 240px; min-width: 140px; display: none; }
.top .topsearch svg { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); width: 15px; height: 15px; color: var(--ink-3); pointer-events: none; }
.topsearch input {
  width: 100%; min-height: 36px; padding: 0 12px 0 34px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink);
  font: 500 13.5px/1 var(--font); -webkit-appearance: none; appearance: none;
}
.topsearch input:focus { border-color: var(--line-strong); outline: 0; box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink) 8%, transparent); }
.topsearch .hits {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 40;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: var(--shadow); padding: 4px; display: flex; flex-direction: column;
}
.topsearch .hits button {
  border: 0; background: transparent; color: var(--ink); text-align: left;
  font: 500 14px/1.2 var(--font); padding: 9px 10px; border-radius: 7px; cursor: pointer;
}
.topsearch .hits button:hover, .topsearch .hits button:focus-visible { background: var(--surface-2); }
@media (min-width: 760px) { .topsearch { display: block; } }

/* ---- Overview ------------------------------------------------------------- */
.vhead { display: flex; align-items: center; gap: 10px; margin: 2px 0 14px; flex-wrap: wrap; }
.vhead h2 { margin: 0; font-size: 20px; letter-spacing: -0.01em; }
.spacer { flex: 1; }
.sel {
  min-height: 36px; padding: 0 32px 0 12px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink); font: 500 13.5px/1 var(--font); max-width: 200px;
}
.vhead .seg { margin: 0; }
.vhead .seg button { min-height: 30px; padding: 0 12px; font-size: 13px; }

.strip {
  display: flex; flex-wrap: wrap; overflow: hidden; margin-bottom: 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow);
}
.strip .cell { flex: 1 1 150px; padding: 13px 16px; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); min-width: 0; }
.strip .lbl { font-size: 10px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.strip .val { font-size: 27px; font-weight: 300; letter-spacing: -0.025em; margin-top: 4px; }
.strip .sub { font-size: 11px; color: var(--ink-3); margin-top: 2px; }
@media (min-width: 1100px) { .strip .cell { border-bottom: 0; } }

.pos { color: var(--good); }
.neg { color: var(--bad); }
.written { color: var(--forgive); }
.bigfig { font-size: 30px; font-weight: 300; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.muted { color: var(--ink-3); }
td.small { font-size: 12px; }

.cardgrid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr)); gap: 14px; margin-bottom: 14px; }
.cardgrid2 > .card, .cardgrid2 > div { margin-bottom: 0; min-width: 0; }
.cardgrid2 { align-items: start; }
.cardgrid2 > div > .card:last-child { margin-bottom: 0; }
.cardhead { display: flex; align-items: baseline; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; }
.cardhead h3 { margin: 0; font-size: 15px; font-weight: 620; }
.cardhead h2 { margin: 0; }
.cardhead .hint { font-size: 12px; margin: 0; }
.chartbox { width: 100%; min-height: 120px; }
.chartbox svg { display: block; max-width: 100%; height: auto; }

.gridline { stroke: var(--line); stroke-width: 1; }
.zeroline { stroke: var(--ink-3); stroke-width: 1; }
.axistxt { fill: var(--ink-3); font-size: 10px; font-family: var(--font); }
.axislab { fill: var(--ink-2); font-size: 10.5px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; font-family: var(--font); }
.hit { fill: transparent; cursor: pointer; }
.hit:hover { fill: color-mix(in srgb, var(--ink) 6%, transparent); }
.lineser { fill: none; stroke-linejoin: round; stroke-linecap: round; }
.dot { stroke: var(--surface); stroke-width: 1.5; }
.bar { transition: opacity 0.15s ease; }
.bar:hover { opacity: 0.78; }

.legend { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.lgi {
  display: inline-flex; align-items: center; gap: 7px; font: 500 11.5px/1 var(--font); color: var(--ink-2);
  border: 1px solid var(--line); border-radius: 999px; padding: 6px 11px; background: var(--surface); cursor: pointer;
}
.lgi:hover { color: var(--ink); border-color: var(--line-strong); }
.lgi.off { opacity: 0.4; }
.lgi .sw { width: 9px; height: 9px; border-radius: 3px; flex: 0 0 auto; display: block; }
.lgi.dash .sw { border-radius: 2px; height: 3px; width: 14px; }

.tip {
  position: fixed; z-index: 200; pointer-events: none; max-width: 300px;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow); padding: 9px 12px; font-size: 12px;
}
.tip .hd { font-weight: 600; margin-bottom: 2px; }
.tip .r { display: flex; justify-content: space-between; gap: 16px; margin-top: 3px; color: var(--ink-2); }
.tip .r span:last-child { color: var(--ink); font-variant-numeric: tabular-nums; }

.stand { display: flex; flex-direction: column; gap: 10px; }
.stand .srow {
  display: grid; grid-template-columns: 120px 1fr 96px; align-items: center; gap: 12px;
  border: 0; background: transparent; color: inherit; padding: 2px 0; width: 100%; text-align: left; cursor: pointer; font: inherit;
}
.stand .sname { font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stand .bar { position: relative; height: 9px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.stand .bar i { position: absolute; top: 0; bottom: 0; border-radius: 999px; display: block; }
.stand .bar i.ahead { background: var(--good); left: 50%; }
.stand .bar i.behind { background: var(--bad); right: 50%; }
.stand .bar i.plan { background: var(--warn); right: 50%; }
.stand .sname .ptag { display: block; font-weight: 500; font-size: 11px; color: var(--ink-3); margin-top: 1px; }
.stand .sname .ptag.neg { color: var(--bad); }
.stand .sname .ptag.pos { color: var(--good); }
.stand .bar::after { content: ''; position: absolute; left: 50%; top: -3px; bottom: -3px; width: 1px; background: var(--ink-3); }
.stand .sval { text-align: right; font-size: 13px; font-weight: 600; }
@media (max-width: 420px) { .stand .srow { grid-template-columns: 96px 1fr 84px; gap: 8px; } }

.tblwrap { overflow-x: auto; border: 1px solid var(--line); border-radius: 12px; }
table.tbl { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px; }
table.tbl th {
  position: sticky; top: 0; z-index: 2; box-shadow: 0 1px 0 var(--line); background: var(--surface-2); text-align: left;
  font-size: 10px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-2);
  padding: 9px 12px; border-bottom: 1px solid var(--line); white-space: nowrap;
}
table.tbl td { padding: 9px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
table.tbl tr:last-child td { border-bottom: 0; }
table.tbl tbody tr:hover { background: var(--surface-2); }
table.tbl td.r, table.tbl th.r { text-align: right; white-space: nowrap; }
table.tbl tr.placed td:first-child { box-shadow: inset 3px 0 0 var(--warn); }

.badge {
  display: inline-flex; align-items: center; gap: 6px; font-size: 10.5px; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; padding: 3px 9px; border-radius: 999px; white-space: nowrap;
  color: var(--ink-2); background: var(--surface-2);
}
.badge .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; display: block; }
.badge.b-good { color: var(--good); background: var(--good-bg); }
.badge.b-warn { color: var(--warn); background: var(--warn-bg); }
.badge.b-bad { color: var(--bad); background: var(--bad-bg); }
.badge.b-forgive { color: var(--forgive); background: var(--forgive-bg); }

/* A Review row: a tick on the left, and the rest of the row is a button. */
.row .tick { display: flex; align-items: center; padding: 6px 4px 6px 0; cursor: pointer; }
.row .tick input { width: 20px; height: 20px; }
.rowedit { border: 0; background: transparent; color: inherit; font: inherit; text-align: left; padding: 0; cursor: pointer; min-width: 0; }
.rowedit:hover .t { text-decoration: underline; }

/* ---- feeling like an app on a phone --------------------------------------- */
/* A new screen fades up rather than snapping in. */
main.arrive > .view, main.arrive > .card, main.arrive > .btnrow { animation: arrive 0.18s ease-out both; }
@keyframes arrive { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { main.arrive > * { animation: none; } }

@media (pointer: coarse) {
  /* Thumbs, not cursors: nothing to tap is under 44px tall. */
  .btn.small { min-height: 42px; font-size: 14px; padding: 0 14px; }
  .sel, input.sel, .sel.small { min-height: 44px; font-size: 16px; }
  .topsearch input { font-size: 16px; }
  .seg button { min-height: 40px; }
  .vhead .seg button { min-height: 38px; font-size: 14px; }
  .lgi { padding: 9px 13px; font-size: 12.5px; }
  .stand .srow { padding: 6px 0; }
  table.tbl td { padding: 12px 12px; }
  .row .tick input { width: 24px; height: 24px; }
  .pcard { padding: 16px 18px; }
  .tabs { padding-top: 8px; }
  .tabs button { min-height: 50px; font-size: 11.5px; gap: 4px; }
  .tabs button svg { width: 23px; height: 23px; }
}
/* Six sub-tabs on a narrow phone: the row scrolls sideways under the thumb
   rather than stacking into three lines. */
@media (max-width: 759px) {
  .vhead .seg.tabsline { flex-wrap: nowrap; overflow-x: auto; }
  .vhead .seg.tabsline button { flex: 1 0 auto; }
}
/* Six tabs on a narrow phone: the label shrinks before it truncates. */
@media (max-width: 420px) {
  .tabs button { font-size: 10.5px; padding: 4px 0; }
  .tabs { gap: 0; }
  /* Four sub-tabs on a 360px phone fit without clipping the last one. */
  .vhead .seg button, .vhead .seg.tabsline button { padding: 0 9px; font-size: 12.5px; }
}
@media (max-width: 759px) {
  .vhead { gap: 8px; }
  .vhead .seg.tabsline { flex: 1 1 100%; }
  .vhead .seg.tabsline button { flex: 1; justify-content: center; }
  .vhead h2 { flex: 1 1 100%; }
  .vhead .sel, .vhead input.sel { flex: 1 1 140px; max-width: none; }
  .vhead .seg { flex: 1 1 auto; }
  .vhead .btn.small { flex: 0 0 auto; }
  /* The as-of control gets a line of its own so "Back to today" never
     pushes the date off the edge, and Record becomes a thumb-sized bar. */
  .vhead .asof { flex: 1 1 100%; }
  .vhead .asof input.sel { flex: 1 1 auto; min-width: 0; max-width: none; }
  .vhead .btn.primary.small { flex: 1 1 100%; }
}

/* ---- entries as cards, on a phone ----------------------------------------- */
.erows { display: flex; flex-direction: column; gap: 8px; }
.erow { display: flex; gap: 8px; align-items: stretch; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 10px 12px; }
.erow.placed { box-shadow: inset 3px 0 0 var(--warn); }
.erow.off { opacity: 0.6; }
.erow .tick { display: flex; align-items: center; }
.erow .ebody { flex: 1; min-width: 0; border: 0; background: transparent; color: inherit; font: inherit; text-align: left; padding: 0; cursor: pointer; }
.erow .etop { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; }
.erow .etop .t { font-weight: 560; font-size: 14px; }
.erow .etop .amt { font-weight: 620; font-size: 16px; white-space: nowrap; }
.erow .esub { margin-top: 5px; display: flex; gap: 6px; align-items: center; flex-wrap: wrap; font-size: 13px; }
.erow .edesc { margin-top: 4px; font-size: 12px; overflow-wrap: anywhere; }
table.tbl tr.off td { opacity: 0.55; }

/* Looking as a borrower: a strip under the header that says so. */
.asbanner { display: flex; align-items: center; gap: 10px; padding: 8px calc(var(--safe-r) + 16px) 8px calc(var(--safe-l) + 16px); background: var(--warn-bg); color: var(--warn); font-size: 13.5px; font-weight: 560; border-bottom: 1px solid color-mix(in srgb, var(--warn) 35%, transparent); }
.asbanner .grow { min-width: 0; }

/* Home: the things to do, as chips. */
.needsyou { border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip { border: 1px solid var(--line-strong); background: var(--surface-2); color: var(--ink); font: 560 13.5px/1 var(--font); padding: 10px 14px; border-radius: 999px; cursor: pointer; text-align: left; }
.chip:hover { border-color: var(--ink-3); }
@media (pointer: coarse) { .chip { min-height: 42px; } }

/* Activity and More: a second row of tabs, with counts. */
.seg.tabsline button { display: inline-flex; align-items: center; gap: 6px; }
.count { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px; background: var(--warn); color: #1b1917; font: 700 11px/1 var(--font); }
.row.proposed { background: var(--warn-bg); margin: 0 -8px; padding-left: 8px; padding-right: 8px; border-radius: var(--r-sm); }
.row .s.proposal { color: var(--warn); font-weight: 560; margin-top: 4px; }
.row .btnrow { flex-direction: column; gap: 6px; }

/* Setup: switch rows and a text link on the sign-in screen. */
.row.switch { cursor: pointer; }
.row.switch input { width: 22px; height: 22px; flex: 0 0 22px; }
.linkbtn { border: 0; background: transparent; color: var(--ink); font: inherit; text-decoration: underline; padding: 0; cursor: pointer; }
.settings .card h2 { margin-bottom: 10px; }
.settings .cardgrid2 > .card { align-self: start; }

/* ---- settings: a rail of pages, one page at a time ---------------------- */
.setgrid { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: 24px; align-items: start; }
.setrailwrap { position: sticky; top: calc(var(--top-h, 60px) + 12px); }
.railtitle { margin: 0 0 8px 12px; font-size: 20px; letter-spacing: -0.01em; }
.setrail, .setindex { display: flex; flex-direction: column; }
.setgroup { font-size: 11px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); margin: 14px 12px 4px; }
.setgroup:first-child { margin-top: 4px; }
.setlink { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; border: 0; background: transparent; color: var(--ink-2); font: 500 14px/1.3 var(--font); padding: 9px 12px; border-radius: var(--r-sm); cursor: pointer; min-width: 0; }
.setlink .grow { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.setlink:hover { background: var(--surface-2); color: var(--ink); }
.setlink[aria-current='true'] { background: var(--surface-2); color: var(--ink); font-weight: 620; }
.setindex { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: 6px; }
.setindex .setgroup { margin: 12px 12px 2px; }
.setindex .setlink { padding: 12px; color: var(--ink); min-height: var(--tap, 44px); }
.setindex .setlink .t { font-weight: 560; font-size: 15px; }
.setindex .setlink .s { color: var(--ink-3); font-size: 12.5px; line-height: 1.45; }
.setindex .setlink .chev { color: var(--ink-3); flex: 0 0 auto; }
.setindex .setlink .chev svg { width: 18px; height: 18px; }
.pagehead { margin: 0 0 14px; }
.pagehead h2 { margin: 0 0 4px; font-size: 20px; letter-spacing: -0.01em; }
.pagehead .hint { margin: 0; }
.pagehead .back { margin: 0 0 8px -8px; }
.setbody { min-width: 0; }
.setbody .card { margin-bottom: 14px; }
details summary::-webkit-details-marker { display: none; }

/* ---- the toolbar over every list: search, select all, bulk actions ------ */
/* The bar sticks under the header while the list scrolls, so the search box
   and the bulk buttons are always in reach; the table's own header sticks
   just under the bar. Only where the table is not in a sideways scroller. */
.tools { margin: 0; position: sticky; top: var(--top-h, 62px); z-index: 6; background: var(--bg); padding: 8px 0 12px; }
@media (min-width: 760px) {
  .tblwrap { overflow: visible; }
  table.tbl th { top: calc(var(--top-h, 62px) + var(--tools-h, 0px)); }
  table.tbl th:first-child { border-top-left-radius: 0; }
  .view > .tools + .tblwrap table.tbl th, .card .tools ~ div table.tbl th, .card .tools ~ .tblwrap table.tbl th { z-index: 5; }
  /* Inside a sheet the table scrolls in its own box, not under the page
     header, so the sticky offset is the box's own top. */
  dialog.sheet table.tbl th { top: 0; }
  dialog.sheet .tblwrap { overflow: auto; }
}
.toolsrow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.toolsrow input.sel { flex: 1 1 220px; max-width: none; }
.toolsrow .hint { white-space: nowrap; }
.selall { display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface); cursor: pointer; flex: 0 0 36px; }
.selall input { width: 18px; height: 18px; margin: 0; }
.bulk { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; padding: 8px 12px; border-radius: var(--r-sm); background: var(--surface-2); border: 1px solid var(--line); }
.bulk .pickcount { font-weight: 600; color: var(--ink); margin-right: 4px; }
@media (pointer: coarse) { .selall { width: 44px; height: 44px; flex-basis: 44px; } .selall input { width: 22px; height: 22px; } }

/* Account tabs on the bank feed: they wrap rather than scroll off. */
.btnrow { align-items: center; }
.sincerow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 12px 0 4px; }
.sincerow .lab { font-size: 13px; font-weight: 560; color: var(--ink-2); }
.sincerow input.sel { max-width: 180px; }
.sincerow .hint { flex: 1 1 260px; }

/* Account chips on the bank feed: one per account, the number waiting on
   each, the ones with nothing dimmed. */
.accts { display: flex; flex-wrap: wrap; gap: 6px; }
.acct { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--line); background: var(--surface); color: var(--ink-2); font: 500 13px/1 var(--font); padding: 8px 12px; border-radius: 999px; cursor: pointer; }
.acct:hover { border-color: var(--line-strong); color: var(--ink); }
.acct[aria-pressed='true'] { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.acct[aria-pressed='true'] .mask, .acct[aria-pressed='true'] .count { color: var(--on-accent); }
.acct[aria-pressed='true'] .count { background: color-mix(in srgb, var(--on-accent) 20%, transparent); }
.acct.none { opacity: 0.55; }
.acct .mask { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.acct .count { min-width: 16px; height: 16px; font-size: 10.5px; }
.feedpage .vhead { margin-bottom: 10px; }
.daterange { display: flex; align-items: center; gap: 6px; }
.daterange input.sel { max-width: 150px; min-height: 36px; font-size: 13px; padding: 0 10px; }
@media (max-width: 759px) { .daterange { flex: 1 1 100%; } .daterange input.sel { flex: 1; max-width: none; } }

table.feedtbl { table-layout: fixed; }
table.feedtbl th:nth-child(1), table.feedtbl td:nth-child(1) { width: 40px; }
table.feedtbl th.c + th, table.feedtbl td.c + td { width: 92px; }
table.feedtbl th:nth-last-child(1), table.feedtbl td:nth-last-child(1) { width: 120px; }
table.feedtbl th:nth-last-child(2), table.feedtbl td:nth-last-child(2) { width: 190px; }
table.feedtbl.one th:nth-last-child(2), table.feedtbl.one td:nth-last-child(2) { width: 220px; }
table.feedtbl:not(.one) th:nth-last-child(3), table.feedtbl:not(.one) td:nth-last-child(3) { width: 200px; }
table.feedtbl td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
table.feedtbl td.c, table.feedtbl th.c { overflow: visible; text-overflow: clip; padding-right: 0; }
table.feedtbl td.c input { display: block; }
table.feedtbl td.faint { color: transparent; }
table.feedtbl td .t { font-weight: 560; }
table.feedtbl td .hint { font-size: 11.5px; margin-top: 1px; overflow: hidden; text-overflow: ellipsis; }
table.feedtbl td .suggest { white-space: normal; }
table.feedtbl tr.off td { opacity: 0.55; }
.seg.accts { flex-wrap: wrap; overflow: visible; }
.seg.accts button { flex: 0 0 auto; }
.count.quiet { background: var(--line-strong); color: var(--ink); }
.subhead { margin: 18px 0 10px; font-size: 15px; }

/* The archive, and archived things on a person's page. */
.pcard.archived { cursor: default; opacity: 0.92; }
.archhint { margin-top: 12px; }
.archdetails { margin-top: 12px; }
.archdetails .rows { margin-top: 6px; opacity: 0.8; }
.row .rowbtns { flex-direction: row; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
/* A row's text keeps a readable width; when the buttons will not fit
   beside it they drop underneath instead of squeezing the words. */
.row { flex-wrap: wrap; }
.headline .under.quiet { font-size: 13px; color: var(--ink-3); margin-top: 6px; }
.headline .planstate { margin-top: 10px; }
.headline .planstate .badge { font-size: 13px; padding: 6px 12px; }

/* ---- V1.3: sparklines, rings, suggestions, the Record sheet, undo ------- */
.sparkrow { display: flex; align-items: center; gap: 10px; margin: 2px 0 8px; }
.spark { width: 120px; height: 28px; flex: 0 0 120px; display: block; }
.trend { font-size: 12px; font-weight: 560; }
.proj { margin-top: 6px; }
.proj .pbar { height: 5px; border-radius: 999px; background: var(--surface-2); overflow: hidden; margin-bottom: 4px; max-width: 320px; }
.proj .pbar { display: flex; }
.proj .pbar i { display: block; height: 100%; background: var(--good); border-radius: 999px; }
.proj .pbar i.f { background: var(--forgive); }
.choices { display: flex; flex-direction: column; gap: 8px; }
.choice { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; text-align: left; width: 100%; padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface-2); color: inherit; font: inherit; cursor: pointer; }
.choice:hover { border-color: var(--line-strong); }
.choice .t { font-weight: 600; }
.choice .s { font-size: 13px; color: var(--ink-3); }
.suggest { display: flex; align-items: center; gap: 8px; margin-top: 4px; flex-wrap: wrap; }
.suggest .hint { color: var(--good); font-weight: 560; }
.suggest .btn.small { min-height: 28px; font-size: 12px; padding: 0 10px; }
label.check.remember { background: var(--good-bg); color: var(--good); padding: 10px 12px; border-radius: var(--r-sm); }
.toast { display: flex; align-items: center; gap: 14px; }
.toast .undo { border: 0; background: transparent; color: var(--on-accent); font: 700 14px/1 var(--font); text-decoration: underline; cursor: pointer; padding: 4px 0; }
.hits .hitgroup { font-size: 10px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); padding: 8px 10px 2px; }
.hits button { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; }
.hits button small { font-size: 11.5px; color: var(--ink-3); font-weight: 500; }
.topsearch { flex: 0 1 300px; }
.nextcard .nexttop { display: flex; align-items: center; gap: 16px; }
.nextcard .label { font-size: 11px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); }
.nextcard .nextamt { font-size: 30px; font-weight: 300; letter-spacing: -0.02em; margin: 2px 0; }
.nextcard .sub { font-size: 13px; }
.countdown { text-align: center; min-width: 72px; padding: 8px 10px; border-radius: var(--r-sm); background: var(--surface-2); border: 1px solid var(--line); }
.countdown .n { font-size: 28px; font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; }
.countdown .u { font-size: 11px; color: var(--ink-3); margin-top: 3px; }
.countdown.warn { background: var(--warn-bg); border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
.countdown.warn .n { color: var(--warn); }
.countdown.neg { background: var(--bad-bg); border-color: color-mix(in srgb, var(--bad) 40%, transparent); }
.countdown.neg .n { color: var(--bad); }
.rings { display: flex; flex-direction: column; gap: 12px; }
.ring { display: flex; align-items: center; gap: 14px; }
.ringsvg { flex: 0 0 56px; }
.ring .t { font-weight: 600; }
.ring .s { font-size: 13px; color: var(--ink-3); }

.erow.stack { flex-direction: column; align-items: stretch; }
.erow.stack .ebody { width: 100%; }
.econtrols { display: flex; flex-direction: column; gap: 6px; padding-top: 8px; margin-top: 8px; border-top: 1px solid var(--line); }
.econtrols .sel.small { margin-top: 0; }
.tapfor { font-size: 12px; }

.dueask { border-top: 1px solid var(--line); margin-top: 10px; }
.dueask .sel.small { width: auto; min-width: 110px; }

/* A part of a split, in the split sheet. */
.part { border: 1px solid var(--line); border-radius: var(--r-sm); padding: 12px 12px 4px; margin-bottom: 10px; }
.part .field { margin-bottom: 10px; }

/* ---- People and Due cards ------------------------------------------------ */
.pgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); gap: 12px; }
.pcard {
  display: block; width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: 14px 16px; box-shadow: var(--shadow);
}
.pcard:hover { border-color: var(--line-strong); transform: translateY(-1px); box-shadow: var(--shadow); }
/* ---- finish: things respond to the hand ---------------------------------
   One short transition on anything that can be pressed, and a lift on a
   card that opens. Off when the person has asked for less motion. */
.pcard, .btn, .rowlink, .setlink, .chip, .seg button, .tabs button, .strip .cell.tap, .choice, .cardhead .expand { transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease; }
.btn:active, .pcard:active, .rowlink:active { transform: translateY(0) scale(0.99); }
.btn.primary:hover { filter: brightness(1.08); }
button.rowlink:hover { background: var(--surface-2); }
@media (prefers-reduced-motion: reduce) { .pcard, .btn, .rowlink, .setlink, .chip, .seg button, .tabs button, .strip .cell.tap, .choice { transition: none; } .pcard:hover { transform: none; } }
.pcard .ptop { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.pcard .av { width: 34px; height: 34px; border-radius: 50%; background: var(--surface-2); border: 1px solid var(--line); display: flex; align-items: center; justify-content: center; font-weight: 650; flex: 0 0 34px; }
.pcard .pname { font-weight: 620; }
.pcard .prow { display: flex; justify-content: space-between; gap: 12px; font-size: 13px; padding: 4px 0; }
.pcard .prow .k { color: var(--ink-2); }
.pcard .prow.total { border-top: 1px solid var(--line); margin-top: 6px; padding-top: 9px; align-items: baseline; }
.pcard .prow .big { font-size: 19px; font-weight: 620; letter-spacing: -0.02em; }
.sel.small { min-height: 30px; font-size: 12.5px; padding: 0 28px 0 10px; margin-top: 6px; }
input.sel { padding-right: 12px; }

/* ---- sheets (dialogs) ------------------------------------------------------ */
dialog.sheet { padding: 0; width: min(520px, calc(100vw - 24px)); }
dialog.sheet.wide { width: min(640px, calc(100vw - 24px)); }
dialog.sheet .mhead { display: flex; align-items: baseline; gap: 10px; padding: 16px 18px 0; flex-wrap: wrap; }
dialog.sheet .mbody { padding: 12px 18px 4px; max-height: 62dvh; overflow-y: auto; }
dialog.sheet .mfoot { display: flex; gap: 8px; align-items: center; padding: 12px 18px 16px; border-top: 1px solid var(--line); flex-wrap: wrap; }
dialog.sheet .field { margin-bottom: 12px; }
dialog.sheet .field .hint { display: block; margin-top: 4px; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
.grid2 > * { min-width: 0; }
@media (max-width: 440px) { .grid2 { grid-template-columns: 1fr; } }
.raterow { grid-template-columns: 1fr 1fr auto; align-items: end; }
.raterow .btn { margin-bottom: 14px; }
.ratebox { border: 1px solid var(--line); border-radius: var(--r-sm); padding: 12px; margin: 4px 0 12px; }
.ratebox .cardhead { margin-bottom: 8px; }
label.check { display: flex; align-items: center; gap: 8px; font-size: 14px; margin: 4px 0 12px; cursor: pointer; }
label.check input { width: 18px; height: 18px; }
.btn.danger { color: var(--bad); border-color: color-mix(in srgb, var(--bad) 40%, transparent); }
@media (max-width: 520px) {
  dialog.sheet { margin: auto 0 0; width: 100vw; max-width: 100vw; border-radius: var(--r) var(--r) 0 0; border-bottom: 0; max-height: 92dvh; }
  dialog.sheet .mfoot { padding-bottom: calc(var(--safe-b) + 14px); }
}

/* ---- the statement -------------------------------------------------------- */
.statement .paper { padding: 22px 22px 16px; }
.sthead { text-align: center; border-bottom: 2px solid var(--ink); padding-bottom: 12px; margin-bottom: 16px; }
.stname { font-size: 20px; font-weight: 700; letter-spacing: 0.06em; }
.stsub { font-size: 11px; letter-spacing: 0.16em; color: var(--ink-2); margin-top: 4px; }
.verdict { border: 1px solid var(--line); border-radius: var(--r-sm); padding: 14px 16px; margin-bottom: 14px; background: var(--surface-2); }
.verdict.good { background: var(--good-bg); }
.verdict.bad { background: var(--bad-bg); }
.verdict .vhead-big { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; margin-bottom: 6px; }
.verdict.good .vhead-big { color: var(--good); }
.verdict.bad .vhead-big { color: var(--bad); }
.verdict p { margin: 0; font-size: 14px; }
.statement .strip { box-shadow: none; }
.stsection { margin-top: 18px; }
.stfoot { margin: 18px 0 0; text-align: center; font-size: 11px; }
@media print {
  .top, .tabs, .noprint, .toast, .tip { display: none !important; }
  html, body { background: #fff !important; color: #000 !important; }
  main { padding: 0 !important; max-width: none !important; }
  .card, .strip, .verdict, .tblwrap { box-shadow: none !important; border-color: #ccc !important; break-inside: avoid; }
  .paper { border: 0 !important; padding: 0 !important; }
  .stsection { break-inside: avoid; }
}

/* ---- cards -------------------------------------------------------------- */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 16px;
  margin: 0 0 12px;
}
@media (min-width: 760px) { .card { padding: 20px 22px; } }
.card.tight { padding: 12px 14px; }
.card > h2, .card > h3 { margin-bottom: 10px; }

.sub { color: var(--ink-2); font-size: 14px; }
.hint { color: var(--ink-3); font-size: 13px; line-height: 1.55; }

/* The one number the whole page exists to show. */
.headline { text-align: center; padding: 24px 12px 20px; }
.headline .label {
  font-size: 13px;
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 600;
}
.headline .big {
  font-size: clamp(44px, 14vw, 64px);
  font-weight: 300;
  letter-spacing: -0.035em;
  line-height: 1.05;
  margin: 8px 0 6px;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.headline .big.bad { color: var(--bad); }
.headline .big.good { color: var(--good); }
.headline .under { color: var(--ink-2); font-size: 14px; }

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
}
.stat {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 12px;
  min-width: 0;
}
.stat .k { font-size: 12px; color: var(--ink-2); font-weight: 500; }
.stat .v {
  font-size: 20px;
  font-weight: 620;
  letter-spacing: -0.02em;
  margin-top: 3px;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.stat .v.bad { color: var(--bad); }
.stat .v.good { color: var(--good); }
.stat .n { font-size: 12px; color: var(--ink-3); margin-top: 4px; line-height: 1.45; }

/* Forgiveness is a headline, not a footnote. */
.forgiven-card { background: var(--good-bg); border-color: color-mix(in srgb, var(--good) 28%, transparent); }
.forgiven-card .v { color: var(--good); }

/* ---- rows --------------------------------------------------------------- */
.rows { display: flex; flex-direction: column; }
.row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
  min-width: 0;
}
.row:last-child { border-bottom: 0; }
.row .grow { flex: 1 1 180px; min-width: min(160px, 100%); }
.row .t { font-weight: 520; overflow-wrap: anywhere; }
.row .s { font-size: 13px; color: var(--ink-3); margin-top: 2px; overflow-wrap: anywhere; }
.row .amt {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  white-space: nowrap;
  text-align: right;
}
.row .amt.bad { color: var(--bad); }
.row .amt.good { color: var(--good); }

button.rowlink {
  display: flex;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  color: inherit;
  font: inherit;
  padding: 12px 0;
  gap: 12px;
  align-items: center;
  min-height: var(--tap);
  cursor: pointer;
  min-width: 0;
}
button.rowlink:last-child { border-bottom: 0; }
button.rowlink .chev { color: var(--ink-3); flex: 0 0 auto; }
button.rowlink .grow { flex: 1; min-width: 0; }
button.rowlink .amt { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }

/* ---- pills -------------------------------------------------------------- */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 560;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--ink-2);
  white-space: nowrap;
}
.pill.bad { background: var(--bad-bg); color: var(--bad); border-color: color-mix(in srgb, var(--bad) 26%, transparent); }
.pill.good { background: var(--good-bg); color: var(--good); border-color: color-mix(in srgb, var(--good) 26%, transparent); }
.pill.warn { background: var(--warn-bg); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 30%, transparent); }

/* ---- controls ----------------------------------------------------------- */
.btn {
  -webkit-appearance: none;
  appearance: none;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink);
  font: 600 15px/1 var(--font);
  padding: 0 16px;
  min-height: var(--tap);
  border-radius: var(--r-sm);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  text-decoration: none;
  max-width: 100%;
}
.btn { border-radius: 999px; letter-spacing: 0.005em; }
.btn:active { transform: scale(0.985); }
/* An inline SVG with a viewBox and no width/height has no intrinsic size, so
   it fills whatever the flex line gives it and shoves the label onto three
   lines. The tab bar sized its icons; every other button did not. */
.btn svg { width: 18px; height: 18px; flex: 0 0 18px; }
.btn.small svg { width: 15px; height: 15px; flex-basis: 15px; }
.btn > span, .btn { white-space: nowrap; }
.btn.primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.btn.ghost { border-color: transparent; background: transparent; color: var(--ink-2); }
.btn.small { min-height: 36px; font-size: 13px; padding: 0 13px; }
.btn.wide { width: 100%; }
.btn[disabled] { opacity: 0.5; cursor: default; }
.btn.ok { background: var(--good-bg); color: var(--good); border-color: color-mix(in srgb, var(--good) 34%, transparent); }

.btnrow { display: flex; flex-wrap: wrap; gap: 8px; }

label.field { display: block; margin: 0 0 14px; }
label.field .lab { display: block; font-size: 13px; font-weight: 560; color: var(--ink-2); margin-bottom: 5px; }
input[type='text'], input[type='email'], input[type='password'], input[type='date'],
input[type='number'], input[type='tel'], input[type='url'], select, textarea {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  min-height: var(--tap);
  padding: 11px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  /* 16px or iOS zooms the page on focus, which then cannot be zoomed back. */
  font: 16px/1.4 var(--font);
}
textarea { min-height: 88px; resize: vertical; }
input:focus-visible, select:focus-visible, textarea:focus-visible, .btn:focus-visible,
button:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.seg {
  display: flex;
  gap: 2px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 3px;
  overflow-x: auto;
  scrollbar-width: none;
}
.seg::-webkit-scrollbar { display: none; }
.seg button {
  flex: 1 0 auto;
  border: 0;
  background: transparent;
  color: var(--ink-2);
  font: 560 13px/1 var(--font);
  padding: 9px 12px;
  border-radius: 7px;
  cursor: pointer;
  white-space: nowrap;
  min-height: 36px;
}
.seg button[aria-pressed='true'] { background: var(--surface); color: var(--ink); box-shadow: var(--shadow); }

/* ---- tables ------------------------------------------------------------- */
/* A table is the one thing allowed to be wider than the screen, and only
   inside its own scroller. */
.scroll-x {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 -14px;
  padding: 0 14px;
}
table { border-collapse: collapse; width: 100%; font-size: 14px; }
th, td { text-align: left; padding: 9px 10px; border-bottom: 1px solid var(--line); white-space: nowrap; }
th { font-size: 12px; font-weight: 600; color: var(--ink-2); text-transform: uppercase; letter-spacing: 0.05em; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
td.bad { color: var(--bad); }
td.good { color: var(--good); }
tr:last-child td { border-bottom: 0; }

/* ---- chart -------------------------------------------------------------- */
.chart { width: 100%; height: auto; display: block; max-width: 100%; }

/* ---- sign in ------------------------------------------------------------ */
.gate {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: calc(var(--safe-t) + 24px) calc(var(--safe-r) + 18px)
    calc(var(--safe-b) + 24px) calc(var(--safe-l) + 18px);
}
.gate .box { width: 100%; max-width: 380px; }
.gate .mark { width: 46px; height: 46px; flex-basis: 46px; border-radius: 12px; margin: 0 auto 16px; display: block; }
.gate h1 { text-align: center; margin-bottom: 6px; }
.gate .sub { text-align: center; margin-bottom: 22px; }

/* ---- misc --------------------------------------------------------------- */
.msg {
  border-radius: var(--r-sm);
  padding: 11px 13px;
  font-size: 14px;
  margin: 0 0 14px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.msg.bad { background: var(--bad-bg); color: var(--bad); }
.msg.good { background: var(--good-bg); color: var(--good); }
.msg.warn { background: var(--warn-bg); color: var(--warn); }

.empty { text-align: center; color: var(--ink-3); padding: 34px 16px; font-size: 15px; }

/* A button that follows the bottom of the screen while a long list scrolls.
   On a phone it rides above the tab bar; on a wide screen the tabs are at the
   top, so it sits on the bottom edge. The fade behind it keeps the rows it
   passes over from showing through around the button. */
.stick-bottom {
  position: sticky;
  bottom: calc(var(--safe-b) + 64px);
  padding: 10px 0 4px;
  background: linear-gradient(to bottom, transparent, var(--bg) 45%);
}
@media (min-width: 760px) {
  .stick-bottom { bottom: 0; padding-bottom: 12px; }
}

.spin {
  width: 18px; height: 18px;
  border: 2px solid var(--line-strong);
  border-top-color: var(--ink);
  border-radius: 50%;
  animation: sp 0.7s linear infinite;
  display: inline-block;
}
@keyframes sp { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spin { animation-duration: 2s; } * { scroll-behavior: auto !important; } }

.toast {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(var(--safe-b) + 76px);
  z-index: 60;
  background: var(--ink);
  color: var(--on-accent);
  padding: 12px 18px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 540;
  box-shadow: var(--shadow);
  max-width: calc(100vw - 32px);
  text-align: center;
}
@media (min-width: 760px) { .toast { bottom: 24px; } }

dialog {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--ink);
  padding: 18px;
  width: min(480px, calc(100vw - 28px));
  max-height: 86dvh;
  box-shadow: var(--shadow);
}
dialog::backdrop { background: var(--scrim); }

.linkbox {
  display: flex;
  gap: 8px;
  align-items: stretch;
  margin-top: 10px;
}
.linkbox input {
  font: 13px/1.4 var(--mono);
  min-height: var(--tap);
}

/* Add to Home Screen prompt, shown once. */
.a2hs { display: flex; gap: 12px; align-items: flex-start; }
.a2hs .grow { flex: 1; min-width: 0; }

/* The chart is drawn at this box's measured pixel width, so one SVG unit is
   one CSS pixel and the axis text is the size it says it is. */
.chartbox { width: 100%; min-height: 190px; }
.chartbox svg { display: block; width: 100%; height: auto; max-width: 100%; }

/* ---- the landing page ----------------------------------------------------
   Four words and a sign-in box. No feature list, no names, no amounts, no
   count of who is on it: a private ledger that advertises itself is a target.

   No photography anywhere. The art is the mark's own idea at wall size, drawn
   in SVG — a zero rule with the debt hanging off it, closing left to right.
   It weighs a few hundred bytes, loads with the page, and cannot 404. */
.land {
  position: relative;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  overflow: hidden;
  /* The landing page is always dark, whatever the phone is set to. It is the
     first thing anyone sees and it should look like one thing. */
  background: #08080a;
  color: #f4f2ee;
}
.land-art { position: absolute; inset: 0; z-index: 0; }

/* The generated loop. Hidden until it is genuinely playing, and the drawn
   columns fade out underneath it rather than being removed, so the handover
   is a cross-fade and not a flash of black. */
.land-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 900ms ease;
  pointer-events: none;
}
.land.has-video .land-video { opacity: 0.55; }
.land.has-video .land-bars { opacity: 0.1; transition: opacity 900ms ease; }
@media (min-width: 900px) { .land.has-video .land-bars { opacity: 0.12; } }

.land-bars {
  position: absolute;
  /* Texture on the right, never under the headline. The left column has to
     stay clean or the type fights a chart for the same pixels. */
  left: 8%;
  right: 4%;
  bottom: 6%;
  width: auto;
  height: 56%;
  opacity: 0.26;
  /* Screen, so the columns ADD light over the vignette instead of sitting
     under it and turning brown. */
  mix-blend-mode: screen;
}
@media (min-width: 900px) {
  .land-bars { left: 46%; right: 2%; bottom: 10%; height: 64%; opacity: 0.3; }
}
.land-bar {
  transform-origin: 0 60px;          /* the zero rule: columns grow down from it */
  /* Two animations: the drop on load, then a slow breath that never stops.
     Different periods per column so the row never resolves into a wave the
     eye can follow — a login page should have a pulse, not a thing to watch. */
  animation:
    bardrop 1000ms cubic-bezier(0.16, 0.84, 0.28, 1) both,
    barbreathe var(--dur, 6s) ease-in-out infinite alternate;
  animation-delay: calc(var(--i) * 52ms + 140ms), calc(var(--i) * 190ms + 1200ms);
}
@keyframes barbreathe { from { transform: scaleY(1); } to { transform: scaleY(var(--amp, 0.96)); } }
@keyframes bardrop { from { transform: scaleY(0); } to { transform: scaleY(1); } }
.land-zero {
  transform-origin: 0 50%;
  opacity: 0.85;
  animation: rulein 650ms cubic-bezier(0.16, 0.84, 0.28, 1) both;
}
@keyframes rulein { from { transform: scaleX(0); opacity: 0; } to { transform: scaleX(1); opacity: 0.85; } }
@media (prefers-reduced-motion: reduce) {
  .land-bar, .land-zero { animation: none; }
}
/* A glow that drifts with the columns, so the light looks like it comes from
   them rather than being painted on behind. */
.land-glow { animation: glowdrift 19s ease-in-out infinite alternate; }
@keyframes glowdrift { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(-1.4%, -1%, 0); } }
@media (prefers-reduced-motion: reduce) { .land-glow { animation: none; } }

/* Light, not colour wash: a green bloom where the debt runs out and a red one
   where it is deepest, both far enough down to leave the type alone. */
.land-glow {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(70% 55% at 88% 74%, rgba(62, 199, 90, 0.22), transparent 62%),
    radial-gradient(60% 50% at 40% 96%, rgba(224, 72, 60, 0.16), transparent 60%),
    radial-gradient(90% 70% at 10% 8%, rgba(255, 255, 255, 0.05), transparent 55%),
    linear-gradient(100deg, #08080a 0%, rgba(8, 8, 10, 0.96) 30%, rgba(8, 8, 10, 0.72) 52%, rgba(8, 8, 10, 0.55) 100%);
}
/* Grain as a data URI, because the page loads nothing from anywhere else. */
.land-grain {
  position: absolute;
  inset: 0;
  opacity: 0.32;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/></filter><rect width='140' height='140' filter='url(%23n)' opacity='0.5'/></svg>");
}

.land-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 1160px;
  margin: 0 auto;
  padding: calc(var(--safe-t) + 44px) calc(var(--safe-r) + 24px)
    calc(var(--safe-b) + 44px) calc(var(--safe-l) + 24px);
  display: grid;
  gap: 38px;
  grid-template-columns: 1fr;
  align-items: center;
}
@media (min-width: 900px) {
  .land-inner { grid-template-columns: 1.15fr 0.85fr; gap: 72px; padding-left: calc(var(--safe-l) + 48px); padding-right: calc(var(--safe-r) + 48px); }
}

/* The mark, big: it is the one thing on the page that is Chris's own, and
   at this size it reads as a badge rather than a favicon. A soft green
   bloom behind it ties it to the columns on the right. */
.land-mark {
  width: 132px; height: 132px; border-radius: 32px; display: block; margin-bottom: 30px;
  box-shadow: 0 24px 70px -22px rgba(62, 199, 90, 0.45), 0 2px 0 rgba(255, 255, 255, 0.04);
}
@media (max-width: 899px) {
  .land-say { text-align: center; }
  .land-mark { width: 104px; height: 104px; border-radius: 26px; margin: 0 auto 22px; }
  .land-rule { margin-left: auto; margin-right: auto; }
  .land-inner { gap: 30px; padding-top: calc(var(--safe-t) + 36px); }
}
.land-h1 {
  font-size: clamp(40px, 8.6vw, 68px);
  font-weight: 680;
  letter-spacing: -0.045em;
  line-height: 1.02;
  margin: 0;
  text-wrap: balance;
}
.land-rule {
  width: 64px;
  height: 4px;
  border-radius: 2px;
  margin: 26px 0 16px;
  background: linear-gradient(90deg, #e0483c, #c98f3a 45%, #3ec75a);
}
.land-quiet {
  margin: 0;
  color: #8f8a82;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* The sign-in box sits on glass over the art. */
.land-box { width: 100%; max-width: 400px; justify-self: end; }
@media (max-width: 899px) { .land-box { justify-self: stretch; max-width: none; } }
.land-box .card {
  background: rgba(16, 16, 19, 0.72);
  border-color: rgba(255, 255, 255, 0.13);
  backdrop-filter: blur(18px) saturate(1.3);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  padding: 26px 24px 22px;
  margin: 0;
  border-radius: 20px;
  box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.8);
}
.land-box .boxhead { font: 600 17px/1.2 var(--font); color: #f4f2ee; margin: 0 0 4px; }
.land-box .boxsub { font-size: 13px; color: #a9a49c; margin: 0 0 18px; }
.land-box .lab { color: #b9b4ab; }
.land-box input {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.17);
  color: #f4f2ee;
}
.land-box input:focus-visible { outline-color: #f4f2ee; }
.land-box .btn.primary { background: #f4f2ee; color: #14120f; border-color: #f4f2ee; }
.land-box .hint { color: #a9a49c; }
.land-box .msg.bad { background: rgba(224, 72, 60, 0.22); color: #ffb3ab; }
.land-box .msg.good { background: rgba(62, 199, 90, 0.2); color: #8fe0b0; }

/* ---- V1.4: tabs, plans, rules written by hand, tokens ------------------- */
.row .s.plan { font-weight: 560; margin-top: 4px; }
.row .s.plan.neg { color: var(--bad); }
.row .s.plan.pos { color: var(--good); }
.rkgroup { margin-top: 10px; }
.rkgroup .cardhead { margin-bottom: 4px; }
.rkgroup .row.placed { background: var(--warn-bg); }
.sel.small { padding: 4px 8px; font-size: 13px; }
.mono, input.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; }
code.mono { padding: 2px 6px; border-radius: 6px; background: var(--surface-2); }
/* A generic `th, td { nowrap }` further up was winning over the ledger
   table, so a long note pushed the whole page sideways. The wording and
   note columns wrap; dates, amounts and badges keep their nowrap. */
table.tbl td.muted, table.tbl td.muted.small { white-space: normal; overflow-wrap: anywhere; min-width: 160px; }

/* ---- V1.5 ---------------------------------------------------------------- */
.bigamt { font-size: 28px; font-weight: 640; font-variant-numeric: tabular-nums; }
.asof { display: inline-flex; align-items: center; gap: 6px; }
.asof input.sel { width: auto; min-height: 36px; }
.asof.on input.sel { border-color: var(--warn); }
.receipts { margin-top: 8px; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.files { display: flex; flex-wrap: wrap; gap: 6px; }
.filechip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border: 1px solid var(--line); border-radius: 999px; font-size: 13px; }
.filechip a { color: inherit; }
table.tbl tr.total td { border-top: 2px solid var(--line); }
textarea { width: 100%; box-sizing: border-box; }
.btn.wide { width: 100%; justify-content: center; }
.row .btnrow input[type=text] { min-width: 180px; }

/* A wide table that scrolls inside its own box, sticky header or not. */
.tblwrap.scrollx { overflow-x: auto !important; }
.tblwrap.scrollx table.tbl th { position: static; }

/* A strip cell that opens something: same look, a hand on hover, a lift. */
/* A button brings its own outset border and centres its contents; both
   have to go or the strip grows white seams and one tile floats. */
.strip button.cell { display: flex; flex-direction: column; justify-content: flex-start; align-items: stretch; font: inherit; color: inherit; background: none; text-align: left; cursor: pointer; appearance: none; margin: 0; border-top: 0; border-left: 0; border-radius: 0; }
/* A chart that opens big: the button sits in the card head. */
.cardhead .expand { margin-left: auto; min-width: 34px; min-height: 34px; padding: 0; display: inline-flex; align-items: center; justify-content: center; border-radius: 999px; }
.cardhead .expand svg { width: 16px; height: 16px; }
dialog.sheet.chartdlg { width: calc(100vw - 16px); max-width: 1100px; }
dialog.sheet.chartdlg .mbody { max-height: 80dvh; }
/* A chart full-screen on a phone, turned sideways. The rotor is a box the
   size of the screen in landscape, pinned at the top-right corner and
   rotated a quarter turn about that corner, so it lands exactly over the
   portrait screen. In real landscape it is not turned at all. */
dialog.sheet.chartfull { width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0; border: 0; border-radius: 0; background: var(--surface); }
dialog.sheet.chartfull .mhead, dialog.sheet.chartfull .mfoot { display: none; }
dialog.sheet.chartfull .mbody { max-height: none; height: 100dvh; padding: 0; overflow: hidden; position: relative; }
.rotor { position: absolute; top: 0; left: 100vw; width: 100dvh; height: 100vw; transform: rotate(90deg); transform-origin: top left; display: flex; flex-direction: column; gap: 6px; padding: calc(10px + var(--safe-t, 0px)) 18px 14px; box-sizing: border-box; }
.rotor.natural { left: 0; width: 100vw; height: 100dvh; transform: none; }
.rotor .rtop { display: flex; align-items: center; gap: 10px; }
.rotor .rtitle { font-weight: 620; font-size: 15px; flex: 1; }
.rotor .chartbox { flex: 1; min-height: 0; display: flex; align-items: center; }
.rotor .chartbox svg { max-height: 100%; }
.rotor .legend { margin-top: 0; }
.strip .cell.tap:hover { background: var(--surface-2); }
.strip .cell.tap:focus-visible { outline: 2px solid var(--accent, #7aa2ff); outline-offset: -2px; }
/* On a phone a row with several buttons wraps them under the text instead of
   crushing the text into a column of letters. */
@media (max-width: 759px) {
  .row { flex-wrap: wrap; }
  .row .grow { flex: 1 1 160px; }
  .row .rowbtns { flex: 0 0 100%; justify-content: flex-end; margin-top: 6px; }
  .row .rowbtns .btn { flex: 0 1 auto; }
}
/* The payment, itemised: each piece on its own chip so nothing is lumped. */
.headline .parts { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 8px; margin-top: 8px; }
.headline .parts .part { font-size: 13px; color: var(--ink-2); padding: 4px 10px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface-2); }
/* "a month" is the unit, not the number: smaller, and it may drop to its own line. */
.headline .big .per { font-size: 0.42em; font-weight: 400; color: var(--ink-2); letter-spacing: 0; white-space: nowrap; }
