/* FundLedger - simple surfaces, futuristic edges. One stylesheet, no framework. */
:root {
  --bg: #070a0f;
  --bg-2: #0c111a;
  --panel: #0e141e;
  --panel-2: #121a26;
  --line: #1c2634;
  --line-2: #26344a;
  --text: #dde5f0;
  --muted: #7b8a9e;
  --accent: #35e0d0;
  --accent-dim: #1d7f78;
  --violet: #8b7bff;
  --good: #3ddc97;
  --warn: #ffc46b;
  --bad: #ff6b81;
  --radius: 10px;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", "JetBrains Mono", Consolas, monospace;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background:
    radial-gradient(900px 500px at 15% -10%, #10202e 0%, transparent 60%),
    radial-gradient(700px 400px at 95% 0%, #191430 0%, transparent 55%),
    var(--bg);
  background-attachment: fixed;
  color: var(--text);
  font: 14px/1.5 "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3 { font-weight: 600; letter-spacing: -0.01em; margin: 0 0 14px; }
h1 { font-size: 21px; }
h2 { font-size: 16px; }
h3 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.09em; color: var(--muted); }

/* ---------------------------------------------------------------- shell */
.topbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 22px;
  padding: 0 22px; height: 56px;
  background: rgba(8, 12, 18, 0.82);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
.brand {
  display: flex; align-items: center; gap: 9px;
  font-weight: 600; font-size: 15px; color: var(--text); letter-spacing: -0.02em;
}
.brand:hover { text-decoration: none; }
/* The mark, where the glowing dot used to be. Its ground is cut away, so no
   corner rounding and no box glow -- either would draw a faint square around a
   shape that has none. The artwork carries its own glow. */
.brand .brandmark { width: 28px; height: 28px; display: block; }
.brand .dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 10px var(--accent);
}
nav { display: flex; gap: 3px; flex: 1; flex-wrap: wrap; }
nav a {
  padding: 7px 12px; border-radius: 8px; color: var(--muted);
  font-size: 13px; font-weight: 500; border: 1px solid transparent;
}
nav a:hover { color: var(--text); background: var(--panel); text-decoration: none; }
nav a.on {
  color: var(--accent); background: rgba(53, 224, 208, 0.07);
  border-color: rgba(53, 224, 208, 0.22);
}
.whoami { color: var(--muted); font-size: 12px; display: flex; align-items: center; gap: 10px; }
.wrap { max-width: 1220px; margin: 0 auto; padding: 26px 22px 70px; }

/* ---------------------------------------------------------------- panels */
.panel {
  background: linear-gradient(180deg, var(--panel) 0%, var(--bg-2) 100%);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  margin-bottom: 18px;
}
.panel > h2:first-child, .panel > h3:first-child { margin-top: 0; }
.grid { display: grid; gap: 18px; }
.g2 { grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); }
.g3 { grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); }
.g4 { grid-template-columns: repeat(auto-fit, minmax(165px, 1fr)); }
.g5 { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
.row { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; }
.spread { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
/* A page heading with buttons beside it: the heading carries a bottom margin of
   its own, so centring the two put the words above the buttons and left the
   buttons all but touching whatever came next. The margin moves to the row, and
   both sit on one line with a proper gap under them. */
.spread > h1 { margin-bottom: 0; }
.spread:has(> h1) { margin-bottom: 18px; }
/* On a phone the two do not fit side by side once the buttons are real words:
   the heading takes its own line and the buttons follow, full width. */
@media (max-width: 560px) {
  .spread:has(> h1) { flex-wrap: wrap; row-gap: 10px; }
  .spread:has(> h1) > h1 { flex: 1 1 100%; }
  .spread:has(> h1) > .row { flex: 1 1 100%; }
  .spread:has(> h1) > .row > .btn { flex: 1 1 0; justify-content: center; }
}

/* stat tiles */
.stat {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px; position: relative; overflow: hidden;
}
.stat::before {
  content: ""; position: absolute; inset: 0 auto auto 0; width: 100%; height: 1px;
  background: linear-gradient(90deg, var(--accent), transparent 70%); opacity: 0.5;
}
.stat .k { font-size: 11px; text-transform: uppercase; letter-spacing: 0.09em; color: var(--muted); }
.stat .v { font-family: var(--mono); font-size: 21px; margin-top: 5px; letter-spacing: -0.02em; }
/* A deal's tiles: one height across the row, so the strip reads as one thing
   rather than four boxes of assorted sizes. The padding is tighter than a
   general tile's, which is what keeps the empty ones from looking cavernous. */
.grid.dealtiles .stat {
  padding: 10px 14px 11px;
  /* one height across the row means the shorter tiles have room under them:
     their few lines sit in the middle of it rather than perched at the top */
  display: flex; flex-direction: column; justify-content: center;
}
/* the pair sits a little below the label it shares a line with, so the words
   and the buttons are not fighting for the same baseline */
/* dropped by eye, not by height: the negative bottom takes back the space the
   nudge would otherwise add to the tile */
.dealbtns { margin-top: 7px; margin-bottom: -7px; align-items: flex-start; }
.grid.dealtiles .bykind { margin-top: 6px; padding-top: 5px; }
.grid.dealtiles .bykind .spread { padding: 2px 0; }

/* the deal in coin: the figure this whole panel is about */
.stat .v.big { font-size: 23px; }
.stat .sub { font-size: 11px; color: var(--muted); margin-top: 3px; font-family: var(--mono); }

/* ---------------------------------------------------------------- tables */
table { width: 100%; border-collapse: collapse; font-size: 13px; }
.scroll { overflow-x: auto; }
th {
  text-align: left; padding: 9px 11px; font-size: 10.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.085em; color: var(--muted);
  border-bottom: 1px solid var(--line-2); white-space: nowrap;
}
td { padding: 10px 11px; border-bottom: 1px solid var(--line); vertical-align: top; }
tbody tr:hover td { background: rgba(53, 224, 208, 0.035); }
tbody tr:last-child td { border-bottom: none; }
.num { font-family: var(--mono); text-align: right; white-space: nowrap; }
/* A deal reference is the way into a deal, so it is a thing to press rather than
   a word to aim at. Bare text a few pixels tall is a poor target on a phone and
   not much better with a mouse; this gives it edges, a surface and room. */
.refchip {
  display: inline-block; padding: 6px 12px; border-radius: 999px;
  font-family: var(--mono); font-size: 13px; letter-spacing: -0.01em;
  color: var(--accent); white-space: nowrap;
  border: 1px solid rgba(53, 224, 208, 0.28);
  background: rgba(53, 224, 208, 0.06);
  transition: background .12s, border-color .12s, box-shadow .12s;
}
.refchip:hover {
  text-decoration: none; border-color: rgba(53, 224, 208, 0.6);
  background: rgba(53, 224, 208, 0.13); box-shadow: 0 0 14px rgba(53, 224, 208, 0.15);
}
body.client .refchip { font-size: 14px; padding: 8px 14px; }

/* A row carries a line per asset. One cell holding a single thing -- a bar, a
   figure -- reads better level with the middle of them than pinned to the top
   of the first. */
td.progcell { vertical-align: middle; }
.dim { color: var(--muted); }
.empty { padding: 26px; text-align: center; color: var(--muted); font-size: 13px; }

/* ---------------------------------------------------------------- pills */
.pill {
  display: inline-block; padding: 2px 9px; border-radius: 999px;
  font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
  border: 1px solid var(--line-2); color: var(--muted); white-space: nowrap;
}
.pill.ok      { color: var(--good);   border-color: rgba(61, 220, 151, 0.35); background: rgba(61, 220, 151, 0.09); }
.pill.pending { color: var(--warn);   border-color: rgba(255, 196, 107, 0.35); background: rgba(255, 196, 107, 0.09); }
.pill.bad     { color: var(--bad);    border-color: rgba(255, 107, 129, 0.35); background: rgba(255, 107, 129, 0.09); }
.pill.info    { color: var(--violet); border-color: rgba(139, 123, 255, 0.35); background: rgba(139, 123, 255, 0.09); }
/* a conversion: green, and its own shade -- it is not an IN and not a transfer */
.pill.convert { color: var(--good);   border-color: rgba(61, 220, 151, 0.4); background: rgba(61, 220, 151, 0.10); }
/* one line per account waiting to be looked at, with its limit box on it */
/* The week a run of daily deals belongs to: a heading inside the list, not a
   row of its own data. Heavy enough to break the list into blocks at a glance. */
.weekrow td {
  background: rgba(139, 123, 255, .13);
  border-top: 2px solid var(--line);
  color: var(--muted);
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  padding: 7px 10px;
}
/* The week's own figures: the same quiet weight as the date beside them. A
   deal's figures are what you read; these only say what the block adds up to. */
.weekrow .bar { height: 4px; opacity: .6; }
.weekrow td.num { font-variant-numeric: tabular-nums; letter-spacing: 0; }
tbody tr.weekrow:first-child td { border-top: 0; }

/* A deal's money read apart by the kind of account it was paid into: the two
   are worked at different rates, so they are never added into one figure. */
/* The two kinds of account, read under the figure they add up to. Close to the
   name they belong to and big enough to read as money, not as a footnote. */
.bykind { margin-top: 7px; border-top: 1px solid var(--line); padding-top: 6px; }
.bykind .spread { font-size: 12.5px; padding: 3px 0; gap: 10px; align-items: center;
                  justify-content: flex-start; }
/* the figure sits beside the name it belongs to, not across the tile from it */
.bykind .spread > span:last-child { margin-left: auto; }
.bykind.tight .spread > span:last-child { margin-left: 0; }
/* the pair of figures on the left, what they come to on the right -- the space
   beside them was empty and the sum was nowhere on the tile */
.bykind.withtotal { display: flex; justify-content: space-between; align-items: flex-end; gap: 14px; }
/* the figures keep their line; only the label beside them may wrap */
.bykind .spread > span:last-child, .kindtotal > div:last-child { white-space: nowrap; }
.bykind.withtotal > div:first-child { flex: 0 0 auto; }
.kindtotal { flex: 1 1 auto; min-width: 0; }
.kindtotal { text-align: right; font-family: var(--mono); font-size: 16.5px;
             letter-spacing: -0.01em; color: var(--text); }
.kindtotal .k { font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.09em;
                color: var(--muted); font-family: inherit; margin-bottom: 2px; }
.bykind .spread > span:last-child { font-family: var(--mono); letter-spacing: -0.01em; }
.bykind .tagbox { font-size: 9.5px; padding: 1px 7px; }
.tagbox.savings { border-color: rgba(53, 224, 208, .45); color: var(--accent-dim); }
.tagbox.current { border-color: rgba(122, 162, 255, .5); color: #9db4ff; }

.newacct { align-items: center; gap: 10px; padding: 5px 0; }
.newacct + .newacct { border-top: 1px solid var(--line); }
.newacct .inline-update { gap: 6px; align-items: center; }

/* A field the books have already answered: shown, not editable. Dimmed rather
   than hidden, because what it says still has to be read before sending. */
input.locked, select.locked {
  background: var(--panel); color: var(--muted); border-style: dashed; cursor: default;
}

/* Lending: money that moved and is coming back. Orange, and a deeper one than
   the amber a pending row wears -- violet is a plain transfer, and the whole
   point of the pill is telling those apart at a glance. */
.pill.lend    { color: #ff9a3c; border-color: rgba(255, 154, 60, 0.5); background: rgba(255, 154, 60, 0.12); }
/* the other half -- the same loan, seen from the side that has to return it */
.pill.lend.back { color: rgba(255, 154, 60, 0.65); border-color: rgba(255, 154, 60, 0.3); background: transparent; }
.pill.in      { color: var(--good);   border-color: rgba(61, 220, 151, 0.3); }
.pill.out     { color: var(--bad);    border-color: rgba(255, 107, 129, 0.3); }
.pos { color: var(--good); }
.neg { color: var(--bad); }

/* progress */
.bar { height: 5px; background: var(--line); border-radius: 3px; overflow: hidden; min-width: 70px; }
.bar > i {
  display: block; height: 100%;
  background: linear-gradient(90deg, var(--accent-dim), var(--accent));
  box-shadow: 0 0 8px rgba(53, 224, 208, 0.5);
}

/* ---------------------------------------------------------------- forms */
label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em;
        color: var(--muted); margin-bottom: 5px; }
input, select, textarea {
  width: 100%; padding: 9px 11px;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--line-2); border-radius: 8px;
  font: inherit; outline: none; transition: border-color .12s, box-shadow .12s;
}
input[type=number], input[inputmode=decimal], .mono { font-family: var(--mono); }
input:focus, select:focus, textarea:focus {
  border-color: var(--accent); box-shadow: 0 0 0 3px rgba(53, 224, 208, 0.13);
}
input::placeholder { color: #4d5b6d; }
textarea { resize: vertical; min-height: 62px; }
.field { flex: 1 1 175px; min-width: 145px; margin-bottom: 12px; }
.field.wide { flex: 1 1 100%; }
.field .err { color: var(--bad); font-size: 11.5px; margin-top: 4px; text-transform: none;
              letter-spacing: 0; }
.field.bad input, .field.bad select { border-color: var(--bad); }
.hint { font-size: 11.5px; color: var(--muted); margin-top: 4px; }

button, .btn {
  display: inline-block; padding: 9px 15px; border-radius: 8px; cursor: pointer;
  font: 500 13px/1.2 inherit; border: 1px solid var(--line-2);
  background: var(--panel-2); color: var(--text); transition: all .12s;
}
button:hover, .btn:hover { border-color: var(--accent-dim); text-decoration: none; }
.btn-primary {
  background: linear-gradient(180deg, rgba(53,224,208,.16), rgba(53,224,208,.06));
  border-color: rgba(53, 224, 208, 0.45); color: var(--accent); font-weight: 600;
}
.btn-primary:hover { box-shadow: 0 0 16px rgba(53, 224, 208, 0.22); }
.btn-deal {
  background: linear-gradient(180deg, rgba(139,123,255,.18), rgba(139,123,255,.06));
  border-color: rgba(139, 123, 255, 0.45); color: var(--violet); font-weight: 600;
}
.btn-deal:hover { box-shadow: 0 0 16px rgba(139, 123, 255, 0.25); }
/* What a debt is: money lent, money borrowed, or the far half of an exchange.
   Small and rounded, because it labels the row rather than shouting at it. */
.tagbox {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  border: 1px solid var(--line-2); color: var(--muted); white-space: nowrap;
}
.tagbox.lent     { color: var(--good);   border-color: rgba(61, 220, 151, 0.45); }
.tagbox.borrowed { color: var(--warn, #ffc46b); border-color: rgba(255, 196, 107, 0.45); }

/* The debt a client owes is a row, not a form the page is built around: the
   account, the slip and the button sit on one line beside the amount. */
.duerow { padding: 8px 0; gap: 10px; align-items: center; }
.duerow + .duerow { border-top: 1px solid var(--line); }
.duerow .inline-update { gap: 6px; align-items: center; flex-wrap: wrap; }
.duerow .proofpick { max-width: 150px; font-size: 11px; }
.duerow .pastezone { display: none; }
.duerow .amt { font-size: 13px; }
.duerow .k { font-size: 10.5px; }

/* money going IN -- green, and heavy enough to find without reading */
/* .btn-sm sets a size of its own, and the narrow-screen rules set another --
   both after this one, so the plus states its own with the same weight */
.btn.btn-add, .btn-sm.btn-add {
  background: linear-gradient(180deg, rgba(61,220,151,.20), rgba(61,220,151,.07));
  border-color: rgba(61, 220, 151, 0.5); color: var(--good);
  font-weight: 800; font-size: 17px; line-height: 1; padding: 4px 12px;
}
.btn.btn-add:hover, .btn-sm.btn-add:hover {
  border-color: rgba(61, 220, 151, 0.75); box-shadow: 0 0 16px rgba(61, 220, 151, 0.25);
}
.btn-sm { padding: 5px 10px; font-size: 12px; }
.btn-danger { color: var(--bad); border-color: rgba(255, 107, 129, 0.35); }
form.inline { display: inline; }

/* ---------------------------------------------------------------- flash */
.flash {
  padding: 11px 15px; border-radius: 9px; margin-bottom: 16px; font-size: 13px;
  border: 1px solid var(--line-2); background: var(--panel);
}
.flash.ok  { border-color: rgba(61, 220, 151, 0.4); color: var(--good);
             background: rgba(61, 220, 151, 0.07); }
.flash.bad { border-color: rgba(255, 107, 129, 0.4); color: var(--bad);
             background: rgba(255, 107, 129, 0.07); }

/* ---------------------------------------------------------------- login */
.login-wrap { min-height: 100vh; display: grid; place-items: center; padding: 20px; }
.login-card { width: 100%; max-width: 358px; }
.login-card .panel { padding: 30px; }
.login-mark {
  text-align: center; margin-bottom: 22px; font-size: 20px; font-weight: 600;
  letter-spacing: -0.02em;
}
.login-mark span { color: var(--accent); text-shadow: 0 0 18px rgba(53, 224, 208, 0.55); }
/* the full lockup carries the name itself, so nothing is written beside it */
.login-logo { display: block; width: 100%; max-width: 300px; margin: 0 auto 2px; }
.login-mark .tag {
  display: block; font-size: 11px; color: var(--muted); font-weight: 400;
  text-transform: uppercase; letter-spacing: 0.16em; margin-top: 7px;
}

/* ---------------------------------------------------------------- misc */
.chain { list-style: none; margin: 0; padding: 0; }
.chain li {
  position: relative; padding: 12px 0 12px 26px; border-bottom: 1px solid var(--line);
}
.chain li:last-child { border-bottom: none; }
.chain li::before {
  content: ""; position: absolute; left: 4px; top: 18px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 8px var(--accent);
}
.chain li.pending::before { background: var(--warn); box-shadow: 0 0 8px var(--warn); }
.chain li::after {
  content: ""; position: absolute; left: 7.5px; top: 28px; bottom: -4px; width: 1px;
  background: var(--line-2);
}
.chain li:last-child::after { display: none; }
.kv { display: grid; grid-template-columns: 155px 1fr; gap: 9px 16px; font-size: 13px; }
.kv dt { color: var(--muted); font-size: 12px; }
.kv dd { margin: 0; font-family: var(--mono); }
.tabs { display: flex; gap: 6px; margin-bottom: 16px; flex-wrap: wrap; }
.tabs a { padding: 7px 14px; border-radius: 8px; border: 1px solid var(--line);
          color: var(--muted); font-size: 13px; }
.tabs a.on { color: var(--accent); border-color: rgba(53, 224, 208, 0.4);
             background: rgba(53, 224, 208, 0.07); }
.hidden, [hidden] { display: none !important; }
/* small tag inside an uppercase h3 - must opt out of the heading's transform */
.only {
  display: inline-block; margin-left: 7px; padding: 2px 7px; border-radius: 999px;
  font-size: 9.5px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: none; color: var(--violet);
  border: 1px solid rgba(139, 123, 255, 0.32); background: rgba(139, 123, 255, 0.08);
  vertical-align: middle;
}
code { font-family: var(--mono); font-size: 12px; color: var(--violet); }

@media (max-width: 720px) {
  .topbar { height: auto; padding: 10px 14px; flex-wrap: wrap; }
  .wrap { padding: 18px 14px 60px; }
  .kv { grid-template-columns: 1fr; gap: 3px 0; }
  .kv dd { margin-bottom: 9px; }
}

/* ---------------------------------------------------------------- review modal */
.modal-back {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center; padding: 20px;
  background: rgba(4, 7, 11, 0.72);
  backdrop-filter: blur(3px);
}
.modal {
  width: 100%; max-width: 310px; max-height: 78vh; overflow-y: auto;
  background: linear-gradient(180deg, var(--panel) 0%, var(--bg-2) 100%);
  border: 1px solid var(--line-2); border-radius: 12px; padding: 15px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.7);
}
.modal h2 { font-size: 13.5px; margin: 0 0 11px; }
.modal-list { grid-template-columns: 42% 1fr; gap: 5px 10px; font-size: 12px; }
.modal-list dt {
  color: var(--muted); font-size: 11px;
  border-bottom: 1px solid var(--line); padding-bottom: 5px;
}
.modal-list dd {
  margin: 0; font-family: var(--mono); font-size: 12px; word-break: break-word;
  border-bottom: 1px solid var(--line); padding-bottom: 5px;
}
.modal .row { gap: 7px; margin-top: 13px !important; }
.modal button { padding: 6px 11px; font-size: 12px; }
input:disabled, select:disabled {
  opacity: .62; cursor: not-allowed; background: var(--bg-2);
}

/* ------------------------------------------------- one-tap action rows
   Approve / Confirm live here. A table would push the button off the right of a
   phone screen and force a sideways scroll before it could be tapped, so these
   rows wrap instead: the button is always reachable at any width. */
.actionrow {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
  padding: 11px 0; border-bottom: 1px solid var(--line);
}
.actionrow:last-child { border-bottom: none; padding-bottom: 0; }
.actioninfo { flex: 1 1 210px; min-width: 0; }
.actioninfo > div { line-height: 1.45; }
.actionbtns { display: flex; gap: 7px; flex: 0 0 auto; }
.actionbtns button, .actionbtns .btn { padding: 8px 16px; }
@media (max-width: 560px) {
  .actionbtns { width: 100%; }
  .actionbtns form { flex: 1 1 auto; }
  .actionbtns button { width: 100%; }        /* full-width tap target on a phone */
}

/* ------------------------------------------------- holder rows (Accounts)
   Reads as one table: a header strip, then a row per holder with a divider
   between. Each row is a <details> so it opens to show that holder's accounts --
   native element, no JavaScript. Header and rows share one grid template, which
   is what keeps the columns lined up down the page. */
.holderhead, .holder > summary {
  display: grid;
  grid-template-columns: minmax(150px, 2.2fr) 92px 90px minmax(120px, 1fr) minmax(120px, 1fr);
  align-items: center;
  gap: 12px;
}
.holderhead {
  padding: 2px 11px 10px;
  font-size: 10.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.085em; color: var(--muted);
  border-bottom: 1px solid var(--line-2);
}
.holder { border-bottom: 1px solid var(--line); }
.holder:last-child { border-bottom: none; }
.holder > summary {
  cursor: pointer; list-style: none; user-select: none;
  padding: 12px 11px; border-radius: 8px; transition: background .12s;
}
.holder > summary::-webkit-details-marker { display: none; }
.holder > summary:hover { background: rgba(53, 224, 208, 0.035); }
.holder > summary:hover .hname { color: var(--accent); }
.holder[open] > summary { background: rgba(53, 224, 208, 0.05); }
.hname { position: relative; padding-left: 16px; font-weight: 600; font-size: 14px; }
.hname::before {
  content: "▸"; position: absolute; left: 0; color: var(--muted);
  font-size: 10px; transition: transform .12s; display: inline-block;
}
.holder[open] .hname::before { transform: rotate(90deg); color: var(--accent); }
.holder > summary .num { font-size: 13.5px; }
.hcount { font-size: 12.5px; }
.holderbody {
  margin: 0 11px 14px; padding: 4px 14px 0;
  border-left: 2px solid var(--line-2);
}
@media (max-width: 720px) {
  .holderhead { display: none; }
  .holder > summary { grid-template-columns: 1fr auto; row-gap: 4px; }
  .holder > summary .num { text-align: right; }
  .hcount { grid-column: 1; }
  .holderbody { margin-left: 0; padding-left: 8px; }
}

/* ------------------------------------------------- assets reported apart
   INR and USDT are different things and are never added together, so the
   dashboard gives each its own line and its own total. */
.assetline {
  display: flex; align-items: baseline; gap: 8px;
  font-family: var(--mono); font-size: 13px; margin-top: 6px;
}
.assetline .alabel {
  font-size: 9.5px; letter-spacing: 0.08em; color: var(--muted);
  min-width: 32px; font-family: inherit;
}
.assettotal {
  font-size: 20px; margin: -4px 0 12px;
  padding-bottom: 10px; border-bottom: 1px solid var(--line-2);
  text-align: left;
}
h3 .atag { margin-left: 6px; vertical-align: middle; }
.atag {
  font-size: 10px; font-weight: 700; letter-spacing: 0.1em; color: var(--accent);
  padding: 2px 8px; border-radius: 999px;
  border: 1px solid rgba(53, 224, 208, 0.3); background: rgba(53, 224, 208, 0.07);
}

/* ------------------------------------------------- dashboard side column
   The check queue is the one part of the dashboard you act on, so it sits in
   its own column and stays put while the ledger scrolls beside it. */
.dashgrid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: 18px;
  align-items: start;
}
/* a grid column will not shrink below its content unless told to, and the
   tables inside are wide -- without this the page scrolls sideways on a phone */
.dashmain, .dashside { min-width: 0; }
.dashside > .panel {
  position: sticky; top: 74px;
  max-height: calc(100vh - 100px); overflow-y: auto;
}
/* the column is narrow, so its rows stack instead of squeezing. the info block
   must stop growing once stacked, or flex stretches it down the whole row */
.dashside .actionrow { flex-direction: column; align-items: stretch; gap: 8px; }
.dashside .actioninfo { flex: 0 0 auto; }
.dashside .actionbtns { width: 100%; }
.dashside .actionbtns form { flex: 1 1 auto; }
.dashside .actionbtns button { width: 100%; }
@media (max-width: 1080px) {
  .dashgrid { grid-template-columns: minmax(0, 1fr); }
  .dashside > .panel { position: static; max-height: none; }
}

/* an amount larger than the account holds, flagged while it is typed */
input.overdrawn { border-color: var(--bad); box-shadow: 0 0 0 3px rgba(255,107,129,.12); }

/* Confirmation that floats over the page. A banner inserted into the flow would
   push whatever you are reading down the screen every time you press a button. */
.toast {
  position: fixed; left: 50%; bottom: 22px; transform: translate(-50%, 8px);
  padding: 10px 18px; border-radius: 999px; font-size: 13px; z-index: 60;
  border: 1px solid rgba(61, 220, 151, 0.4); color: var(--good);
  background: var(--panel); box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
  opacity: 0; pointer-events: none; transition: opacity .15s, transform .15s;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.bad  { border-color: rgba(255, 107, 129, 0.4); color: var(--bad); }

/* A statement reads in two columns: what left on the left, what arrived on the
   right. Each figure carries its own asset, because a conversion moves two. */
.money { white-space: nowrap; vertical-align: top; }
.money .acct { font-size: 11px; color: var(--dim); font-weight: 400; }
.money .waiting { opacity: .55; }
.money .waiting .acct::after { content: " · awaited"; }
.money.debit  { border-right: 1px solid var(--line); }
/* Update a wallet in place -- typing the real figure where the old one is shown
   is less work than opening a form to say the same thing. */
.inline-update { display: flex; gap: 6px; justify-content: flex-end; }
.inline-update input { width: 108px; padding: 5px 8px; font-size: 12.5px; text-align: right; }
.inline-update .btn { padding: 5px 11px; font-size: 12.5px; }

/* The check queue holds three different asks, and they used to look identical:
   something a client already moved, something not yet counted, and a debt still
   to be released. A colour down the edge tells them apart before you read. */
.actionrow.kind-posted      { border-left: 3px solid var(--violet); padding-left: 11px; }
.actionrow.kind-unconfirmed { border-left: 3px solid var(--warn);   padding-left: 11px; }
.actionrow.kind-due         { border-left: 3px solid var(--good);   padding-left: 11px; }

.kindtag { font-size: 10.5px; letter-spacing: .04em; text-transform: uppercase;
           padding: 2px 7px; border-radius: 5px; white-space: nowrap; }
.kindtag.posted      { color: var(--violet); background: rgba(139, 123, 255, 0.12); }
.kindtag.unconfirmed { color: var(--warn);   background: rgba(255, 196, 107, 0.12); }
.kindtag.due         { color: var(--good);   background: rgba(61, 220, 151, 0.12); }
/* A standing ask -- nothing has moved, so it gets its own colour rather than
   sitting among the things that need confirming. */
.actionrow.kind-ask { border-left: 3px solid var(--accent); padding-left: 11px; }

/* Column headings double as the sort control -- the thing you want to sort by is
   already the thing you are looking at. */
.sorth { color: inherit; text-decoration: none; display: inline-flex; gap: 4px; }
.sorth:hover { color: var(--text); }
.sorth.on { color: var(--accent); }
.sorth .arrow { font-size: 10px; opacity: .8; }

/* Queue rows: what left and what arrived, side by side and coloured, so a
   conversion is not approved on the strength of one of its two figures. */
.qlegs { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 5px 0 2px; }
.qleg { display: inline-flex; gap: 6px; align-items: baseline; font-family: var(--mono, monospace);
        font-size: 12.5px; border-left: 2px solid transparent; padding-left: 7px; }
.qleg.credit { border-left-color: rgba(61, 220, 151, 0.5); }
.qleg.debit  { border-left-color: rgba(255, 107, 129, 0.5); }
.qleg .acct { font-size: 11px; color: var(--muted); font-family: inherit; }
/* Who is sending and who is receiving, above the figures. A queue row is read
   in that order: whose money, then how much. */
.qwho { font-size: 13px; font-weight: 500; margin: 2px 0 6px; letter-spacing: -0.01em; }
/* Asking a client to confirm a transfer is a question, not the page. Half the
   size of an ordinary panel: tighter rows, smaller slip, and the heading in the
   same key as the ones around it. */
.told { padding: 12px 14px; border-color: rgba(53, 224, 208, 0.3); }
.told h3 { margin-bottom: 8px; }
.told .actionrow { padding: 8px 0; }
.told .qwho { font-size: 12.5px; margin: 0 0 3px; }
.told .qleg { font-size: 12.5px; }
.told .actionrow { align-items: center; }
.told-slip { margin: 0 10px 0 0; flex: 0 0 auto; }
.told .proof { width: 46px; height: 46px; border-radius: 6px; }
.told .qleg { padding: 0; }
/* Keeping the slip, beside looking at it. Small, but a real target: on a phone
   this is what somebody presses before ringing their bank. */
.told-slip { display: flex; align-items: center; gap: 6px; }
.slipdl {
  width: 26px; height: 26px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-2); border-radius: 7px;
  color: var(--text); font-size: 14px; line-height: 1; text-decoration: none;
  background: var(--panel-2);
}
/* The name behind an account number, once it has been checked. Green, because
   it is the thing a client reads back before sending real money. */
.hint.verified { color: var(--good); font-weight: 600; }

.slipdl:hover { color: var(--accent); border-color: var(--accent-dim); text-decoration: none; }
@media (max-width: 720px) { .slipdl { width: 32px; height: 32px; font-size: 15px; } }
.told .actionbtns button { min-height: 32px; padding: 6px 13px; font-size: 12.5px; }
body.client .told, body.client .told .qwho { font-size: 13px; }

/* The answer to the one question the row asks, pushed to the far right of its
   head: a row that has been answered should say so before it is read. */
.answer {
  margin-left: auto; font-size: 10.5px; font-weight: 700; letter-spacing: 0.07em;
  padding: 3px 9px; border-radius: 999px; white-space: nowrap;
}
.answer.yes     { color: var(--good); border: 1px solid rgba(61, 220, 151, 0.45);
                  background: rgba(61, 220, 151, 0.12); }
.answer.no      { color: var(--bad);  border: 1px solid rgba(255, 107, 129, 0.45);
                  background: rgba(255, 107, 129, 0.12); }
.answer.waiting { color: var(--muted); border: 1px solid var(--line-2); }

/* What was done, as the row's heading. The direction pill describes the shape of
   a movement; this says what job it was. */
.qhead { font-weight: 600; font-size: 13.5px; letter-spacing: .01em;
         display: flex; flex-wrap: wrap; gap: 7px; align-items: center; margin-bottom: 3px; }

/* A tick-box that reveals a row of fields, rather than a row that is always
   there asking about something most movements do not have. */
.checkline { display: inline-flex; align-items: center; gap: 8px; margin: 4px 0 10px;
             font-size: 13px; color: var(--muted); cursor: pointer; }
.checkline input { width: 15px; height: 15px; accent-color: var(--accent); }

/* What was done, in the colours of the thing itself. This is what you scan for,
   so it leads; whether it was confirmed or checked is bookkeeping about it and
   sits underneath in small grey type. */
.act { display: inline-block; padding: 3px 9px; border-radius: 6px; font-size: 11.5px;
       font-weight: 700; letter-spacing: .06em; border: 1px solid transparent; }
.act-transfer      { color: var(--violet); background: rgba(139,123,255,.13); border-color: rgba(139,123,255,.35); }
.act-convert       { color: var(--accent); background: rgba(53,224,208,.13);  border-color: rgba(53,224,208,.35); }
.act-new-deal      { color: var(--good);   background: rgba(61,220,151,.13);  border-color: rgba(61,220,151,.35); }
.act-released      { color: var(--good);   background: rgba(61,220,151,.10);  border-color: rgba(61,220,151,.3); }
.act-request       { color: var(--warn);   background: rgba(255,196,107,.13); border-color: rgba(255,196,107,.35); }
.act-wallet-update { color: #7fb2ff;       background: rgba(127,178,255,.13); border-color: rgba(127,178,255,.35); }
.act-entry         { color: var(--muted);  background: rgba(123,138,158,.12); border-color: rgba(123,138,158,.3); }

/* the status that used to shout */
.subtle { font-size: 10.5px; color: var(--muted); margin-top: 4px; letter-spacing: .03em; }
.qhead .pill, .qhead .kindtag { font-weight: 400; opacity: .85; }
/* the two sides of a request are the choice being made, so they read as a choice */
#sidetabs a { font-weight: 700; letter-spacing: .06em; }
/* the tabs are choices, not links -- no underline on hover */
.tabs a, .tabs a:hover, .tabs a:focus { text-decoration: none; }

/* A searchable dropdown: an input that filters the real <select> behind it.
   The select still submits and is still what other scripts read. */
.ss { position: relative; }
.ss-hidden { position: absolute; opacity: 0; pointer-events: none; height: 0; width: 0; }
.ss-input { width: 100%; }
.ss-list { position: absolute; z-index: 40; left: 0; right: 0; top: 100%; margin-top: 4px;
           max-height: 260px; overflow-y: auto; background: var(--panel-2);
           border: 1px solid var(--line-2); border-radius: 9px;
           box-shadow: 0 10px 28px rgba(0,0,0,.45); }
.ss-opt { padding: 8px 11px; font-size: 13px; cursor: pointer; }
.ss-opt:hover, .ss-opt.on { background: rgba(53,224,208,.12); color: var(--text); }
.ss-none { padding: 8px 11px; font-size: 12.5px; color: var(--muted); }

/* Charges: money the deal cost somebody. Red down the edge so it reads apart
   from the figures that describe what it made. */
/* A tile holding its place until it is given something to say. */
.stat.empty-slot { background: none; border-style: dashed; opacity: .35; }

.stat.charges { border-left: 3px solid rgba(255, 107, 129, 0.55); }
.stat.charges .v { color: var(--bad); }
.act-charge { color: var(--bad); background: rgba(255,107,129,.13);
              border-color: rgba(255,107,129,.35); }
/* and the same in the chain, so a charge leg is not mistaken for a movement */
/* A charge hangs off the leg above it: the red bar says so. It keeps the same
   text indent as every other row -- shifting it left dragged the words over the
   dot and left the column ragged -- and gives up the dot, since the bar is
   already its marker. */
.chain li.charge {
  border-left: 3px solid rgba(255, 107, 129, 0.45);
  padding-left: 23px;                     /* 3px border + 23 = the 26px others use */
}
.chain li.charge::before { display: none; }
.chain li.charge::after { left: 4.5px; }
/* a pager arm with nowhere to go */
.btn.off { opacity: .35; pointer-events: none; }

/* ---------------------------------------------------------------- proof */
.proofs { display: flex; flex-wrap: wrap; gap: 10px; }
.proof {
  position: relative; width: 132px; height: 132px; border-radius: 9px;
  overflow: hidden; border: 1px solid var(--line); background: var(--panel-2);
}
.proof img { width: 100%; height: 100%; object-fit: cover; cursor: zoom-in; display: block; }
.proof .doc {
  display: flex; align-items: center; justify-content: center; height: 100%;
  padding: 10px; font-size: 11px; text-align: center; word-break: break-all;
}
.proof .dl {
  position: absolute; right: 6px; bottom: 6px; width: 26px; height: 26px;
  display: flex; align-items: center; justify-content: center; border-radius: 7px;
  font-size: 14px; line-height: 1; text-decoration: none; color: var(--text);
  background: rgba(10, 14, 20, 0.78); border: 1px solid var(--line-2);
}
.proof .dl:hover { color: var(--accent); border-color: var(--accent-dim); }

#lightbox {
  position: fixed; inset: 0; z-index: 60; display: flex; cursor: zoom-out;
  align-items: center; justify-content: center; padding: 28px;
  background: rgba(4, 7, 11, 0.88);
}
#lightbox[hidden] { display: none; }
#lightbox img {
  max-width: 100%; max-height: 100%; border-radius: 10px;
  border: 1px solid var(--line-2);
}
.proof .rm {
  position: absolute; right: 5px; top: 5px; width: 24px; height: 24px; padding: 0;
  display: flex; align-items: center; justify-content: center; border-radius: 7px;
  font-size: 15px; line-height: 1; color: var(--bad);
  background: rgba(10, 14, 20, 0.82); border: 1px solid rgba(255, 107, 129, 0.35);
}
.proof .rm:hover { background: rgba(255, 107, 129, 0.18); }

/* proof picked inside a one-line action row */
.inline-update { flex-wrap: wrap; align-items: center; }
.inline-update .proofpick { width: auto; text-align: left; font-size: 11.5px; max-width: 190px; }
.inline-update .proofs { flex-basis: 100%; justify-content: flex-end; margin-top: 6px; }
.inline-update .proof { width: 78px; height: 78px; }
.inline-update .proof .rm { width: 20px; height: 20px; font-size: 13px; }
.nowrap { white-space: nowrap; }
.nowrap form + form { margin-left: 5px; }

/* A box whose value is decided for you: shown, but plainly not yours to type in */
input.locked, select.locked {
  color: var(--muted); background: var(--panel); border-style: dashed;
  pointer-events: none; user-select: none;
}

/* an amount box with a Max beside it */
/* "Max" sits inside the amount box, at its right edge -- beside it, it read as
   a second field and left a gap in the row. */
.withmax { position: relative; display: block; }
.withmax input { width: 100%; padding-right: 66px; }
.withmax .btn {
  position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
  padding: 4px 10px; font-size: 11.5px; line-height: 1.3;
}
.hint.overpct { color: var(--bad); }
/* a row whose fields carry hints: line the boxes up, not their bottoms */
.row.top { align-items: flex-start; }
/* a value that was decided elsewhere: shown, not asked for */
.fixedvalue {
  padding: 9px 12px; border: 1px dashed var(--line-2); border-radius: 8px;
  background: var(--panel); font: 500 13px/1.3 var(--mono); color: var(--text);
}

/* something is waiting on that tab */
.dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--bad); margin-left: 5px; vertical-align: top;
  box-shadow: 0 0 6px rgba(255, 107, 129, 0.7);
}

