/* caboose-fi — phone first.
 *
 * Rewritten after seeing it on an actual phone. The previous sheet grew by
 * append and assumed desktop widths: nothing truncated, five tab labels
 * fought for 390px, and the hero number was wider than the screen.
 *
 * Rules that hold throughout:
 *   - every flex row that contains text has a min-width:0 child, or long
 *     text pushes its sibling off-screen instead of shortening
 *   - type that must fit uses clamp() rather than a fixed rem
 *   - anything tappable is at least 44px
 */

:root {
  --bg: #0d1117;
  --panel: #161b22;
  --raised: #1c232c;
  --border: #2d333b;
  --text: #e6edf3;
  --muted: #8b949e;
  --accent: #79c0ff;
  --green: #7ee787;
  --red: #ff7b72;
  --warn: #e3b341;
  --link: #79c0ff;

  --gap: .75rem;
  --pad: .95rem;
  --radius: 12px;
  --tap: 44px;
}
@media (prefers-color-scheme: light) {
  :root {
    --bg: #f6f8fa; --panel: #ffffff; --raised: #f0f3f6; --border: #d0d7de;
    --text: #1f2328; --muted: #656d76; --accent: #0969da; --green: #1a7f37;
    --red: #cf222e; --warn: #9a6700; --link: #0969da;
  }
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
  background: var(--bg);
  color: var(--text);
  font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  min-height: 100vh;
  padding: 1rem .8rem 2rem;
  overflow-wrap: anywhere;
}
body.centered { display: flex; flex-direction: column; align-items: center; justify-content: center; }
/* Login/join: the heading sat flush against the first label with no room
   to breathe. */
body.centered .card h1 + * { margin-top: .8rem; }
body.app { padding-bottom: calc(4.6rem + env(safe-area-inset-bottom)); }

main, header, footer { max-width: 46rem; margin-inline: auto; width: 100%; }

/* ---- Header ---------------------------------------------------------- */
header {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--gap); margin-bottom: 1rem; flex-wrap: wrap;
}
header > div:first-child { min-width: 0; flex: 1 1 12rem; }
h1 { font-size: clamp(1.25rem, 5.5vw, 1.55rem); letter-spacing: -.01em; line-height: 1.2; }
h1 .dot, .accent { color: var(--accent); }
h2 {
  font-size: .7rem; color: var(--muted); text-transform: uppercase;
  letter-spacing: .09em; font-weight: 600;
}
p { margin-bottom: .7rem; }
p:last-child { margin-bottom: 0; }
.muted { color: var(--muted); }
.small { font-size: .78rem; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-variant-numeric: tabular-nums; }
/* A pairing code is read off the screen and typed into a phone: big, spaced,
   and selectable in one tap. */
.pair-code { font-size: 2rem; letter-spacing: .12em; margin: .5rem 0; user-select: all; }
.pos { color: var(--green); }
.neg { color: var(--red); }
.warn { color: var(--warn); }
.raw { word-break: break-all; }
a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }
/* One ring for every keyboard-focusable control, theme-aware since --accent
   already flips between light and dark. */
a:focus-visible, button:focus-visible, summary:focus-visible, a.row:focus-visible {
  outline: 2px solid var(--accent); outline-offset: -2px;
}
.sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; clip-path: inset(50%);
}

/* ---- Cards ----------------------------------------------------------- */
.card {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius); padding: var(--pad); margin-bottom: var(--gap);
}
.card.list { padding: 0; overflow: hidden; }
.card.list p, .quiet { padding: var(--pad); color: var(--muted); font-size: .85rem; }
.banner { border-radius: 10px; padding: .6rem .8rem; margin-bottom: var(--gap); font-size: .88rem; }
.banner.error { color: var(--red); border: 1px solid var(--red); }
.banner.warn { color: var(--warn); border: 1px solid var(--warn); }
.banner.ok { color: var(--green); border: 1px solid var(--green); }
/* A preview is not an error or a success: it is a mode, and it stays on
   every page until it is ended. */
.banner.preview { color: var(--accent); border: 1px solid var(--accent); display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .25rem .75rem; }
.note { margin-top: var(--gap); line-height: 1.6; font-size: .8rem; color: var(--muted); }

/* ---- Rows ------------------------------------------------------------
 * The core primitive: a description that shortens, and a figure that does
 * not. min-width:0 on the left is what makes the ellipsis possible at all. */
.row {
  display: flex; align-items: center; justify-content: space-between;
  gap: .7rem; padding: .62rem var(--pad); border-top: 1px solid var(--border);
  min-height: var(--tap);
}
.card.list > .row:first-child,
.card.list > a.row:first-child,
.card.list > form:first-child { border-top: none; }
.row > div:first-child { min-width: 0; flex: 1; }
.row > div:first-child > div { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row > span, .row > a:not(.row), .acct-right { flex: 0 0 auto; text-align: right; white-space: nowrap; }
a.row { color: inherit; text-decoration: none; }
a.row:active { background: var(--raised); }
@media (hover: hover) { a.row:hover { background: var(--raised); text-decoration: none; } }

/* The in/out/net figures folded into the header subtitle (e.g. /activity)
   are context, not calls to action -- link blue (or a red/green streak from
   the templates' pos/neg classes) made them compete with the page's real
   links. header p.muted a outranks the bare .pos/.neg classes. */
header p.muted a {
  color: inherit; text-decoration: underline dotted; text-underline-offset: .15em;
}
header p.muted a:hover { text-decoration-style: solid; }

/* ---- Hero ------------------------------------------------------------ */
.hero { text-align: center; padding: 1.1rem var(--pad) 1rem; }
.hero .label, .card.stat .label {
  font-size: .66rem; color: var(--muted); text-transform: uppercase;
  letter-spacing: .09em; font-weight: 600;
}
/* Pairs the label with a link (Left to spend / Targets) without the link
   inheriting the label's uppercase, tracked-out styling. */
.stat-head { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; }
.hero .big, .hero a.big {
  display: block; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.7rem, 9vw, 2.4rem); font-weight: 600;
  letter-spacing: -.03em; line-height: 1.15; margin: .15rem 0;
  color: inherit; text-decoration: none;
}
.hero .sub { font-size: .82rem; color: var(--muted); line-height: 1.5; }
.hero a { color: inherit; }
.hero a:hover, .card.stat a.num:hover { text-decoration: underline; text-underline-offset: .18em; }
/* The headline figure carries its own weight; red is reserved for when it is
   actually negative, and there is no green twin -- a positive net does not
   need to shout the way an inflow row does. Extra class in the selector
   outranks the templates' bare .pos/.neg so they cannot repaint it. */
.hero .big.neg, .hero a.neg, .card.stat .num.neg, .card.stat .big.neg { color: var(--red); }

/* ---- Stat pair ------------------------------------------------------- */
.cards, .split { display: flex; gap: var(--gap); margin-bottom: var(--gap); }
.cards > *, .split > * { flex: 1 1 0; min-width: 0; margin-bottom: 0; }
.card.stat { padding: .7rem .8rem; }
.card.stat .num, .card.stat a.num {
  display: block; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.05rem, 5.2vw, 1.4rem); font-weight: 600;
  margin-top: .1rem; letter-spacing: -.02em; color: inherit; text-decoration: none;
  overflow: hidden; text-overflow: ellipsis;
}
/* "Left to spend" (.big/.sub) had no base rule, so it rendered as body text
   until 64rem. Same sizing as .num, phone first. */