/* the queue's controls read as one row: same height, same rhythm */
.actionbtns { align-items: stretch; }
.actionbtns form { display: flex; gap: 6px; }
.actionbtns input, .actionbtns button, .actionbtns .btn {
  height: 36px; padding: 0 16px; display: inline-flex; align-items: center;
  justify-content: center; font-size: 13px;
}
.actionbtns input { width: 104px; text-align: left; }

/* ------------------------------------------------------- the client app
   Read on a phone as often as at a desk, by people who see it once a week
   rather than all day. Everything runs a step larger there; the office app,
   which shows far more at once, keeps its density. */
body.client { font: 15px/1.55 "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
body.client h1 { font-size: 25px; }
body.client h2 { font-size: 18px; }
body.client h3 { font-size: 14px; }
body.client table { font-size: 15px; }
body.client th { font-size: 12px; }
body.client td { padding: 12px 11px; }
body.client .stat .k { font-size: 12.5px; }
body.client .stat .v { font-size: 23px; }
body.client .stat .sub { font-size: 12.5px; }
body.client .kv { font-size: 15px; }
body.client .kv dt { font-size: 13.5px; }
body.client label { font-size: 12.5px; }
body.client .hint,
body.client .empty { font-size: 13.5px; }
body.client .pill { font-size: 11px; }
body.client .btn, body.client button { font-size: 14px; }
body.client .btn-sm { font-size: 13px; }
body.client input, body.client select, body.client textarea { font-size: 15px; }
/* the small print set straight on the element in a template, lifted with it */
body.client [style*="font-size:11px"] { font-size: 12.5px !important; }
body.client [style*="font-size:11.5px"] { font-size: 13px !important; }
body.client [style*="font-size:12px"] { font-size: 13.5px !important; }

/* ------------------------------------------------- who is on a deal
   A short list of names, so it reads as a list of names: one chip each, the
   owner marked rather than shouted, and the way to remove somebody kept small
   enough that it is not the first thing the eye lands on. */
.addmember { display: flex; align-items: center; gap: 8px; }
.addmember select { width: 190px; }
.members { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.member {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 6px 8px 6px 13px; border: 1px solid var(--line-2);
  border-radius: 999px; background: var(--panel-2); font-size: 13px;
}
.member .who { font-weight: 500; letter-spacing: -0.01em; }
.member.owner { border-color: rgba(53, 224, 208, 0.32); padding-right: 13px; }
.member .tag {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--accent-dim);
}
/* Handing the deal over: quiet until you look for it, because it is a rarer
   thing to want than adding somebody. */
.member .btn { opacity: .65; }
.member:hover .btn { opacity: 1; }

.member .rm {
  width: 20px; height: 20px; padding: 0; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; line-height: 1; color: var(--muted);
  background: transparent; border: 1px solid transparent;
}
.member .rm:hover { color: var(--bad); border-color: rgba(255, 107, 129, 0.35); }
.members:empty { display: none; }

/* a stat tile that is also a filter: it reads as a figure, clicks as a tab */
.stat.count { display: block; color: inherit; text-decoration: none; }
.stat.count:hover { border-color: var(--line-2); text-decoration: none; }
.stat.count.on { border-color: rgba(53, 224, 208, 0.45); }
.stat.count .v { font-size: 22px; }

/* The one place a paste lands: a screenshot is attached because this box was
   asked for it, never because Ctrl-V happened to be pressed on the page. */
.pastezone {
  display: block; margin-top: 10px; padding: 9px 14px;
  border: 1px dashed var(--line-2); border-radius: 8px; background: transparent;
  color: var(--muted); font-size: 12.5px; text-align: left; width: 100%;
}
.pastezone:hover { border-color: var(--accent-dim); color: var(--text); }
.pastezone:focus {
  outline: none; border-style: solid; border-color: var(--accent);
  color: var(--text); box-shadow: 0 0 0 3px rgba(53, 224, 208, 0.12);
}
.pastezone:focus::after { content: " - now press Ctrl-V"; color: var(--accent); }

/* Something you are allowed to do, that you should know the cost of first. */
.warn { color: var(--warn); }

/* Names are stored in capitals, so they are typed in capitals: what you see
   while entering one is what the ledger will show. */
input.caps { text-transform: uppercase; }

/* ------------------------------------------------- the standing strip
   Five figures in the width the three used to take: one row, no wrapping onto
   a second line, nothing clipped. The tiles share the row equally and the
   number inside shrinks to fit rather than running past its own edge. */
.standing {
  display: grid; gap: 10px; margin-bottom: 18px;
  grid-template-columns: repeat(5, minmax(0, 1fr));
}
.standing .stat {
  display: flex; flex-direction: column; justify-content: space-between;
  padding: 12px 13px 13px; min-width: 0;
}
.standing .stat .k {
  font-size: 10px; line-height: 1.3; min-height: 2.6em; letter-spacing: 0.07em;
}
.standing .stat .v {
  font-size: clamp(13px, 1.15vw, 18px); margin-top: 8px;
  white-space: nowrap; font-variant-numeric: tabular-nums; min-width: 0;
}
/* narrow screens have no row to share, so they wrap rather than squeeze */
@media (max-width: 1100px) {
  .standing { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
}

/* A question with one possible answer, shown as the answer. The dropdown is
   still there and still what submits -- it is simply not asked. */
.settled-as { display: none; }
.field.settled .settled-as { display: block; }
.field.settled > select,
.field.settled > .ss { display: none; }

/* The earlier legs of a long chain: off screen until asked for, and the press
   sits at the foot of the list where the eye ends up. */
.chain li.extra { display: none; }
.chain.all li.extra { display: list-item; }
.morelegs { margin-top: 10px; }

/* the charges of a deal on their own, without the legs they hang off */
.chain.onlycharges li:not(.charge) { display: none; }
.chain.onlycharges li.charge.extra { display: list-item; }

/* What of a deal reached them and what has gone on again -- the two figures the
   client actually works from, so they get room of their own rather than being
   squeezed into the corner by the bar beside them. */
.dealflow {
  display: grid; align-items: center; gap: 14px 34px;
  grid-template-columns: minmax(150px, auto) minmax(150px, auto) minmax(200px, 1fr);
  margin: 12px 0 16px; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel-2);
}
.dealflow .k { font-size: 11px; text-transform: uppercase; letter-spacing: 0.09em;
               color: var(--muted); }
.dealflow .v { font-family: var(--mono); font-size: 18px; margin-top: 5px;
               letter-spacing: -0.02em; }
.dealflow .barcell .k { margin-bottom: 7px; display: inline-block; }
@media (max-width: 760px) {
  .dealflow { grid-template-columns: 1fr 1fr; }
  .dealflow .barcell { grid-column: 1 / -1; }
}

/* Reports: one panel, several views. The tab bar sits at the top of it and the
   sections below take turns, so nothing has to be scrolled past. */
.reportbook > .tabs { margin-bottom: 16px; }
.reportbook > section > .standing { margin-bottom: 10px; }
.reportbook h3 { margin-top: 4px; }

/* Opening a door, beside the red one that shuts it. */
.btn-go { color: var(--good); border-color: rgba(61, 220, 151, 0.4); }
.btn-go:hover { box-shadow: 0 0 14px rgba(61, 220, 151, 0.18); }

/* ================================================================ phones
   Measured with mobile_audit.py at 390x844, not guessed at. Four things make a
   page unusable in a hand, and each is answered below: a menu that eats the
   screen, taps too small to hit, a field that zooms the page in when it takes
   focus, and text nobody can read without pinching. */
@media (max-width: 720px) {
  /* The bar at the top: one row for who you are, one strip for where to go.
     Ten sections wrapping into five stacked rows took 400px -- half the screen
     -- before the page even started. The strip scrolls sideways instead, one
     row tall, and nav-strip.js brings the section you are on into view. */
  .topbar { height: auto; padding: 8px 0 0; gap: 0; align-items: center; }
  .brand { order: 1; padding: 0 14px 8px; }
  .whoami { order: 2; margin-left: auto; padding: 0 14px 8px; font-size: 12.5px; }
  nav {
    order: 3; flex: 1 0 100%; flex-wrap: nowrap;
    overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch;
    gap: 2px; padding: 6px 10px; border-top: 1px solid var(--line);
    scrollbar-width: none;
  }
  nav::-webkit-scrollbar { display: none; }
  nav a { flex: 0 0 auto; padding: 9px 13px; font-size: 13.5px; }

  /* A finger is about 44px across, and a 27px button is a miss. */
  button, .btn { padding: 10px 16px; min-height: 40px; }
  .btn-sm { padding: 7px 13px; font-size: 12.5px; min-height: 36px; }
  .whoami .btn-sm { min-height: 36px; padding: 7px 12px; }
  .tabs a { padding: 10px 15px; }
  .actionbtns button, .actionbtns .btn { min-height: 42px; }

  /* 16px is the line below which a phone zooms the page in as soon as a field
     takes focus -- and it does not zoom back out afterwards. */
  input, select, textarea { font-size: 16px; min-height: 44px; padding: 11px 12px; }
  textarea { min-height: 78px; }
  /* a 15px checkbox is a miss; 20px is still small but it can be hit */
  input[type=checkbox], input[type=radio] {
    min-height: 0; width: 20px; height: 20px; margin-right: 4px;
  }
  /* one question to a row: side by side, each half was too narrow to read */
  .field { flex: 1 1 100%; min-width: 0; }
  /* Filters are the exception, and a GET form is exactly what a filter is: six
     stacked boxes pushed the list itself off the screen, so they go two to a
     line with the search box across the top. */
  form[method="get"] .field { flex: 1 1 calc(50% - 6px); }
  form[method="get"] .field:first-child,
  form[method="get"] .field.wide { flex: 1 1 100%; }

  /* Text that was sized for a desktop table. */
  label { font-size: 12px; }
  .hint, .field .err { font-size: 12.5px; }
  th { font-size: 11.5px; }
  td { padding: 11px 10px; }
  /* the more specific desktop rules have to be answered by name, or they win */
  .pill, body.client .pill { font-size: 11.5px; padding: 3px 10px; }
  .acct, .money .acct, .qleg .acct, .stat .sub, .kv dt { font-size: 12px; }
  .kindtag, .subtle, .holderhead, .sorth .arrow { font-size: 11.5px; }
  .atag, .only, .tag, .member .tag { font-size: 11.5px; }
  .dealflow .k { font-size: 12px; }
  .stat .k { font-size: 11.5px; }
  .standing .stat .k { font-size: 11.5px; min-height: 0; }
  .standing .stat .v { font-size: 16px; }
  /* ponytail: the templates set a few sizes inline, which a stylesheet cannot
     reach without this. Delete the rule when they become classes. */
  [style*="font-size:11px"], [style*="font-size:11.5px"] { font-size: 12.5px !important; }

  /* A wide table keeps its columns and scrolls inside its own box: crushing
     eight columns into 350px put one word on each line. Only tables that really
     have that many columns are pushed out -- a short one still fits as it is. */
  .scroll { scrollbar-width: thin; }
  .scroll::-webkit-scrollbar { height: 5px; }
  .scroll::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 3px; }
  .scroll > table:has(tbody tr > *:nth-child(5)) { min-width: 560px; }
  .refchip { padding: 9px 14px; font-size: 13.5px; }
  /* a reference is one word: D-2026-0001 broken over three lines is unreadable.
     Only linked refs -- a wrapped date or note is fine where it is. */
  td a.mono { white-space: nowrap; }
  /* likewise a timestamp, an amount, or a route, once the table can scroll */
  .scroll td.mono, .scroll td .money, .scroll td.num { white-space: nowrap; }
  .scroll .flowpath { white-space: nowrap; }

  h1 { font-size: 19px; }
  .panel { padding: 14px; }
  .spread { flex-wrap: wrap; }
}


/* A panel that folds: the same long box as any other panel, with its name on
   the left and a + on the right. Pressing it brings the form down; the list
   below is what the page is for, so the form waits until it is asked for. */
details.fold {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px; margin-bottom: 18px;
}
details.fold > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center;
  gap: 8px; color: var(--text); font-size: 13.5px; font-weight: 500;
}
/* no native triangle, in any browser */
details.fold > summary::marker,
details.fold > summary::-webkit-details-marker { content: ""; display: none; }
details.fold > summary::after {
  content: "+"; margin-left: auto; color: var(--muted);
  font-family: var(--mono); font-size: 16px; line-height: 1;
}
details.fold[open] > summary::after { content: "−"; }
details.fold > summary:hover, details.fold > summary:hover::after { color: var(--accent); }
details.fold[open] > summary { margin-bottom: 14px; }
/* No slide-in animation here on purpose: this page refreshes itself in the
   background every couple of seconds, and an animation on the freshly swapped
   content replayed each time -- which reads as the panel shivering. */


/* The Screen's week picker: the weeks being read are the handle, and the month
   drops out of it. Whole rows light up, because a week is what is chosen. */
.weekpick { position: relative; }
.weekfold { margin-bottom: 0; padding: 6px 12px; }
.weekfold > summary { font-size: 12.5px; }
.weekfold[open] { position: absolute; right: 0; z-index: 20; min-width: 268px; }
.cal-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-bottom: 8px; font-size: 12.5px;
}
.cal-head .btn { padding: 1px 9px; }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-day-name {
  text-align: center; font-size: 10px; color: var(--muted);
  text-transform: uppercase; letter-spacing: .06em; padding-bottom: 2px;
}
.cal-day {
  padding: 5px 0; font-size: 12px; border: 1px solid transparent;
  border-radius: 6px; background: none; color: var(--text); cursor: pointer;
  font-family: var(--mono);
}
.cal-day:hover { border-color: var(--line-2); }
.cal-day.other { color: var(--muted); opacity: .55; }
.cal-day.today { border-color: rgba(53, 224, 208, .35); }
/* a whole week lights at once: it is the row that is chosen, not the day */
.cal-day.on { background: rgba(53, 224, 208, .16); color: var(--text); opacity: 1; }