.card.stat .big, .card.stat a.big {
  display: block; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.05rem, 5.2vw, 1.4rem); font-weight: 600;
  margin-top: .1rem; letter-spacing: -.02em; color: inherit; text-decoration: none;
}
.card.stat .sub { font-size: .82rem; color: var(--muted); }

/* ---- Section headings ------------------------------------------------ */
.section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .7rem; margin: 1.3rem 0 .45rem; flex-wrap: wrap;
}
.section-head h2 { margin: 0; min-width: 0; white-space: nowrap; }
.section-head a, .section-head span { font-size: .76rem; white-space: nowrap; }

/* ---- Bars ------------------------------------------------------------ */
.bar-row { padding: .58rem var(--pad); border-top: 1px solid var(--border); }
.bar-top { display: flex; justify-content: space-between; gap: .7rem; margin-bottom: .35rem; align-items: baseline; }
.bar-top > :first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bar-top > :last-child { flex: 0 0 auto; }
.bar-top a { color: inherit; text-decoration: none; }
.bar-top a:hover { text-decoration: underline; }
.track { height: 5px; background: var(--bg); border: 1px solid var(--border); border-radius: 999px; overflow: hidden; }
.fill { height: 100%; background: var(--accent); border-radius: 999px; }

/* ---- Forms ----------------------------------------------------------- */
label { display: block; font-size: .78rem; color: var(--muted); margin-bottom: .25rem; }
input, select {
  width: 100%; background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: 10px;
  padding: .6rem .7rem; font: inherit; font-size: 16px; /* 16px stops iOS zooming on focus */
  margin-bottom: .7rem; min-height: var(--tap);
}
input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
button, a.button {
  background: var(--accent); color: var(--bg); border: none; border-radius: 10px;
  padding: .6rem 1.05rem; font: inherit; font-size: .92rem; font-weight: 600;
  cursor: pointer; min-height: var(--tap); white-space: nowrap;
}
button:active { filter: brightness(.92); }
a.button { display: inline-flex; align-items: center; justify-content: center; text-decoration: none; }
button.link {
  background: none; color: var(--muted); font-weight: 400; padding: .2rem 0;
  font-size: .82rem; text-decoration: underline;
  /* Visually a small text link, but still a 44px tap target. */
  display: inline-flex; align-items: center; min-height: var(--tap);
}
button.link:hover { color: var(--text); }
header form { margin: 0; flex: 0 0 auto; }
.card > form { margin: 0; }
.inline-act { padding: .55rem var(--pad); border-top: 1px solid var(--border); margin: 0; }
/* Small action forms (e.g. remove/revoke rows) that should not stretch. */
form.inline { margin: 0; flex: 0 0 auto; }

/* A row that is nothing but an action (Sign out): the whole row is the
   button, rather than a label sitting next to a second copy of itself. */
.row-button { padding: 0; }
.row-button > .row-label {
  background: none; border: none; border-radius: 0; box-sizing: border-box;
  display: flex; align-items: center; width: 100%;
  min-height: var(--tap); padding: .62rem var(--pad);
  font: inherit; font-weight: 400; color: inherit; text-align: left;
  cursor: pointer;
}
.row-button > .row-label:active { background: var(--raised); }
@media (hover: hover) { .row-button > .row-label:hover { background: var(--raised); } }

/* Anything a <details> uses as a disclosure control is a tap target too,
   even though it reads as small inline text. */
details > summary {
  display: inline-flex; align-items: center; min-height: var(--tap);
}

/* ---- Tab bar ---------------------------------------------------------
 * Five destinations on a 390px screen is 78px each. Labels are short, the
 * badge sits on the icon rather than after the word, and the whole thing
 * shrinks rather than wrapping. */