/* A table with lines between its columns, for the rows that carry a lot of
   figures. The last column gets none -- a rule against the edge is a border. */
table.ruled th:not(:last-child), table.ruled td:not(:last-child) {
  border-right: 1px solid var(--line);
}
table.ruled tr.weekrow td { border-right-color: var(--line-2); }
/* a ref and a date are single things: they scroll sideways rather than being
   broken over four lines when the row runs out of width */
table.ruled td:first-child, table.ruled td:nth-child(2) { white-space: nowrap; }


/* A row of tiles all the same height: their content sits in the middle of it
   rather than at the top with the space below them. */
.grid.evenrow .stat { display: flex; flex-direction: column; justify-content: center; }


/* New Deal: the one thing on the page you might come to do, so its handle is a
   button rather than a heading -- rounded, in the accent, inside the panel. */
.fold.newdeal > summary .foldname {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 16px; border: 1px solid rgba(53, 224, 208, .55);
  border-radius: 999px; background: rgba(53, 224, 208, .12);
  color: var(--accent); font-weight: 600; letter-spacing: .01em;
}
.fold.newdeal > summary .foldname::before { content: "+"; font-family: var(--mono); }
.fold.newdeal > summary:hover .foldname {
  background: rgba(53, 224, 208, .2); border-color: var(--accent);
}
/* the + belongs to the button now, so the one on the right goes */
.fold.newdeal > summary::after { content: ""; }
.fold.newdeal[open] > summary::after { content: "−"; }


/* The deal report's own header: the name of the thing and the weeks it covers,
   in one box above the table rather than two loose items over it. */
.reporthead {
  margin-bottom: 14px; padding: 10px 14px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel-2);
}
.reporthead h2 { font-size: 15px; letter-spacing: -0.01em; }

/* Every column reads down the middle: a table where some figures sit left and
   some right has no line for the eye to follow. */
table.ruled th, table.ruled td { text-align: center; }
table.ruled td.progcell .bar { margin: 0 auto 3px; }
/* the week line is a heading, so its name stays at the left where it reads */
table.ruled tr.weekrow td:first-child { text-align: left; }

/* Six short columns -- a holder, a bank, a number. Pulled in from the panel
   edges so the row reads as a row and not as space with figures in it. */
table.ruled.narrow { max-width: 900px; margin: 0 auto; }

/* The client app runs a step larger than the office one, but the Deal Report
   is ten columns wide: at the full client scale it ran off the side of the
   page. It keeps the larger app and comes back towards the office density. */
body.client { font-size: 14.5px; }
body.client h1 { font-size: 23px; }
body.client h2 { font-size: 17px; }
body.client table { font-size: 14px; }
body.client td { padding: 10px 10px; }
body.client .stat .v { font-size: 21px; }
body.client table.ruled { font-size: 13px; }
body.client table.ruled td { padding: 9px 8px; }

/* The Deal Report is ten columns of money. On the page's usual width it ran
   half a column over and put a slider under it; here it takes the room the
   screen already has instead of being scrolled inside a box that fits. */
.wrap:has(.reporthead), .wrap:has(.dashside) { max-width: 1560px; }