.tabs {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  display: flex; background: var(--panel); border-top: 1px solid var(--border);
  padding: .3rem .15rem calc(.35rem + env(safe-area-inset-bottom));
}
.tabs a {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .12rem; color: var(--muted); text-decoration: none;
  font-size: .62rem; letter-spacing: -.01em; padding: .3rem .1rem;
  min-height: var(--tap); position: relative;
}
.tabs a span {
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tabs a:hover { text-decoration: none; color: var(--text); }
.tabs a[aria-current="page"] { color: var(--accent); font-weight: 600; }
.tabs svg {
  width: 21px; height: 21px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.pip {
  position: absolute; top: .12rem; left: 50%; margin-left: .25rem;
  background: var(--accent); color: var(--bg); border-radius: 999px;
  min-width: 1.05rem; padding: 0 .2rem; font-size: .58rem; font-weight: 700;
  line-height: 1.05rem; text-align: center;
}

/* ---- Review queue ---------------------------------------------------
 * The controls stack on a phone. A select, a checkbox and a button sharing
 * one line at 390px left nothing readable. */
form.review { padding: .7rem var(--pad); border-top: 1px solid var(--border); margin: 0; }
.review-top { display: flex; justify-content: space-between; align-items: baseline; gap: .7rem; }
.review-top > div:first-child { min-width: 0; }
.review-top > div:first-child > div:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.review-top > span { flex: 0 0 auto; white-space: nowrap; }
.review .raw { margin-top: .12rem; opacity: .75; }
/* The guess sits between the payee and the dropdown it pre-selects, so the
   claim and the thing it acted on are read in one movement. */
.suggested { margin-top: .35rem; line-height: 1.4; }

.review-actions { display: flex; align-items: center; gap: .55rem; margin-top: .5rem; flex-wrap: wrap; }
.review-actions select { flex: 1 1 100%; margin-bottom: 0; }
.review-actions button { flex: 0 0 auto; }
.always { display: inline-flex; align-items: center; gap: .35rem; font-size: .78rem; color: var(--muted); margin: 0; flex: 1 1 auto; min-height: var(--tap); }
.always input { width: 18px; height: 18px; min-height: 0; accent-color: var(--accent); margin: 0; }
.new-cat { flex: 1 1 100%; margin: .1rem 0 0; }
/* The dismiss sits where the row's link would, so the attention block keeps
   one column of actions rather than two kinds of thing in the same place. */
.dismiss { margin: 0; flex: 0 0 auto; }
.dismiss button { min-height: 44px; }

/* One budget line: name and spend on top, progress bar, then the setter.
   Vertical rather than a table -- at 412px a four-column table either
   scrolls sideways or shrinks the numbers past reading. */
.bline { margin: 0; padding: .7rem var(--pad); border-bottom: 1px solid var(--border); }
.bline:last-child { border-bottom: 0; }
.bline-top { display: flex; align-items: baseline; justify-content: space-between; gap: .75rem; }
.bline-top > div:first-child { min-width: 0; }
.bline-edit { margin-top: .4rem; }
.bline-edit > summary { display: inline-flex; align-items: center; min-height: var(--tap); font-size: .8rem;
  color: var(--accent); cursor: pointer; list-style: none; }
.bline-edit > summary::-webkit-details-marker { display: none; }
.bline-edit > summary::after { content: " \203A"; margin-left: .3rem; }
.bline-edit[open] > summary::after { content: " \2039"; }

.bline-set { display: flex; gap: .5rem; margin-top: .5rem; }
.bline-set input { flex: 1 1 auto; margin: 0; min-width: 0; }
.bline-set button { flex: 0 0 auto; }

/* The bar carries the thing a number cannot: where you are in the month.
   Two colours only -- under and over -- because a gradient of worry invites
   reading precision into a bar that has none. */
.bar { height: 6px; border-radius: 3px; background: var(--border); overflow: hidden; margin: .5rem 0 .35rem; }
.bar span { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
.bar span.over { background: var(--red); }

/* Search first, filters folded behind a disclosure. The search box is what
   is wanted nine times in ten; four selects competing with it at 412px is
   how a filter bar becomes something people scroll past. */
.filters { padding: var(--pad); }
.filter-search { display: flex; gap: .5rem; }
.filter-search input { flex: 1 1 auto; min-width: 0; margin: 0; }
.filter-search button { flex: 0 0 auto; }
.filter-more { margin-top: .6rem; }
.filter-more > summary { display: inline-flex; align-items: center; min-height: var(--tap);
  font-size: .8rem; color: var(--accent); cursor: pointer; list-style: none; }
.filter-more > summary::-webkit-details-marker { display: none; }
.filter-more > summary::after { content: " \203A"; margin-left: .3rem; }
.filter-more[open] > summary::after { content: " \2039"; }
.filter-grid { display: grid; gap: .5rem; margin-top: .5rem; }
.filter-grid select { margin: 0; width: 100%; }
.filter-actions { display: flex; align-items: center; gap: .75rem; margin-top: .6rem; }

/* The "Payments from" pick list can run to 50 payees (payeeCandidateCap):
   the ones already linked sort first, so most of what a phone screen needs
   is above the fold, and the long tail of one-off-looking payees is a
   details disclosure rather than a scroll through fifty checkboxes. */
.payee-more { margin-top: .25rem; }
/* A payee's bounds, when one payee pays two debts (migration 033): two
   small amounts on a line under its name, indented to the name. */
.payee-bounds { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .5rem; margin: .1rem 0 .4rem 1.6rem; }
.payee-bounds input { width: 6.5em; margin: 0; }
.payee-range { margin: 0 0 .3rem 1.6rem; }
.payee-range > summary { display: inline-flex; align-items: center; min-height: var(--tap);
  color: var(--link); cursor: pointer; font-size: .82rem; list-style: none; }
.payee-range > summary::-webkit-details-marker { display: none; }
.payee-range > .payee-bounds { margin-left: 0; }
.payee-more > summary { display: inline-flex; align-items: center; min-height: var(--tap);
  font-size: .8rem; color: var(--accent); cursor: pointer; list-style: none; }
.payee-more > summary::-webkit-details-marker { display: none; }
.payee-more > summary::after { content: " \203A"; margin-left: .3rem; }
.payee-more[open] > summary::after { content: " \2039"; }

/* The pager states the range and the total. "Next" alone tells you there is
   more but never how much, which is the thing you want to know before
   deciding to page through it. */
.pager { margin-top: var(--gap); display: grid; gap: .5rem; justify-items: center; text-align: center; }
.pager-links { display: flex; flex-wrap: wrap; gap: .35rem; justify-content: center; }
.pager-links a { min-height: var(--tap); display: inline-flex; align-items: center;
  padding: 0 .7rem; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); }
.pager-size { display: flex; gap: .45rem; align-items: center; flex-wrap: wrap; justify-content: center; }
.pager-size a, .pager-size b { min-width: 32px; display: inline-flex;
  align-items: center; justify-content: center; }
.pager-size b { min-height: 32px; color: var(--accent); }
.pager-size a { min-width: 44px; min-height: 44px; }


/* Charts. Two drawings ship per card -- a compact one sized for a phone slot
   and the usual wide one -- and only one is ever visible: this rule picks the
   compact drawing by default (phone first), the width query below hands off
   to the wide one at tablet width up, and the print query below that hands
   it back regardless of screen width, so a chart never breaks across pages
   at a size tuned for scrolling past. Both scale to the card and keep their
   aspect ratio, so the one showing still works at whatever width the card
   actually is. */
.chart { padding: var(--pad); }
.chart svg { display: block; width: 100%; height: auto; margin: .4rem 0 .2rem; }
.chart-wide { display: none; }
.chart-head { display: flex; align-items: baseline; justify-content: space-between; gap: .75rem; }
.chart-head h2 {
  text-transform: none; letter-spacing: 0; color: var(--text); font-size: 1rem;
}
/* Moved out of the chart header into "The numbers" disclosure: that header
   is the first, most crowded thing on the card, and a download is something
   reached for after looking, not before. Full tap targets because these are
   the same weight as any other link a finger has to hit reliably. */
.chart-export { display: flex; gap: .4rem; flex: 0 0 auto; font-size: .8rem; margin-bottom: .3rem; }
.chart-export a { min-height: var(--tap); padding: 0 .6rem; display: inline-flex; align-items: center; }
.chart-data { margin-top: .5rem; }
.chart-data > summary { font-size: .8rem; color: var(--accent); cursor: pointer;
  list-style: none; min-height: var(--tap); display: inline-flex; align-items: center; }
.chart-data > summary::-webkit-details-marker { display: none; }
.chart-data table { width: 100%; border-collapse: collapse; font-size: .8rem; margin-top: .4rem; }
.chart-data th, .chart-data td { text-align: right; padding: .3rem .5rem; white-space: nowrap; }
.chart-data th:first-child, .chart-data td:first-child { text-align: left; }
.chart-data thead th { color: var(--muted); border-bottom: 1px solid var(--border); }
.scroll-x { overflow-x: auto; }

.ranges { display: flex; align-items: center; gap: .5rem; padding: .7rem var(--pad); flex-wrap: wrap; }
.ranges > span { white-space: nowrap; }
.ranges a, .ranges b {
  white-space: nowrap; min-height: var(--tap); display: inline-flex; align-items: center;
  padding: 0 .7rem; border-radius: 8px;
}
.ranges b { background: var(--bg); color: var(--accent); }

/* Printing is the PDF export. Anything that only makes sense on screen goes
   away, the dark theme is dropped so it does not consume a cartridge, and a
   chart is not allowed to break across pages. */
@media print {
  .no-print, nav.tabs, footer, header a { display: none !important; }
  :root { --bg: #fff; --panel: #fff; --raised: #fff; --text: #000;
          --muted: #444; --border: #bbb; }
  body { background: #fff; color: #000; }
  .card { break-inside: avoid; page-break-inside: avoid; border: 1px solid #bbb; box-shadow: none; }
  .chart-data[open] > summary { display: none; }
  .chart-data:not([open]) > * { display: revert; }
  main { max-width: none; padding: 0; }
  /* The compact chart exists for a phone screen, which a printed page never
     is -- print always gets the wide drawing, whatever width the screen
     that triggered the print was. */
  .chart-compact { display: none !important; }
  .chart-wide { display: block !important; }
}

.apply-all { margin-top: var(--gap); }

/* ---- Misc ------------------------------------------------------------ */
.monthnav { display: flex; gap: .3rem; flex: 0 0 auto; }
.monthnav a {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--tap); height: var(--tap); border: 1px solid var(--border);
  border-radius: 10px; color: var(--muted); font-size: 1.15rem; text-decoration: none;
}
.monthnav a:hover { color: var(--text); text-decoration: none; }
/* The amount and what it costs a year, stacked right. The annual figure is
   the one that changes minds about a subscription; the monthly one never
   looks like much. */
.due-amt { flex: 0 0 auto; text-align: right; }

.due-when { flex: 0 0 3.6rem; }
/* Matches the desktop 4.5rem override below -- the date column was getting
   squeezed by .row > div:first-child's flex:1 on phones too. */
.row > div.due-when { flex: 0 0 4rem; }
.due-what { flex: 1 1 auto; min-width: 0; }
.due-min { display: block; text-align: right; }
.due-what > div { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Needs a look: a Due row, then its actions on a line of their own under
   it, so the field and buttons never squeeze the name or the amount. The
   line spans the row on a phone, so Set amount and Not a bill share it,
   and starts under the name from 46rem. "amount unknown" is small, not a
   figure, so the name keeps its width. */
.look { border-top: 1px solid var(--border); }
.look > .row { border-top: none; }
.look-unknown { font-size: .78rem; }
.look-acts {
  display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .9rem;
  padding: 0 var(--pad) .62rem;
}
@media screen and (min-width: 46rem) { .look-acts { padding-left: calc(var(--pad) + 4.7rem); } }
.look-set { display: flex; align-items: center; gap: .5rem; margin: 0; }
.look-set input { width: 6em; margin: 0; min-height: var(--tap); }
.look-set button { flex: 0 0 auto; padding: .5rem .8rem; }
.look-off { margin: 0; }
/* This is a bill, in a charge's Change card: the price, how often and the
   button on one line where they fit and under each other where they do
   not, the price never narrower than a price; the note reads whole. */
.pin { border-top: 1px solid var(--border); margin-top: .7rem; padding-top: .7rem; }
.pin-set { flex-wrap: wrap; }
.pin-set select { width: auto; margin: 0; min-height: var(--tap); }
.pin-note { margin: .45rem 0 0; }
/* Add a bill, on Due: the name wider than a price, and the date field as
   wide as its picker needs. */
.hand-set input[name="name"] { width: 11em; }
.hand-set input[type="date"] { width: auto; }
/* Change, under a row counted at an amount the owner set. */
.card.list > .look:first-child { border-top: none; }
.own-change > summary {
  display: inline-flex; align-items: center; min-height: var(--tap);
  padding: 0 var(--pad); font-size: .8rem; color: var(--accent); cursor: pointer; list-style: none;
}
.own-change > summary::-webkit-details-marker { display: none; }
.own-change > summary::after { content: " \203A"; margin-left: .3rem; }
.own-change[open] > summary::after { content: " \2039"; }
@media screen and (min-width: 46rem) { .own-change > summary { padding-left: calc(var(--pad) + 4.7rem); } }
@media screen and (min-width: 64rem) { .own-change > summary { padding-left: calc(var(--pad) + 5.2rem); } }
@media screen and (min-width: 64rem) { .look-acts { padding-left: calc(var(--pad) + 5.2rem); } }
.attention { border-color: var(--warn); }
.acct-right { text-align: right; }
/* The sub-line can carry a warning ("no transactions for 40d") long enough
   that a single-line ellipsis would swallow the part that matters. Two
   lines and a stop, same trade as the attention block above. The extra
   class in the selector is what beats .row > div:first-child > div's
   nowrap -- same element, higher specificity needed to win. */
.row > div:first-child > div.acct-sub {
  white-space: normal;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
}
/* A warning ("no transactions for 40d", "$184.94 on hold") shares the row's
   clamp otherwise, and a long one gets cut mid-sentence right when it
   matters most. Its own line, unclamped, is the only way it always reads in
   full. */
.row > div:first-child > div.acct-warn {
  white-space: normal;
  overflow: visible;
}
.xfer { display: flex; align-items: center; gap: .6rem; }
.xfer form { margin: 0; }
footer {
  display: flex; justify-content: space-between; gap: .7rem;
  color: var(--muted); font-size: .72rem; margin-top: 1.6rem; flex-wrap: wrap;
}
.ver { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.card.soon { text-align: center; padding: 2.2rem 1.4rem; }
.soon-tag {
  display: inline-block; margin-top: .7rem; color: var(--accent);
  border: 1px solid var(--accent); border-radius: 999px; padding: .12rem .75rem;
  font-size: .76rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
}

/* ---- Wider screens --------------------------------------------------- */
@media (min-width: 46rem) {
  body { padding: 1.5rem 1rem 3rem; }
  body.app { padding-bottom: 2rem; }
  .tabs {
    position: static; max-width: 46rem; margin: 0 auto 1.1rem;
    border: 1px solid var(--border); border-radius: var(--radius);
    padding: .25rem; gap: .25rem;
  }
  .tabs a { flex-direction: row; gap: .45rem; font-size: .84rem; border-radius: 9px; padding: .45rem; }
  .tabs a[aria-current="page"] { background: var(--bg); }
  .pip { position: static; margin: 0 0 0 .1rem; }
  .row { padding: .68rem 1.05rem; }
}

/* ---- Fixes from seeing it at 390px -----------------------------------
 * The attention block carries sentences, not labels, so a single-line
 * ellipsis cut them mid-word ("Chase Freedom Unlimited has go…"). Two lines
 * keeps the meaning; the clamp keeps the row from growing without bound. */
.attention .row > div:first-child > div {
  white-space: normal;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
}
/* The raw bank string is reference, not headline: one line, then stop. */
.review .raw {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  word-break: normal; font-size: .72rem;
}

/* ---- Desktop ----------------------------------------------------------
 * Phone first still holds: below 46rem nothing here applies except rules
 * that hide elements which exist only for wider screens. Every query says
 * "screen" so printing (the PDF export) never sees a desktop rule.
 *   46rem  tablet: today's column, with the tab row moved above the page
 *   64rem  desktop: fixed left sidebar, header strip, column tables
 *   80rem  wide: right-hand rails beside the main column */
.tabs .nav-brand, .tabs .nav-sep, .tabs .nav-targets, .tabs .nav-settings, .tabs .nav-ver { display: none; }

@media screen and (min-width: 46rem) {
  /* The nav is emitted after <main>, so on a long page the tab row was the
     last thing on it. order moves it to the top without moving markup. */
  /* Not denied.html (no-nav): it has no tab row to move, and as a flex
     column its margins would stop collapsing. */
  body.app:not(.no-nav) { display: flex; flex-direction: column; }
  body.app > nav.tabs { order: -1; width: 100%; }
  /* Budget rows had no inset, so their text touched the card edge. */
  .bline { padding-inline: 1.05rem; }
  /* A sign-in card, not a 736px slab. */
  body.centered > main, body.centered > footer { max-width: 26rem; }
  /* Past the phone width the compact chart was sized for, swap in the wide
     one -- its 11px labels have the room here that they do not on a phone. */
  .chart-compact { display: none; }
  .chart-wide { display: block; }
}

@media screen and (min-width: 64rem) {
  /* Fixed rather than sticky: where the nav sits in the DOM stops
     mattering, so no template has to move it. */
  body.app:not(.no-nav) {
    display: block; padding: 0 0 2rem 13rem;
    /* Paints the sidebar column down the whole page, so a full-page
       screenshot or a print preview does not show it ending at 100vh. */
    background: linear-gradient(to right, var(--panel) calc(13rem - 1px), var(--border) calc(13rem - 1px) 13rem, var(--bg) 13rem);
  }
  body.app > nav.tabs {
    position: fixed; top: 0; bottom: 0; left: 0; right: auto; z-index: 20;
    width: 13rem; max-width: none; margin: 0; overflow-y: auto;
    flex-direction: column; gap: 0; padding: 1.25rem 0;
    border: 0; border-right: 1px solid var(--border); border-radius: 0;
  }
  .tabs a {
    flex: 0 0 auto; flex-direction: row; justify-content: flex-start;
    gap: .625rem; padding: .5625rem 1.125rem; min-height: 2.25rem;
    font-size: .8125rem; letter-spacing: 0;
    border-radius: 0; border-left: 2px solid transparent;
  }
  .tabs a:hover { background: var(--raised); }
  .tabs a[aria-current="page"] { background: var(--bg); border-left-color: var(--accent); }
  /* On /budget the phone bar lights Budget; here Targets carries it. */
  .tabs a.nav-also[aria-current="page"] { color: var(--muted); font-weight: 400; background: none; border-left-color: transparent; }
  .tabs a.nav-also[aria-current="page"]:hover { color: var(--text); background: var(--raised); }
  .tabs svg { width: 16px; height: 16px; flex: 0 0 16px; }
  .tabs a span { flex: 1 1 auto; display: flex; align-items: center; gap: .4rem; overflow: visible; }
  .pip { margin: 0 0 0 auto; }
  .tabs .nav-brand {
    display: block; min-height: 0; padding: 0 1.125rem 1.25rem; border: 0;
    font-size: .9375rem; font-weight: 600; color: var(--text);
  }
  .tabs .nav-brand:hover { background: none; }
  .tabs .nav-sep { display: block; height: 1px; background: var(--border); margin: .875rem 1.125rem; }
  .tabs a.nav-targets, .tabs a.nav-settings { display: flex; }
  .tabs .nav-ver { display: block; margin-top: auto; padding: 1rem 1.125rem 0; font-size: .625rem; color: var(--muted); }

  /* Header strip: full width of the content area, ruled off below. */
  body.app:not(.no-nav) > header {
    max-width: none; margin: 0 0 1.5rem; padding: 1.5rem 2rem 1.125rem;
    border-bottom: 1px solid var(--border); align-items: flex-end;
  }
  body.app:not(.no-nav) > header h1 { font-size: 1.5rem; font-weight: 600; letter-spacing: -.015em; }
  body.app:not(.no-nav) > header p { font-size: .8125rem; margin-top: .25rem; }
  body.app:not(.no-nav) > header button { min-height: 2.375rem; padding: .5rem 1rem; font-size: .8125rem; border-radius: 8px; }
  body.app:not(.no-nav) > header .monthnav a { width: 2.375rem; height: 2.375rem; border-radius: 8px; }
  /* Back / Done / Budget read as buttons once they sit alone at the right. */
  body.app:not(.no-nav) > header > a {
    display: inline-flex; align-items: center; min-height: 2.375rem; padding: 0 .875rem;
    border: 1px solid var(--border); border-radius: 8px; color: var(--muted); font-size: .8125rem;
  }
  body.app:not(.no-nav) > header > a:hover { color: var(--text); background: var(--raised); text-decoration: none; }

  /* Left-aligned against the sidebar; the cap only bites past ~1550px. */
  body.app:not(.no-nav) > main,
  body.app:not(.no-nav) > footer { max-width: 80rem; margin-inline: 0; padding-inline: 2rem; }
}

/* ---- Desktop: shared pieces ------------------------------------------
 * .d-only marks markup that exists for the desktop layout alone (table
 * headers, extra cells). It is hidden until 64rem, so a phone never sees
 * it. A hidden header row is still the list's :first-child, which would
 * give the first real row a top border it never had; the second rule
 * takes that border back off. */
.d-only { display: none; }
.card.list > .d-only:first-child + .row { border-top: none; }

@media screen and (min-width: 64rem) {
  .d-only { display: revert; }
  /* Column headings for the tables built from .card.list rows. Sticky, so
     the columns stay named while a long list scrolls under them. */
  .thead, .bhead {
    position: sticky; top: 0; z-index: 1; background: var(--panel);
    padding: .55rem 1.05rem; border-bottom: 1px solid var(--border);
    font-size: .66rem; color: var(--muted); text-transform: uppercase;
    letter-spacing: .09em; font-weight: 600;
  }
  /* A row of summary cards. Children keep their own margin-bottom as the
     row gap, so an empty strip takes no space at all. */
  .strip {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    column-gap: var(--gap); align-items: stretch;
  }
}

@media screen and (min-width: 80rem) {
  /* Main column plus a 312px rail (the wireframe's width). Placement is
     explicit, so blocks never move in the DOM and the phone order holds.
     Rows are "auto 1fr": an item spanning the 1fr row is left out when the
     auto row is sized, so row 1 is exactly as tall as the -top item and
     the -bottom item sits right under it with no gap. */
  .layout {
    display: grid; grid-template-columns: minmax(0, 1fr) 19.5rem;
    grid-template-rows: auto 1fr; column-gap: 1.5rem; align-items: start;
  }
  .layout > .l-main        { grid-column: 1; grid-row: 1 / span 2; min-width: 0; }
  .layout > .l-main-top    { grid-column: 1; grid-row: 1; min-width: 0; }
  .layout > .l-main-bottom { grid-column: 1; grid-row: 2; min-width: 0; }
  .layout > .l-rail        { grid-column: 2; grid-row: 1 / span 2; min-width: 0; }
  .layout > .l-rail-top    { grid-column: 2; grid-row: 1; min-width: 0; }
  .layout > .l-rail-bottom { grid-column: 2; grid-row: 2; min-width: 0; }
  .layout > .l-main > :first-child, .layout > .l-main-top > :first-child,
  .layout > .l-rail > :first-child, .layout > .l-rail-top > :first-child { margin-top: 0; }
  /* Cash and Owed side by side do not fit 312px; stack them. */
  .layout > :is(.l-rail, .l-rail-top, .l-rail-bottom) .split { flex-direction: column; }
  .layout > :is(.l-rail, .l-rail-top, .l-rail-bottom) .split > * { flex: 0 0 auto; }
}

/* ---- Desktop: budget targets table ------------------------------------
 * Each line stays its own <form>; .bline-top dissolves (display:contents)
 * so its name and figures become cells of the form's grid. Named lines
 * let the 80rem layout add Typical without renumbering anything. */
@media screen and (min-width: 64rem) {
  /* clip, not hidden, because hidden breaks the sticky heading. .card.list
     sets hidden at 0,2,0, so the selector must outrank it. */
  .card.list.btable { overflow: clip; }
  .btable > .bhead, .btable > form.bline {
    display: grid; column-gap: 1rem; align-items: center;
    grid-template-columns: [cat] minmax(0, 2fr) [tgt] minmax(5.5rem, 1fr) [spent] minmax(5.5rem, 1fr) [rem] minmax(5.5rem, 1fr) [bar] 5rem [edit] 6.5rem;
  }
  .btable > .bhead > span { grid-row: 1; text-align: right; }
  .btable > .bhead > .h-cat { grid-column: cat; text-align: left; }
  .btable > .bhead > .h-typ { grid-column: typ; }
  .btable > .bhead > .h-tgt { grid-column: tgt; }
  .btable > .bhead > .h-spent { grid-column: spent; }
  .btable > .bhead > .h-rem { grid-column: rem; }
  /* Typical needs the extra width; below 80rem it squeezed Category. */
  .btable .h-typ, .btable .b-typ { display: none; }
  .btable > .bgroup {
    padding: 1rem 1.05rem .35rem; font-size: .6875rem; color: var(--accent);
    text-transform: uppercase; letter-spacing: .09em; font-weight: 600;
  }
  .btable > form.bline { padding: .45rem 1.05rem; min-height: var(--tap); font-size: .9rem; }
  .btable > form.bline > .bline-top { display: contents; }
  .btable > form.bline > *, .btable > form.bline > .bline-top > * { grid-row: 1; }
  .btable .bline-top > div:first-child { grid-column: cat; min-width: 0; }
  .btable .bline-top > div:first-child > div { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* The group is the heading row above; the sentences are the columns. */
  .btable .bline-top > div:first-child > .muted.small,
  .btable > form.bline > .muted.small { display: none; }
  .btable .bcell { text-align: right; white-space: nowrap; }
  .btable .b-typ { grid-column: typ; }
  .btable .b-tgt { grid-column: tgt; }
  .btable .bline-top > span.mono:not(.bcell) { grid-column: spent; text-align: right; }
  .btable .b-rem { grid-column: rem; }
  .btable > form.bline > .bar { grid-column: bar; margin: 0; }
  .btable > form.bline > .bline-edit { grid-column: edit; margin: 0; justify-self: end; }
  .btable .bline-edit > summary { white-space: nowrap; }
  /* Opened, the editor takes a second row under the line, right-aligned. */
  .btable > form.bline > .bline-edit[open] { grid-column: 1 / -1; grid-row: 2; width: min(22rem, 100%); text-align: right; }
  .btable > form.bline > .bline-edit[open] .bline-set { margin: 0 0 .35rem; }
  span.tag {
    display: inline-block; margin-left: .5rem; padding: 0 .4rem; border: 1px solid currentColor;
    border-radius: 999px; font-size: .5625rem; font-weight: 600; line-height: 1.1rem;
    text-transform: uppercase; letter-spacing: .04em; vertical-align: .1em;
  }
}
@media screen and (min-width: 80rem) {
  .btable > .bhead, .btable > form.bline {
    grid-template-columns: [cat] minmax(0, 2fr) [typ] minmax(5.5rem, 1fr) [tgt] minmax(5.5rem, 1fr) [spent] minmax(5.5rem, 1fr) [rem] minmax(5.5rem, 1fr) [bar] 6rem [edit] 6.5rem;
  }
  .btable .h-typ, .btable .b-typ { display: block; }
}

/* ---- Desktop: activity table ----------------------------------------- */
@media screen and (min-width: 64rem) {
  /* clip, not hidden, because hidden breaks the sticky heading. .card.list
     sets hidden at 0,2,0, so the selector must outrank it. */
  .card.list.txlist { overflow: clip; }
  .txlist > .thead, .txlist > a.row {
    display: grid; column-gap: 1rem; align-items: center;
    grid-template-columns: 6.5rem minmax(0, 2fr) minmax(0, 1.3fr) minmax(0, 1.3fr) 8rem;
  }
  .txlist > .thead > :last-child { text-align: right; }
  .txlist > a.row { padding-block: .45rem; font-size: .9rem; }
  .txlist > a.row > div:first-child { display: none; }   /* the phone's stacked layout */
  .txlist > a.row > span { grid-row: 1; min-width: 0; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .txlist > a.row > span.a-date { grid-column: 1; font-size: .8125rem; }
  .txlist > a.row > span.a-payee { grid-column: 2; }
  .txlist > a.row > span.a-acct { grid-column: 3; font-size: .8125rem; }
  .txlist > a.row > span.a-cat { grid-column: 4; font-size: .8125rem; }
  .txlist > a.row > span.a-amt { grid-column: 5; text-align: right; }
  /* Four selects fit one line here; stacked they pushed the list down. */
  .filter-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ---- Desktop: review queue -------------------------------------------
 * What you read on the left, what you decide on the right, so the eye
 * stays in one lane and the pointer in the other. */
@media screen and (min-width: 64rem) {
  form.review {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem);
    column-gap: 1.5rem; align-items: center; padding-inline: 1.05rem;
  }
  form.review > * { grid-column: 1; }
  form.review > .review-actions { grid-column: 2; grid-row: 1 / span 3; margin-top: 0; }
}

/* ---- Desktop: Due page ------------------------------------------------ */
@media screen and (min-width: 64rem) {
  /* Base rule (near .due-when above) already fixes the phone squeeze;
     desktop just gets a touch more room. */
  .row > div.due-when { flex: 0 0 4.5rem; }
}

/* ---- Desktop: reports -------------------------------------------------
 * The SVGs scale with their card. Past 56rem the 11px axis labels grow past
 * body text; two charts per row would shrink them to about 8px. So one
 * column, capped. */
@media screen and (min-width: 64rem) {
  .charts { max-width: 56rem; }
}

/* ---- Ask -------------------------------------------------------------- */
/* Sidebar-only, like Targets: on a phone Ask is the box on Home. */
.tabs .nav-ask { display: none; }
@media screen and (min-width: 64rem) {
  .tabs a.nav-ask { display: flex; }
  /* An answer is prose: at desktop widths its lines would run past 110
     characters. The column stays readable; the header strip stays wide. */
  body.app:not(.no-nav) > main.ask { max-width: 46rem; margin-inline: 0; }
}
.ask-box { margin-bottom: var(--gap); }
/* A thread is titled by its first question, which can run to 80
   characters; at page-heading size that is three lines of shouting. */
body.app > header.ask-head h1 { font-size: 1.15rem; line-height: 1.35; }
.ask-box label a, .ask-form label a { color: var(--link); }
.ask-form { margin: var(--gap) 0; }
/* The question reads as the person's own words, set apart from the answer
   the way a message thread does it, without pretending to be a chat app. */
.ask-q {
  margin: 1rem 0 .6rem auto; max-width: 85%; width: fit-content;
  background: var(--raised); border: 1px solid var(--border); border-radius: var(--radius);
  padding: .55rem .8rem;
}
.ask-a { line-height: 1.55; }
.ask-a p, .ask-a ul, .ask-a ol { margin-bottom: .65rem; }
.ask-a ul, .ask-a ol { padding-left: 1.25rem; }
.ask-a li + li { margin-top: .25rem; }
.ask-a a { color: var(--link); }
/* Once an answer is finished, the "Checking your budget…" lines have done
   their job; "Used:" below the answer says the same thing in one line. */
.ask-live:has(.ask-done) .ask-status { display: none; }
.ask-used { margin-top: -.2rem; }
.ask-starters { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: var(--gap); }
.ask-starters .chip {
  background: var(--panel); color: var(--text); border: 1px solid var(--border);
  font-weight: 400; font-size: .85rem; white-space: normal; text-align: left;
}
.ask-about { margin-bottom: var(--gap); }
.ask-clear { margin-top: .5rem; }
.ask-clear > summary { font-size: .8rem; color: var(--muted); cursor: pointer; }

/* ---- Sync problems ---------------------------------------------------- */
/* A run's problem is a sentence from the bank feed ("Capital One: connection
   needs attention"). Cut off with an ellipsis it says nothing, so it wraps. */
.row > div:first-child > .run-problem { white-space: normal; overflow: visible; overflow-wrap: anywhere; margin-top: .15rem; }

/* ---- Activity: sort ---------------------------------------------------- */
/* Label and control in two columns, one pair per row on a phone, so "Sort"
   never ends up stranded at the end of the "Show" row. */
.filter-sort { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: .5rem .6rem; margin-top: .6rem; }
.filter-sort label { margin: 0; }
.filter-sort select { margin: 0; width: 100%; }
.filter-sort .link { grid-column: 2; justify-self: start; }
@media screen and (min-width: 46rem) {
  .filter-sort { grid-template-columns: auto minmax(0, 14rem) auto minmax(0, 14rem) auto; }
  .filter-sort .link { grid-column: auto; }
}
/* A grid item's minimum width is its content, and a select is as wide as
   its longest option: "Groceries · Food & dining" pushed the whole panel
   past the card edge on a phone. */
.filter-grid > * { min-width: 0; }

/* ---- Activity: ranges -------------------------------------------------- */
.filter-pair { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: .5rem; }
.filter-pair label { margin-bottom: .15rem; }
/* A date input has a wide built-in minimum; without width and max-width it
   ignores min-width: 0 and runs past the card on a phone. */
.filter-pair input { margin: 0; min-width: 0; width: 100%; max-width: 100%; }
.filter-quick { color: var(--muted); }
.filter-grid .filter-quick { grid-column: 1 / -1; }
.breakdown-sort { margin: 0 0 var(--gap); }


/* ---- Activity: filter chips -------------------------------------------- */
.chips { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; margin-bottom: var(--gap); }
.chip {
  display: inline-flex; align-items: center; gap: .3rem; min-height: 2rem;
  padding: .2rem .65rem; border: 1px solid var(--border); border-radius: 999px;
  background: var(--panel); color: var(--text); font-size: .82rem; text-decoration: none;
}
.chip span { color: var(--muted); }
@media (hover: hover) { .chip:hover { border-color: var(--accent); } }

/* Accounts, grouped: an account left out of every total still shows,
   dimmed, so it is never silently missing. */
.row.left-out { opacity: .6; }
/* "It's right, count it" under a balance that doesn't add up: clear of
   the label above it. */
.stat form.trust { margin: .7rem 0 0; }
/* "It's +$X" / "It's −$X": two equal choices side by side. */
.stat form.sign-pick { display: flex; flex-wrap: wrap; gap: .5rem; }
/* The account form's "Right now it is": a plain group, no box. */
fieldset.sign-now { border: 0; padding: 0; margin: .25rem 0 .5rem; }
fieldset.sign-now legend { padding: 0; color: var(--muted); }
fieldset.sign-now label.check { margin: .35rem 0; }
.section-head > .mono { font-size: .85rem; }
a.card.stat { display: block; color: inherit; text-decoration: none; }
label.check { display: flex; align-items: center; gap: .5rem; font-size: .9rem; color: var(--text); margin: .75rem 0 .25rem; }
label.check input { width: auto; margin: 0; }
/* A second, quieter action beside a primary one. */
button.secondary { background: transparent; color: var(--accent); border: 1px solid var(--accent); }

/* ---- Screens ---- */
/* A header with two actions (Accounts: Sync now and Settings). The title
   gives way, so the actions stay on its line instead of wrapping under it;
   on a phone the subtitle takes the whole next line rather than wrapping
   in what is left beside them. */
header.head-two > div:first-child { flex-basis: 0; }
@media screen and (max-width: 45.99rem) {
  header.head-two { align-items: center; row-gap: .2rem; }
  header.head-two > div:first-child { display: contents; }
  header.head-two h1 { flex: 1 1 0; min-width: 0; }
  header.head-two > div:first-child > p { order: 1; flex: 1 0 100%; }
}

/* People's fold of past invitations, and Accounts' fold of hidden
   accounts: a disclosure that reads as one, as "Show N more payees" does. */
.past-invites > summary, .hidden-accts > summary { display: inline-flex; align-items: center; min-height: var(--tap);
  font-size: .8rem; color: var(--accent); cursor: pointer; list-style: none; }
.past-invites > summary::-webkit-details-marker, .hidden-accts > summary::-webkit-details-marker { display: none; }
.past-invites > summary::after, .hidden-accts > summary::after { content: " \203A"; margin-left: .3rem; }
.past-invites[open] > summary::after, .hidden-accts[open] > summary::after { content: " \2039"; }
.hidden-accts { margin-top: 1rem; }
.acct-hide p { margin: 0 0 .7rem; }

/* The Monarch export import (/import, /import/compare, /import/rows). */
.row-button > .row-label.spread { justify-content: space-between; gap: .7rem; }
.imp-upload p { margin: .7rem 0 0; }
.imp-summary p { margin: 0; line-height: 1.6; }
.imp-head { padding: .7rem var(--pad) .35rem; }
.imp-name { font-weight: 600; overflow-wrap: anywhere; }
.imp-map { margin-top: .15rem; overflow-wrap: anywhere; }
.imp-head label:not(.check) { margin-top: .5rem; }
.imp-head select { margin-bottom: .2rem; }
.imp-head label.check { margin: .45rem 0 .2rem; }
.imp-acct > .row { border-top: 1px solid var(--border); }
.imp-go button:not(.link) { width: 100%; }
.imp-go button[disabled] { opacity: .5; cursor: default; }
.imp-links { display: flex; gap: 1.2rem; justify-content: center; }
.imp-go p { margin: .4rem 0 0; }
/* A row with its box in front: the text still shortens, the amount not. */
.imp-row { justify-content: flex-start; }
.imp-row > input[type=checkbox] { width: auto; min-height: 0; margin: 0; flex: 0 0 auto; }
.imp-row > div { min-width: 0; flex: 1; }
.imp-row > div > div { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.imp-row > div > .imp-cand { padding-left: .8rem; }
.imp-save { margin-top: var(--gap); }

/* ---- Footer at the foot of the window -------------------------------- */
/* On a short page the footer sat just under the content, halfway up the
   screen. A flex column lets margin-top: auto push it to the bottom; the
   nav is fixed (phone, desktop) or ordered first (tablet), so it is
   unaffected. Not denied.html (no-nav), whose margins must keep
   collapsing. */
body.app:not(.no-nav) { display: flex; flex-direction: column; }
body.app:not(.no-nav) > footer { margin-top: auto; padding-top: 1.6rem; }

/* ---- Payoff (/debts) --------------------------------------------------
 * The controls: the extra and Update on one line, the two strategy buttons
 * above them. Update is first in the markup, so Enter in the field keeps
 * the strategy; order puts the pair on top. */
.payoff-pick { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .6rem; }
.payoff-pick .pp-strategy { order: -1; flex: 1 0 100%; display: flex; gap: .5rem; }
.payoff-pick .pp-strategy button { flex: 1 1 0; min-width: 0; padding-inline: .4rem; }
.payoff-pick button[aria-pressed="false"] { background: transparent; color: var(--accent); border: 1px solid var(--accent); }
.payoff-pick .pp-extra { flex: 1 1 8rem; min-width: 0; }
.payoff-pick .pp-extra input { margin: 0; }
/* In the right rail the pair does not fit side by side; stack it. */
@media screen and (min-width: 80rem) {
  .layout > .l-rail-top .payoff-pick .pp-strategy { flex-direction: column; }
}
/* The debts and the months: real tables, figures right, names left. */
.ptable table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.ptable th, .ptable td { text-align: right; padding: .55rem var(--pad); white-space: nowrap; vertical-align: top; }
.ptable th:first-child, .ptable td:first-child { text-align: left; white-space: normal; }
.ptable thead th {
  font-size: .66rem; color: var(--muted); text-transform: uppercase;
  letter-spacing: .09em; font-weight: 600; border-bottom: 1px solid var(--border);
}
.ptable tbody tr + tr > td { border-top: 1px solid var(--border); }
.ptable td.pm-wide, .ptable th.pm-wide { text-align: left; }
/* On a phone a debt is a block: its name and where its balance comes from,
   then its five figures, each under its column's name. The months keep
   their columns, with the target under the month. */
.pm-wide { display: none; }
@media screen and (max-width: 45.99rem) {
  .ptable.stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .ptable.stack table, .ptable.stack tbody { display: block; }
  .ptable.stack tr { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .45rem .7rem; padding: .7rem var(--pad); }
  .ptable.stack tbody tr + tr { border-top: 1px solid var(--border); }
  .ptable.stack td, .ptable.stack tbody tr + tr > td { display: block; padding: 0; border: 0; text-align: left; white-space: normal; }
  .ptable.stack td:first-child { grid-column: 1 / -1; }
  .ptable.stack td[data-label]::before {
    content: attr(data-label); display: block; font-family: inherit;
    font-size: .62rem; color: var(--muted); text-transform: uppercase; letter-spacing: .07em;
  }
  .ptable:not(.stack) table { font-size: .76rem; }
  .ptable:not(.stack) th, .ptable:not(.stack) td { padding: .5rem .35rem; }
  .ptable:not(.stack) th:first-child, .ptable:not(.stack) td:first-child { padding-left: .7rem; }
  .ptable:not(.stack) th:nth-last-child(2), .ptable:not(.stack) td:nth-last-child(2) { padding-right: .7rem; }
  .pm-narrow { max-width: 5.5rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}
@media screen and (min-width: 46rem) {
  .pm-wide { display: table-cell; }
  .pm-narrow { display: none; }
}
/* A debt left out of the plan: its name is a link, so the row is not. */
.payoff-out > div:first-child > div.acct-warn { white-space: normal; }
/* The folds read as Accounts' "Hidden accounts" does. */
.payoff-fold { margin-top: .4rem; }
.payoff-fold > summary { display: inline-flex; align-items: center; min-height: var(--tap);
  font-size: .8rem; color: var(--accent); cursor: pointer; list-style: none; }
.payoff-fold > summary::-webkit-details-marker { display: none; }
.payoff-fold > summary::after { content: " \203A"; margin-left: .3rem; }
.payoff-fold[open] > summary::after { content: " \2039"; }
/* The Debts section's strip: its pages as a segmented control, the
   current one filled, as Payoff's strategy buttons are. */
.debts-strip { display: flex; gap: .5rem; margin-bottom: var(--gap); }
.debts-strip a {
  flex: 1 1 0; display: inline-flex; align-items: center; justify-content: center; min-height: var(--tap);
  border: 1px solid var(--accent); border-radius: 10px; color: var(--accent); font-weight: 600; font-size: .9rem;
}
.debts-strip a[aria-current="page"] { background: var(--accent); color: var(--bg); }
.debts-strip a:hover { text-decoration: none; }
@media screen and (min-width: 64rem) { .debts-strip { max-width: 24rem; } }
/* This month: a pay period's head reads first, then its rows. */
.mhead { flex-wrap: wrap; gap: .1rem .6rem; }
.mhead-sums { margin: -.3rem 0 .5rem; color: var(--muted); line-height: 1.6; }
.mhead-sums b { color: var(--text); font-weight: 600; }
.mrow .due-what > div.msub { white-space: normal; }
.mrow .mamt { flex: 0 0 auto; text-align: right; }
.mrow.done .due-what > div:first-child a, .mrow.done .mamt { opacity: .6; }
.mtick input[name="on"] { width: auto; }
/* A bill's tick sits under its name: a bill is a compact line. */
.mtick-bill { margin: 0; }
.mtick-bill button.link { min-height: 2rem; padding: 0; font-size: .8rem; color: var(--accent); text-decoration: none; }
/* A debt's "I paid this" and Untick start under its name, as a bill's do. */
.mrow > .own-change > summary, .mrow > .look-acts { padding-left: calc(var(--pad) + 4.7rem); }
.mrow > .own-change > .look-acts { padding-left: calc(var(--pad) + 4.7rem); }
@media screen and (min-width: 64rem) {
  .mrow > .own-change > summary, .mrow > .look-acts, .mrow > .own-change > .look-acts { padding-left: calc(var(--pad) + 5.2rem); }
}
.mrow > .look-acts button.link { min-height: 2rem; font-size: .8rem; color: var(--accent); text-decoration: none; }
.due-month { padding: 0 0 var(--gap); margin: 0; }
/* A card's promotions, in the account page's rail: the figures wrap
   rather than cut off, and Add starts at the card's edge. */
.promo-row > div:first-child > div { white-space: normal; }
.card.list > .promo-add > summary { padding-left: var(--pad); }
/* Remove on a Payoff row: quiet, under the row's source line. */
.debt-remove button.link { min-height: 2rem; padding: 0; font-size: .8rem; }
.payoff-how ul { padding-left: 1.1rem; font-size: .85rem; }
.payoff-how li { margin-bottom: .45rem; }

/* ---- Pending rows from the mail (docs/plans/email-pending.md) -------- */
/* A label, not an alarm: the muted colour and a hairline, no colour of
   its own. It sits after the payee, which shortens first. */
.row > div:first-child > div.pend-name { display: flex; align-items: center; gap: .4rem; }
.pend-name > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.pend {
  flex: 0 0 auto; padding: 0 .45rem; border: 1px solid var(--border); border-radius: 999px;
  color: var(--muted); font-size: .68rem; line-height: 1.15rem; white-space: nowrap;
}
.pend-note { margin: .35rem 0 0; }
p.pend-note { margin: 0 0 var(--gap); }
.pend-dismiss button { min-height: 2rem; padding: 0; font-size: .8rem; }
/* "0 new transactions · nothing newer from the bank" wraps on a phone
   rather than losing its point to an ellipsis. */
.row > div:first-child > div.run-detail { white-space: normal; }
.pend + .bar, .pend-note + .bar { margin-top: .5rem; }
