/* BillFlow console — one stylesheet, no framework, no build step. */

:root {
  --bg: #f4f6fa;
  --surface: #ffffff;
  --surface-2: #f8fafc;
  --sidebar: #16202e;
  --sidebar-ink: #cbd5e1;
  --sidebar-ink-strong: #ffffff;
  --line: #dde3ec;
  --ink: #131922;
  --muted: #64708a;
  --accent: #2a4f8f;
  --accent-soft: #e8eefb;
  --ok: #16714a;
  --ok-soft: #e2f4ec;
  --warn: #8a5b00;
  --warn-soft: #fbf0d9;
  --stop: #a2262a;
  --stop-soft: #fbe6e7;
  /* Table surfaces. Kept apart from --surface/--line because a row is read
     differently from a card: the heading has to out-weigh the rows under it,
     the rule between two rows has to be lighter than the rule round the card,
     and the hover band has to be obvious without being a selection. */
  --head-bg: #eef2f8;
  --head-ink: #46536b;
  --row-bg: var(--surface);
  --row-bg-alt: var(--surface);
  --row-bg-hover: #eff4fd;
  --row-line: #e7ebf3;
  --row-rule: #eef1f6;
  /* Every other row, in the dense view only. Faint enough that it is not a
     highlight and strong enough that the eye can follow it across. */
  --row-band: #f7f9fc;
  --radius: 10px;
  --shadow: 0 1px 2px rgba(19, 25, 34, 0.05), 0 8px 24px rgba(19, 25, 34, 0.06);
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0d131c;
    --surface: #151d29;
    --surface-2: #1a2331;
    --sidebar: #0a0f17;
    --sidebar-ink: #94a3b8;
    --line: #27323f;
    --ink: #e6edf6;
    --muted: #8b98ad;
    --accent: #6f9be8;
    --accent-soft: #1b2941;
    --ok: #64d3a1;
    --ok-soft: #14301f;
    --warn: #e0b357;
    --warn-soft: #322510;
    --stop: #f08a8e;
    --stop-soft: #351619;
    --head-bg: #1d2734;
    --head-ink: #9cabc0;
    --row-bg: var(--surface);
    --row-bg-alt: var(--surface);
    --row-bg-hover: #1f2b3a;
    --row-line: #222d3b;
    --row-rule: #1e2836;
    --row-band: #19222f;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.45);
    color-scheme: dark;
  }
}

* { box-sizing: border-box; }

/* The drawer and the modal set `display`, which would otherwise beat the
   browser's rule for [hidden] and leave both of them open on load. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; font-weight: 620; letter-spacing: -0.01em; }
h1 { font-size: 19px; }
h2 { font-size: 15px; }
h3 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 600; }
p { margin: 2px 0; }
a { color: var(--accent); }
.muted { color: var(--muted); font-size: 12.5px; }
.num { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }

/* ---------------------------------------------------------------- app shell */
.app { display: grid; grid-template-columns: 236px 1fr; min-height: 100vh; }

.sidebar {
  background: var(--sidebar);
  color: var(--sidebar-ink);
  display: flex;
  flex-direction: column;
  padding: 18px 14px;
  gap: 18px;
  position: sticky;
  top: 0;
  height: 100vh;
}
.brand { display: flex; gap: 10px; align-items: center; padding: 0 6px; }
.brand .mark {
  width: 30px; height: 30px; border-radius: 8px;
  display: grid; place-items: center;
  background: linear-gradient(150deg, #3f6fc4, #2a4f8f);
  color: #fff; font-weight: 700; font-size: 15px;
}
.brand strong { display: block; color: var(--sidebar-ink-strong); font-size: 15px; }
.brand em { display: block; font-style: normal; font-size: 11.5px; opacity: 0.65; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 170px; }

nav { display: flex; flex-direction: column; gap: 1px; flex: 1; overflow-y: auto; }
.nav-group { font-size: 10px; text-transform: uppercase; letter-spacing: .1em; opacity: .5; padding: 12px 10px 4px; }
.nav-group:first-child { padding-top: 2px; }
nav button {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 8px 10px;
  border: none; border-radius: 8px; background: none;
  color: inherit; font: inherit; text-align: left; cursor: pointer;
}
nav button:hover { background: rgba(255, 255, 255, 0.06); }
nav button.active { background: rgba(255, 255, 255, 0.12); color: var(--sidebar-ink-strong); font-weight: 600; }
nav button .count {
  margin-left: auto; font-size: 11px; padding: 0 6px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.14); font-variant-numeric: tabular-nums;
}
nav button.active .count { background: rgba(255, 255, 255, 0.22); }
nav svg { width: 16px; height: 16px; flex: none; opacity: 0.85; }

.sidebar-foot { display: grid; gap: 10px; }
.as-on { display: flex; flex-direction: column; padding: 0 6px; }
.as-on strong { color: var(--sidebar-ink-strong); font-variant-numeric: tabular-nums; }
.sidebar-foot .btn.ghost { border-color: rgba(255, 255, 255, 0.18); color: var(--sidebar-ink); background: transparent; }
.sidebar-foot .btn.ghost:hover { background: rgba(255, 255, 255, 0.08); }

.main { min-width: 0; display: flex; flex-direction: column; }
.topbar {
  display: flex; justify-content: space-between; align-items: flex-end; gap: 16px;
  padding: 18px 26px; background: var(--surface); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 5;
}
.topbar-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.scope-switcher { display: flex; gap: 6px; align-items: center; }
.scope-switcher select { font: inherit; font-size: 12.5px; padding: 5px 8px; border-radius: 8px; border: 1px solid var(--line); background: var(--surface); color: var(--ink); }
.scope-switcher .scoped { border-color: var(--accent); color: var(--accent); font-weight: 600; }
.acting-chip { font-size: 11.5px; color: var(--muted); border-left: 1px solid var(--line); padding-left: 10px; }
.acting-chip strong { color: var(--ink); }
main { padding: 22px 26px 64px; }

/* ------------------------------------------------------------------ pieces */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); margin-bottom: 16px; overflow: hidden;
}
.card > header {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding: 12px 16px; border-bottom: 1px solid var(--line);
}
.card > .body { padding: 14px 16px; }

.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; margin-bottom: 18px; }
.kpi { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 16px; }
.kpi .label { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.kpi .value { font-size: 22px; font-weight: 640; margin-top: 4px; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.kpi .sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.kpi.ok .value { color: var(--ok); }
.kpi.stop .value { color: var(--stop); }
.exception-tiles { margin: 0; padding: 14px; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.exception-tile { font: inherit; text-align: left; cursor: pointer; }
.exception-tile:hover { border-color: var(--accent); }
.exception-tile .label { text-transform: none; letter-spacing: 0; font-size: 12.5px; }

/* ==========================================================================
   Tables
   ==========================================================================
   A billing console is read, not browsed. Somebody is checking one figure
   against a bill in their other hand, or running down a column of balances
   looking for the one that is wrong. Four things make that possible, and
   everything in this block serves one of them:

   1. The eye has to find its row again after it has travelled right. Hence a
      hover band across the full width, an identity column that stays put
      while the rest scrolls, and — in the dense view, where rows are too
      close together to tell apart on their own — row banding.
   2. Digits have to line up. Tabular figures on the whole table, so a column
      of amounts aligns on its decimal point and a figure does not change
      width as it is edited.
   3. The first line of every cell has to sit on one baseline, or a row reads
      as eight boxes of different heights instead of one sentence. One
      line-height governs every cell, and the pills and buttons inside them
      are pulled onto it.
   4. The heading has to still be there at row two hundred.

   The three densities at the foot of this file change these numbers; they do
   not change the rules.
   ========================================================================== */

table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--row-font, 13.5px);
  /* Same-width digits. Without this ₹1,11,111 is narrower than ₹1,00,000 and
     a column of amounts stops being a column. */
  font-variant-numeric: tabular-nums;
}

thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--head-bg);
  font-size: var(--head-font, 11px); text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--head-ink);
  font-weight: 650; text-align: left;
  padding: var(--head-pad-y, 9px) var(--row-pad-x, 14px);
  white-space: nowrap;
  /* A border on a sticky cell of a collapsed table stops being painted the
     moment the cell lifts off. A shadow is painted by the cell itself, so the
     heading keeps its underline all the way down the list. */
  box-shadow: inset 0 -1px 0 var(--line);
}
/* A heading sits over its own column: above a column of amounts, on the right. */
thead th.num { text-align: right; }

/* A sortable heading looks and behaves like the heading it is, not like a
   button someone left in the header row. The arrow stays out of the way
   until you are on it. */
.th-sort {
  font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
  background: none; border: 0; padding: 0; margin: 0;
  display: inline-flex; align-items: center; gap: 5px;
  cursor: pointer;
}
thead th.num .th-sort { flex-direction: row-reverse; }
.th-sort:hover { color: var(--accent); }
.th-sort-mark { opacity: 0.45; font-size: 10px; }
.th-sort:hover .th-sort-mark { opacity: 1; }

tbody td {
  padding: var(--row-pad-y, 11px) var(--row-pad-x, 14px);
  border-bottom: 1px solid var(--row-line);
  vertical-align: top;
  /* One line-height everywhere, so the name, the date, the amount and the
     status pill of a row all start on the same baseline. */
  line-height: 1.45;
  /* On the cell, not the row: the identity column below is sticky, and a
     sticky cell paints over whatever the row put behind it. Banding and
     hover have to be set where the sticky cell will pick them up too. */
  background: var(--row-bg);
}
tbody tr:nth-child(even) td { background: var(--row-bg-alt, var(--row-bg)); }
tbody tr:last-child td { border-bottom: none; }
tbody tr.clickable { cursor: pointer; }
tbody tr.clickable:hover td { background: var(--row-bg-hover); }

/* The second line of a cell: who the invoice is for, what the reading was
   before, which branch raised it. Present, and quiet. */
td .sub { display: block; color: var(--muted); font-size: var(--sub-font, 12px); margin-top: 1px; }

/* An amount is the thing being checked, so it is the thing that is legible:
   full ink, never the muted grey a label gets. */
tbody td.num { color: var(--ink); font-weight: 560; }
tbody td.num .sub { font-weight: 400; }

/* Pills and small buttons are inline boxes with a line-height of their own,
   which is what tips a row crooked. Pull them back onto the row's baseline. */
tbody td .pill, tbody td .btn.small { vertical-align: baseline; }

/* The row's buttons stay on the row's line. Left to wrap they put a second
   line into the cell, and because a table row is as tall as its tallest cell,
   two buttons in the last column made every row in the list taller — the
   thing most worth fixing about how this read. */
tbody td .btn-row { flex-wrap: nowrap; }

/* ------------------------------------------------------- column widths

   A table left to itself gives every column a share of the slack, so "Due"
   ends up with room for a date and a half while the narration beside it wraps
   onto three lines and drags the whole row down with it. A column that has
   said it will not wrap does not need slack: it is asked for one per cent,
   which no browser can honour, so it settles at exactly the width of its
   content and hands everything it did not use to the columns that can use it.

   Left alone: the ones with prose in them, which is where the space belongs. */
thead th.nowrap,
thead th.num,
thead th:empty { width: 1%; }

/* An IRN, a GSTIN or a bank reference is one unbroken run of characters, and a
   column is at least as wide as the longest unbreakable thing in it — so one
   of them claims 180px it does not need and the narration next to it wraps
   onto four lines to pay for it. Letting them break anywhere costs nothing
   (they are read a character at a time, not as a word) and gives the space
   back to the prose. Ordinary words break only if they would overflow. */
tbody td { overflow-wrap: anywhere; }

.table-wrap {
  overflow-x: auto;
  /* The scroll container the sticky heading and identity column measure
     themselves against. */
  position: relative;
  /* A soft shadow on whichever edge still has table beyond it, and none on an
     edge that does not. Two of these layers scroll with the content and two
     are pinned, which is what makes them appear and disappear on their own.
     Without it a register wider than its card looks finished at the right. */
  background:
    linear-gradient(to right, var(--row-bg) 30%, transparent) left / 24px 100% no-repeat,
    linear-gradient(to left, var(--row-bg) 30%, transparent) right / 24px 100% no-repeat,
    radial-gradient(farthest-side at 0 50%, rgba(19, 25, 34, 0.14), transparent) left / 12px 100% no-repeat,
    radial-gradient(farthest-side at 100% 50%, rgba(19, 25, 34, 0.14), transparent) right / 12px 100% no-repeat;
  background-attachment: local, local, scroll, scroll;
}

/* --------------------------------------------------- the identity column

   Which row am I reading? On a register wide enough to scroll, the answer
   has usually gone off the left-hand edge by the time you reach the figure
   you came for. So the first column stays, with a rule down its right edge
   to say that the columns beside it have moved and it has not. Every list
   here puts the name or the number first, so there is nothing to configure.

   Tables inside forms are excluded: they are a layout, not a register, and
   there is nothing to scroll away from. */
.table-wrap table:not(.compact) thead th:first-child,
.table-wrap table:not(.compact) tbody td:first-child {
  position: sticky; left: 0; z-index: 1;
  box-shadow: 1px 0 0 var(--line);
}
.table-wrap table:not(.compact) thead th:first-child {
  z-index: 3;
  box-shadow: 1px 0 0 var(--line), inset 0 -1px 0 var(--line);
}
/* The name or number a row is known by, in full ink: it is the label for
   everything to the right of it. */
.table-wrap table:not(.compact) tbody td:first-child { color: var(--ink); }

/* One line above a list: how many rows, and in what order they are. */
.list-caption {
  padding: 8px 16px 0;
  font-size: 12px;
  color: var(--muted);
  letter-spacing: 0.01em;
}
.list-caption strong { color: var(--ink); font-weight: 600; }
td.nowrap, th.nowrap { white-space: nowrap; }

.pill {
  display: inline-block; padding: 1px 9px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.01em;
  background: var(--surface-2); color: var(--muted); border: 1px solid var(--line);
}
.pill.ok { background: var(--ok-soft); color: var(--ok); border-color: transparent; }
.pill.warn { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.pill.stop { background: var(--stop-soft); color: var(--stop); border-color: transparent; }
.pill.info { background: var(--accent-soft); color: var(--accent); border-color: transparent; }

.btn {
  font: inherit; font-size: 13px; font-weight: 550;
  padding: 6px 12px; border-radius: 8px; border: 1px solid transparent;
  background: var(--accent); color: #fff; cursor: pointer; white-space: nowrap;
}
.btn:hover { filter: brightness(1.07); }
.btn:disabled { opacity: 0.45; cursor: default; filter: none; }
.btn.danger { color: var(--stop); }
.btn.danger:not(.ghost) { background: var(--stop); color: #fff; }
.btn.ghost { background: var(--surface); color: var(--ink); border-color: var(--line); }
.btn.ghost:hover { background: var(--surface-2); filter: none; }
.btn.small { padding: 3px 9px; font-size: 12.5px; }
.btn.icon { padding: 4px 9px; }
.btn.block { width: 100%; }
.btn-row { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }

.chips { display: flex; gap: 6px; flex-wrap: wrap; }
.chip {
  font: inherit; font-size: 12.5px; padding: 3px 11px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface); color: var(--muted); cursor: pointer;
}
.chip.active { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }

.note { border-left: 3px solid var(--line); padding: 4px 0 4px 10px; margin-top: 6px; font-size: 12.5px; color: var(--muted); }
.note.stop { border-color: var(--stop); color: var(--stop); }
.note.warn { border-color: var(--warn); color: var(--warn); }
.note.info { border-color: var(--accent); }
.note.ok { border-color: var(--ok); color: var(--ok); }
.note ul { margin: 4px 0 0; padding-left: 18px; }
.note li { margin: 2px 0; }

.empty { padding: 34px 16px; text-align: center; color: var(--muted); }
.empty strong { display: block; color: var(--ink); margin-bottom: 4px; }

pre {
  margin: 0; padding: 14px 16px; overflow: auto; max-height: 460px;
  background: var(--surface-2); border-top: 1px solid var(--line);
  font: 12px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--ink);
}

dl.facts { display: grid; grid-template-columns: 132px 1fr; gap: 6px 14px; margin: 0; font-size: 13px; }
dl.facts dt { color: var(--muted); }
dl.facts dd { margin: 0; }

.exception {
  display: grid; grid-template-columns: 1fr auto auto; gap: 12px; align-items: center;
  padding: 11px 16px; border-bottom: 1px solid var(--line);
}
.exception:last-child { border-bottom: none; }
.exception .what { font-weight: 560; }
.exception .why { color: var(--muted); font-size: 12.5px; margin-top: 2px; }

/* ------------------------------------------------------------ drawer, modal */
.drawer-scrim, .modal-scrim {
  position: fixed; inset: 0; background: rgba(10, 15, 23, 0.42); z-index: 20;
}
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(720px, 94vw); z-index: 21;
  background: var(--surface); border-left: 1px solid var(--line); box-shadow: var(--shadow);
  display: flex; flex-direction: column;
}
.drawer > header, .modal > header {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 12px;
  padding: 16px 20px; border-bottom: 1px solid var(--line);
}
.drawer > div { overflow: auto; padding: 18px 20px 40px; }
/* The document is laid out for A4 (210mm ≈ 794px). Scale it to fit the drawer
   rather than reflowing it — the preview has to look like what prints. */
.preview {
  height: 620px; overflow: auto; background: #fff;
  border: 1px solid var(--line); border-radius: 8px;
}
.preview iframe { width: 794px; height: 1400px; border: 0; transform: scale(0.79); transform-origin: top left; }

.modal {
  position: fixed; z-index: 21; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: min(760px, 94vw); max-height: 88vh; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow);
}
.modal > div { overflow: auto; padding: 18px 20px; }

.field { display: grid; gap: 4px; margin-bottom: 12px; }
.field label { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.field input, .field select {
  font: inherit; padding: 7px 10px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink);
}
.field input:focus, .field select:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0 14px; }
input.num { text-align: right; }

.summary {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px;
  padding: 10px 14px; margin: 14px 0;
}
.summary div span { display: block; font-size: 12px; color: var(--muted); }
.summary div strong { font-size: 15px; font-variant-numeric: tabular-nums; }
.summary div.over strong { color: var(--stop); }
.summary div.left strong { color: var(--warn); }

.toasts { position: fixed; right: 20px; bottom: 20px; z-index: 40; display: grid; gap: 8px; justify-items: end; }
.toast {
  background: var(--sidebar); color: #fff; padding: 10px 14px; border-radius: 9px;
  max-width: 520px; font-size: 13px; box-shadow: var(--shadow);
  display: flex; align-items: center; gap: 12px;
}
.toast.stop { background: var(--stop); }
.toast.ok { background: var(--ok); }
.toast-action {
  flex: none; border: 1px solid rgb(255 255 255 / 70%); border-radius: 7px;
  background: #fff; color: var(--ink); padding: 5px 9px; font: inherit; font-weight: 700; cursor: pointer;
}



/* ------------------------------------------------------------------- forms */
.field { display: grid; gap: 4px; margin-bottom: 12px; align-content: start; }
.field label { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.field input, .field select, .field textarea {
  font: inherit; padding: 7px 10px; border-radius: 8px; width: 100%;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink);
}
.field input:focus, .field select:focus, .field textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.field .hint { font-size: 11.5px; color: var(--muted); }
.field.span-2 { grid-column: span 2; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0 14px; }
input.num { text-align: right; }
label.check { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--ink); text-transform: none; letter-spacing: 0; }
label.check input { width: auto; }
table.compact td { padding: 2px 4px; border-bottom: none; }
table.compact .field { margin-bottom: 4px; }
.bulk { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; border-bottom: 1px solid var(--line); }

.summary {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px;
  padding: 10px 14px; margin: 14px 0;
}
.summary div span { display: block; font-size: 12px; color: var(--muted); }
.summary div strong { font-size: 15px; font-variant-numeric: tabular-nums; }
.summary div.over strong { color: var(--stop); }
.summary div.left strong { color: var(--warn); }

@media (max-width: 900px) {
  .grid-2, .grid-3, .summary { grid-template-columns: 1fr; }
  .field.span-2 { grid-column: span 1; }
}


/* ---------------------------------------------------- cross-links, search */
a.xlink { color: var(--accent); text-decoration: none; border-bottom: 1px dotted currentColor; cursor: pointer; }
a.xlink:hover { border-bottom-style: solid; }
td .sub a.xlink { color: var(--muted); }
td .sub a.xlink:hover { color: var(--accent); }
#search {
  font: inherit; font-size: 13px; padding: 6px 10px; min-width: 230px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--surface); color: var(--ink);
}
#search:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
@media (max-width: 900px) { #search { min-width: 0; width: 100%; } }

/* Reports share one set of filters and expose their supported scope. */
.report-group { border-top: 1px solid var(--line, #e3e8ef); }
.report-group > summary { cursor: pointer; padding: 16px 20px; font-weight: 600; }
.report-group > summary .muted { margin-left: 8px; font-weight: 400; }
.report-group .btn-row { min-width: 250px; }
.report-options { border: 0; padding: 0; margin: 14px 0; }
.report-options legend { font-size: 12px; color: #5b6472; margin-bottom: 8px; }
.report-options .chip { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; }
.report-options .chip:has(input:checked) { background: #e8f0ff; border-color: #7b9cc8; color: #1f4d8f; }
.report-options input { width: auto; margin: 0; }
.report-shortcuts { justify-content: flex-start; margin-bottom: 14px; }
.report-more { margin-bottom: 18px; }
.report-more summary { cursor: pointer; padding: 8px 0; }
.report-unavailable { max-width: 360px; font-size: 12px; }
#report-controls [hidden] { display: none; }

.late-fee-terms { margin: 12px 0; }
.late-fee-terms summary { cursor: pointer; font-weight: 600; padding: 8px 0; }
#late-fee-preview details { min-width: 260px; max-width: 720px; }
#late-fee-preview details p { font-size: 12px; margin: 8px 0; }

#late-fee-preview > .body { padding: 14px 16px; }


/* The splash, up from the first paint until the session is known. */
[hidden] { display: none !important; }
.loading-screen {
  min-height: 100dvh;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 22px;
  padding: 24px;
  padding-top: calc(24px + env(safe-area-inset-top));
  background: var(--bg);
}
.loading-screen .brand { color: var(--ink); }
.loading-screen .brand strong { color: var(--ink); font-size: 17px; }
.spinner {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2.5px solid var(--line);
  border-top-color: var(--accent);
  animation: spin 0.7s linear infinite;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}
/* A spinner that cannot spin should still say something is happening. */
@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 2.4s; }
}
.login-screen { min-height: 100vh; display: grid; place-items: center; padding: 24px; }
.login-card { width: min(100%, 420px); padding: 32px; background: var(--surface); border: 1px solid var(--line); border-radius: 16px; box-shadow: var(--shadow); }
.login-card .brand { padding: 0 0 28px; color: var(--ink); }
.login-card .brand strong { color: var(--ink); }
.login-card h1 { font-size: 26px; margin: 0 0 8px; }
.login-card form { display: grid; gap: 10px; margin: 26px 0; }
.login-card input { width: 100%; min-height: 44px; font: inherit; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); color: var(--ink); }
.login-card input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.login-card label { font-weight: 600; }
.login-card .btn { min-height: 44px; justify-content: center; }
.login-card .note p { margin: 8px 0 0; }
.login-error { color: var(--stop); margin: 0; }
.login-error:empty { display: none; }
.signed-in-user { color: var(--sidebar-ink-strong); margin-bottom: 10px; overflow-wrap: anywhere; }
.sidebar-foot > .btn { color: var(--sidebar-ink-strong); margin-bottom: 18px; }


/* ==========================================================================
   The phone
   ==========================================================================
   Below 900px this stops being a desktop console with smaller margins and
   becomes an app: a bottom tab bar for the four screens a working day touches,
   the sidebar as a full-height More sheet, and the drawer and modal as bottom
   sheets, which is the gesture a phone user already expects.

   Everything stays reachable. A billing console has wide tables and no amount
   of layout makes a thirty-column sales register comfortable on a 390px
   screen, so those scroll inside their own container with the first column
   pinned, rather than being hidden or reflowed into something that no longer
   reconciles.
   ========================================================================== */

/* Chrome that only exists on a phone. */
.tabbar, .nav-scrim, .sheet-close, .sheet-grip { display: none; }

@media (max-width: 900px) {
  /* iOS zooms any input whose text is under 16px when it takes focus, and never
     zooms back out. Every control that accepts typing has to clear that bar. */
  .field input, .field select, .field textarea, #search, .login-card input, .scope-switcher select {
    font-size: 16px;
  }

  .app { grid-template-columns: 1fr; }
  main { padding: 14px 14px calc(78px + env(safe-area-inset-bottom)); }

  /* ------------------------------------------------------------ the app bar */
  /* ------------------------------------------------------------ the app bar
     A title, and at most one action. Everything that used to live here — the
     subtitle, three company selects — took the top third of every screen for
     things read once. The filter moved into the menu; the subtitle is gone. */
  .topbar {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 8px 10px;
    padding: 6px 12px 8px;
    padding-top: calc(6px + env(safe-area-inset-top));
  }
  .topbar-title { min-width: 0; }
  .topbar h1 {
    font-size: 20px;
    letter-spacing: -0.02em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .topbar .muted { display: none; }

  /* The filter lives in the menu on a phone. */
  .topbar .scope-switcher { display: none; }

  .topbar-actions { width: auto; gap: 6px; }
  .topbar-actions .btn {
    min-height: 36px;
    padding: 7px 14px;
    font-size: 14px;
    font-weight: 600;
  }

  /* Search gets the full width, on its own row under the title. */
  .page-search { grid-column: 1 / -1; }
  .page-search:empty { display: none; }
  #search { width: 100%; min-height: 38px; }

  /* ------------------------------------------------- sidebar as More sheet */
  .sidebar {
    position: fixed;
    inset: 0;
    height: 100dvh;
    z-index: 30;
    padding: calc(16px + env(safe-area-inset-top)) 14px calc(84px + env(safe-area-inset-bottom));
    overflow-y: auto;
    transform: translateY(100%);
    visibility: hidden;
    transition: transform 0.22s ease, visibility 0.22s;
  }
  .sidebar.open { transform: none; visibility: visible; }
  @media (prefers-reduced-motion: reduce) {
    .sidebar { transition: none; }
  }
  body.nav-open { overflow: hidden; }

  .nav-scrim { display: block; position: fixed; inset: 0; z-index: 29; background: rgba(10, 15, 23, 0.45); }
  .sheet-close {
    display: grid; place-items: center;
    position: absolute; top: calc(14px + env(safe-area-inset-top)); right: 14px;
    width: 34px; height: 34px; border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: rgba(255, 255, 255, 0.08); color: var(--sidebar-ink);
    font: inherit; font-size: 15px; cursor: pointer;
  }

  .scope-sheet { display: grid; gap: 8px; }
  .scope-sheet select {
    width: 100%;
    min-width: 0;
    text-overflow: ellipsis;
    min-height: 44px;
    font: inherit;
    font-size: 16px;
    padding: 8px 10px;
    border-radius: 9px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: rgba(255, 255, 255, 0.06);
    color: var(--sidebar-ink-strong);
  }

  nav { flex: none; overflow: visible; }
  nav button { min-height: 46px; font-size: 15px; }
  .nav-group { font-size: 11px; padding: 16px 10px 6px; }
  .sidebar-foot { margin-top: 20px; }
  .sidebar-foot .btn { min-height: 44px; }

  /* ------------------------------------------------------ the bottom tabs */
  .tabbar {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 31;
    background: color-mix(in srgb, var(--surface) 88%, transparent);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .tabbar button {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    /* 44px is the smallest target a thumb hits reliably. */
    min-height: 52px; padding: 7px 2px 5px;
    border: 0; background: none; color: var(--muted);
    font: inherit; font-size: 10.5px; font-weight: 550;
    cursor: pointer; -webkit-tap-highlight-color: transparent;
  }
  .tabbar button svg { width: 22px; height: 22px; }
  .tabbar button.active { color: var(--accent); }
  .tabbar button.active svg { stroke-width: 2.1; }
  .tabbar button span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* -------------------------------------------- drawer and modal as sheets */
  .drawer, .modal {
    top: auto; left: 0; right: 0; bottom: 0;
    width: 100%; max-width: none;
    transform: none;
    height: 92dvh; max-height: 92dvh;
    border: 0; border-top: 1px solid var(--line);
    border-radius: 18px 18px 0 0;
  }
  .drawer > header, .modal > header { padding: 4px 18px 14px; }
  .drawer > div, .modal > div { padding: 16px 18px calc(28px + env(safe-area-inset-bottom)); }
  .sheet-grip {
    display: block; width: 38px; height: 4px; border-radius: 999px;
    background: var(--line); margin: 9px auto 2px; flex: none;
  }
  .drawer-scrim, .modal-scrim { background: rgba(10, 15, 23, 0.5); }

  /* An A4 document scaled to a desktop drawer is unreadable on a phone; give it
     the width it needs and let the container scroll both ways. */
  .preview { height: 66dvh; }
  .preview iframe { transform: scale(0.46); }

  /* ------------------------------------------------------ lists and tables */
  .card { border-radius: 12px; margin-bottom: 12px; }
  .card > header { padding: 12px 14px; flex-wrap: wrap; }
  .card > .body { padding: 12px 14px; }

  /* Two by two, all four visible. A dashboard figure you have to swipe to is a
     figure you will not check, and these four are the whole point of opening
     the app: what is owed, what is late, what can be billed, what is coming. */
  .kpis {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin: 12px 0;
    padding: 0 12px;
    overflow: visible;
  }
  .kpi {
    padding: 12px;
    border-radius: 12px;
    min-width: 0;
  }
  .kpi .label {
    font-size: 10.5px;
    letter-spacing: 0.05em;
    /* Two lines at most: "Ready to bill" and "Next 30 days" must not push the
       figures on one tile out of line with its neighbour. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-height: 2.2em;
  }
  .kpi .value {
    /* Scales with the screen so a crore figure still fits a half-width tile. */
    font-size: clamp(14px, 4.4vw, 19px);
    margin-top: 2px;
    letter-spacing: -0.02em;
    overflow-wrap: anywhere;
  }
  .kpi .sub { font-size: 11px; margin-top: 3px; }

  .exception-tiles {
    grid-template-columns: 1fr 1fr;
    margin: 0;
    padding: 0 14px 14px;
  }
  .exception-tile { padding: 10px 12px; }
  .exception-tile .label { min-height: 2.4em; font-size: 11.5px; }
  .exception-tile .value { font-size: 20px; }
  .exception-tile .sub {
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  /* The sticky identity column and the scroll shadows are not phone-specific
     and now live with the rest of the table rules; only the tightening is
     left here. A register that keeps its columns on a phone keeps them on one
     line each, and scrolls. */
  .table-wrap { -webkit-overflow-scrolling: touch; }
  table:not(.cards) thead th,
  table:not(.cards) tbody td { padding-left: 12px; padding-right: 12px; white-space: nowrap; }

  /* Name and figure on one line, reason under it, action across the foot. */
  .exception {
    grid-template-columns: 1fr auto;
    gap: 4px 12px;
    padding: 12px 14px;
    align-items: baseline;
  }
  .exception > :first-child { grid-column: 1; grid-row: 1; min-width: 0; }
  .exception .num {
    grid-column: 2;
    grid-row: 1;
    font-weight: 640;
    white-space: nowrap;
  }
  .exception .why { margin-top: 3px; }
  .exception .btn-row {
    grid-column: 1 / -1;
    justify-content: stretch;
    margin-top: 8px;
  }
  .exception .btn-row:empty { display: none; margin: 0; }
  .exception .btn-row .btn { flex: 1; }

  dl.facts { grid-template-columns: 1fr; gap: 2px 0; }
  dl.facts dt { margin-top: 8px; font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.04em; }

  .grid-2, .grid-3, .summary { grid-template-columns: 1fr; }
  .field.span-2 { grid-column: span 1; }
  .summary { grid-template-columns: repeat(2, 1fr); }

  .btn { min-height: 38px; padding: 8px 14px; }
  .btn.small { min-height: 32px; }
  .btn-row { justify-content: stretch; }
  .btn-row .btn { flex: 1 1 auto; }
  .chips { gap: 8px; }
  .chip { min-height: 34px; padding: 6px 13px; }

  /* Above the tab bar, not behind it. */
  .toasts { right: 12px; left: 12px; bottom: calc(64px + env(safe-area-inset-bottom)); justify-items: stretch; }
  .toast { max-width: none; }

  .login-screen { padding: 20px; align-content: center; }
  .login-card { padding: 24px; border: 0; box-shadow: none; background: transparent; }
  .login-card h1 { font-size: 24px; }
}

/* A phone in landscape, and small tablets: four across, since there is room. */
@media (max-width: 900px) and (min-width: 560px) {
  .kpis, .exception-tiles { grid-template-columns: repeat(4, 1fr); }
  .grid-2, .summary { grid-template-columns: 1fr 1fr; }
}

/* Installed to the home screen, there is no browser chrome to scroll away, so
   the app bar can be flatter and the safe areas do the spacing. */
@media (display-mode: standalone) {
  .topbar { border-bottom: 1px solid var(--line); }
  body { overscroll-behavior-y: none; }
}


/* ==========================================================================
   Lists as cards on a phone
   ==========================================================================
   Every list screen is built by one `table()` helper, so labelling its cells
   is enough to turn all of them into cards here. A register keeps its columns
   and scrolls — see above — but a list you are picking something out of reads
   far better stacked, and stacked is what a phone app looks like.
   ========================================================================== */

@media (max-width: 900px) {
  .table-wrap:has(table.cards) {
    overflow: visible;
    background: none;
  }

  table.cards,
  table.cards tbody {
    display: block;
    width: 100%;
  }

  /* The frozen first column belongs to a table; stacked, there is no table to
     scroll it out of. */
  table.cards thead th:first-child,
  table.cards tbody td:first-child {
    position: static;
    box-shadow: none;
  }

  /* The headings live on each cell instead, as data-label. */
  table.cards thead {
    display: none;
  }

  /* A row reads name-then-figure on one line, the way a list row does in any
     phone app, with everything else as a quiet second line underneath. */
  table.cards tr {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    column-gap: 12px;
    row-gap: 1px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--line);
  }
  table.cards tr:last-child {
    border-bottom: none;
  }

  /* A card you can open should say so when your thumb is on it. */
  table.cards tr.clickable {
    -webkit-tap-highlight-color: transparent;
    cursor: pointer;
  }
  table.cards tr.clickable:hover td { background: none; }
  table.cards tr.clickable:hover { background: var(--row-bg-hover); }
  table.cards tr.clickable:active {
    background: var(--accent-soft);
  }

  table.cards td {
    grid-column: 1 / -1;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    /* Stacked, the card is the row and the row carries its own background —
       including the one it takes on under a thumb. A cell painting over it
       would swallow that. */
    background: none;
    padding: 0;
    border: none;
    text-align: left;
    white-space: normal;
    font-size: 12.5px;
    color: var(--muted);
  }

  /* Labels are a whisper, not a heading. */
  table.cards td::before {
    content: attr(data-label);
    flex: none;
    color: var(--muted);
    font-size: 12px;
    letter-spacing: 0;
    text-transform: none;
  }

  /* The name leads. */
  table.cards td:first-child {
    grid-column: 1;
    grid-row: 1;
    display: block;
    font-size: 15px;
    font-weight: 600;
    color: var(--ink);
    margin-bottom: 3px;
  }
  table.cards td:first-child::before {
    content: none;
  }

  /* The figure sits beside it. */
  table.cards td.lead-figure {
    grid-column: 2;
    grid-row: 1;
    display: block;
    font-size: 15px;
    font-weight: 640;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
  table.cards td.lead-figure::before {
    content: none;
  }

  /* A cell with nothing in it is noise once the row is a card. */
  table.cards td:empty {
    display: none;
  }

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

  /* Buttons go full width at the foot of the row, where a thumb expects them. */
  table.cards td:has(.btn),
  table.cards td:has(.btn-row) {
    display: block;
    padding-top: 10px;
  }
  table.cards td:has(.btn)::before,
  table.cards td:has(.btn-row)::before {
    content: none;
  }
  table.cards td .btn {
    width: 100%;
    margin-top: 6px;
  }
  table.cards td .btn-row {
    flex-direction: column;
    align-items: stretch;
  }

  /* The sub-line under a value should sit under it, not beside the label. */
  table.cards td .sub {
    display: block;
    margin-top: 2px;
  }

  /* ------------------------------------------------------- app-like feel */

  /* Sheets keep their own scroll rather than dragging the page behind them. */
  .drawer > div,
  .modal > div,
  .sidebar {
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }

  /* Everything tappable acknowledges the tap, and nothing flashes grey. */
  .btn,
  .chip,
  .tabbar button,
  nav button,
  .exception-tile,
  a.xlink {
    -webkit-tap-highlight-color: transparent;
  }
  .btn:active,
  .chip:active,
  .exception-tile:active {
    transform: scale(0.985);
  }
  .tabbar button:active span {
    opacity: 0.6;
  }
  @media (prefers-reduced-motion: reduce) {
    .btn:active,
    .chip:active,
    .exception-tile:active {
      transform: none;
    }
  }

  /* The primary action of a screen sits where a thumb reaches it. */
  .topbar-actions .btn {
    font-size: 15px;
    font-weight: 600;
  }
}


/* ==========================================================================
   Typing inside a card
   ==========================================================================
   The screens that matter most on a phone — allocating a receipt against
   bills, entering meter readings, setting tariff slabs — are hand-built tables
   with an input in every row. Restacked as cards, the input has the whole
   width instead of a 120px box reached by scrolling sideways.
   ========================================================================== */

@media (max-width: 900px) {
  table.cards td input,
  table.cards td select,
  table.cards td textarea {
    width: 100%;
    /* Beats the inline width these were given for the desktop layout. */
    max-width: none;
    min-height: 42px;
    font-size: 16px;
  }

  /* A cell that is only an input reads as a labelled field, not a table cell. */
  table.cards td:has(input):not(:has(.btn)),
  table.cards td:has(select),
  table.cards td:has(textarea) {
    display: block;
    padding-top: 8px;
  }
  table.cards td:has(input):not(:has(.btn))::before,
  table.cards td:has(select)::before,
  table.cards td:has(textarea)::before {
    display: block;
    margin-bottom: 4px;
  }

  /* Money still reads right-aligned even when the box is full width. */
  table.cards td.num input { text-align: right; }

  /* A checkbox is not a field; keep it inline with its label. */
  table.cards td:has(input[type='checkbox']) {
    display: flex;
    align-items: center;
  }
  table.cards td input[type='checkbox'] {
    width: auto;
    min-height: 0;
    min-width: 20px;
    height: 20px;
  }

  /* Compact tables inside forms follow the same rules. */
  table.compact.cards tr { padding: 10px 0; }
  table.compact.cards td { padding: 3px 0; }

  /* Long identifiers — GSTINs, invoice numbers, ledger names — wrap rather
     than forcing the card wider than the screen. */
  table.cards td { overflow-wrap: anywhere; }

  /* Field traces and Tally XML: readable, scrollable, and not the whole page. */
  pre { max-height: 300px; font-size: 11.5px; padding: 12px; }

  /* Filter chip groups on the reports screen scroll rather than wrap into a
     wall the page has to be scrolled past. */
  .report-options .chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    padding-bottom: 4px;
  }
  .report-options .chips::-webkit-scrollbar { display: none; }
  .report-options .chip { flex: 0 0 auto; }

  .report-group > summary { padding: 14px 14px; }
  .report-group .btn-row { min-width: 0; }
  .report-more summary { min-height: 44px; display: flex; align-items: center; }

  /* Anything given a fixed width for the desktop layout. */
  [style*='width:120px'],
  [style*='width: 120px'],
  [style*='max-width:180px'] {
    width: 100% !important;
    max-width: none !important;
  }
}


/* ==========================================================================
   A phone screen, not a narrow desktop one
   ==========================================================================
   Two things were making this read as a website: the page kept its desktop
   margins, so a card sat in a box inside a box on a screen with no width to
   spare; and something wide was pushing the whole layout past the viewport, so
   every card was cut off on the right.
   ========================================================================== */

/* Nothing may make the page wider than the screen. Grid and flex children
   default to min-width:auto, so one wide table stretches the column it is in
   and takes the entire layout with it — which is exactly what was happening. */
@media (max-width: 900px) {
  html,
  body {
    max-width: 100%;
    /* `clip`, not `hidden`: hidden makes the body a scroll container, which
       stops the app bar sticking. This is a backstop anyway — the causes are
       fixed below. */
    overflow-x: clip;
  }

  /* A <select> sizes itself to its longest option, so one company called
     "Northern Property Management Ltd" made the whole layout wider than the
     screen and cut every card off at the right. This was the main cause. */
  select,
  input,
  textarea,
  .btn {
    max-width: 100%;
    min-width: 0;
  }

  /* Widths set for a desktop that nothing overrode. */
  #late-fee-preview details {
    min-width: 0;
    max-width: 100%;
  }
  .preview {
    max-width: 100%;
  }
  .preview iframe {
    max-width: none;
  }
  .app,
  .main,
  .topbar,
  main,
  .card,
  .card > .body,
  .kpi {
    min-width: 0;
    max-width: 100%;
  }
  .table-wrap {
    max-width: 100%;
  }

  /* Full bleed. A card is a section of the screen, not a box floating on it. */
  main {
    padding: 0 0 calc(74px + env(safe-area-inset-bottom));
  }
  .card {
    margin: 0 0 8px;
    border-radius: 0;
    border-left: 0;
    border-right: 0;
  }
  /* A grouped-list header: a quiet label above the section, not a title bar. */
  .card > header {
    padding: 14px 14px 6px;
    border-bottom: none;
    background: none;
  }
  .card > header h2 {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
  }

  .exception-tiles { gap: 8px; }

  table.cards tr {
    padding: 12px 14px;
  }

  .empty {
    padding: 28px 16px;
  }

  /* Notes and hints are commentary; they should not out-shout the figures. */
  .note {
    margin: 8px 14px;
    font-size: 12px;
  }
  .card > .body > .note:first-child {
    margin-left: 0;
    margin-right: 0;
  }

  /* Section headings between cards read as list headers, as a phone app does. */
  main > h3,
  .card > .body > h3 {
    padding: 0 2px;
    margin: 16px 0 8px;
  }
}

/* A very narrow phone, and the split-screen widths people actually use. */
@media (max-width: 380px) {
  .topbar h1 { font-size: 18px; }
  .topbar-actions .btn { padding: 7px 10px; font-size: 13px; }
  .kpi .value { font-size: clamp(14px, 5.2vw, 18px); }
  .tabbar button { font-size: 9.5px; }
  .tabbar button svg { width: 20px; height: 20px; }
  table.cards td::before { font-size: 11px; }
}


/* ==========================================================================
   What is being shown
   ==========================================================================
   Company, branch and registration are one global filter, changed rarely and
   read often. On a desktop the three selects sit beside the page title. On a
   phone that was the top third of every screen, so it becomes one button
   saying what is on, opening a sheet to change it.
   ========================================================================== */

.scope-trigger,
.scope-scrim,
.scope-sheet { display: none; }

@media (max-width: 900px) {
  .scope-trigger {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 46vw;
    min-height: 34px;
    padding: 5px 11px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--surface);
    color: var(--muted);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .scope-trigger svg { width: 15px; height: 15px; flex: none; }
  .scope-trigger span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* Narrowed to something is a state worth seeing without reading. */
  .scope-trigger.narrowed {
    border-color: var(--accent);
    background: var(--accent-soft);
    color: var(--accent);
  }
  .scope-trigger:active { transform: scale(0.97); }

  .scope-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 32;
    background: rgba(10, 15, 23, 0.5);
  }

  .scope-sheet {
    display: flex;
    flex-direction: column;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 33;
    max-height: 86dvh;
    background: var(--surface);
    border-top: 1px solid var(--line);
    border-radius: 18px 18px 0 0;
    box-shadow: var(--shadow);
  }
  .scope-sheet > header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 2px 18px 12px;
  }
  .scope-sheet > header h2 { font-size: 16px; }
  .scope-sheet > div {
    display: grid;
    gap: 14px;
    overflow-y: auto;
    padding: 4px 18px 8px;
  }
  .scope-sheet select {
    width: 100%;
    min-width: 0;
    min-height: 48px;
    font: inherit;
    font-size: 16px;
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-radius: 11px;
    background: var(--surface);
    color: var(--ink);
    text-overflow: ellipsis;
  }
  .scope-sheet select.scoped {
    border-color: var(--accent);
    color: var(--accent);
    font-weight: 600;
  }
  .scope-sheet > footer {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    padding: 14px 18px calc(18px + env(safe-area-inset-bottom));
  }
  .scope-sheet > footer .btn { min-height: 46px; }
}

/* ------------------------------------------------------------------ guide */
/* The "How this works" page: a numbered walk through the flow, readable on a
   phone as one column and on a desktop as a number beside its step. */

.guide-flow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 14px 0 4px;
}
.guide-chip {
  padding: 5px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.guide-arrow { color: var(--muted); font-size: 12px; }

.guide-steps { display: grid; gap: 4px; }

.guide-step {
  display: grid;
  grid-template-columns: 34px 1fr;
  gap: 14px;
  padding: 16px 0;
  border-top: 1px solid var(--line);
}
.guide-step:first-child { border-top: 0; padding-top: 4px; }

.guide-num {
  width: 30px;
  height: 30px;
  border-radius: 999px;
  display: grid;
  place-items: center;
  background: var(--accent);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
}
.guide-body h3 { margin: 4px 0 6px; font-size: 15px; }
.guide-body > p { margin: 0 0 10px; color: var(--ink); }

dl.guide-facts {
  display: grid;
  grid-template-columns: 190px 1fr;
  gap: 7px 16px;
  margin: 0 0 10px;
  font-size: 13px;
}
dl.guide-facts dt { color: var(--muted); }
dl.guide-facts dd { margin: 0; }

@media (max-width: 720px) {
  .guide-step { grid-template-columns: 26px 1fr; gap: 10px; }
  .guide-num { width: 24px; height: 24px; font-size: 12px; }
  dl.guide-facts { grid-template-columns: 1fr; gap: 2px 0; }
  dl.guide-facts dt { margin-top: 8px; font-weight: 600; }
}

/* ==========================================================================
   The three ways a list can be shown
   ==========================================================================
   One person is reconciling four hundred rows against a bank statement and
   wants every one of them on the screen at once. Another is checking a single
   invoice before approving it and wants to read it properly. The same table
   cannot be right for both, so the choice is theirs and it sticks.

   What the market does, and what was taken from it:

     Zoho Books and Xero show roomy, unbanded rows with a strong first column
     and the amount right-aligned in full ink. It is the easiest thing to read
     when you are looking for one row out of forty, and it is the default here
     for the same reason.

     Tally Prime shows a true register: one line a row, ruled between the
     columns, banded so the eye can cross thirty of them without losing its
     place. It is the right tool for reconciling, and it is what `Dense` is.

     Every one of them falls back to a stacked, labelled card on a phone,
     because a row with fourteen columns cannot be read any other way on a
     390px screen. `Cards` is that layout, asked for at any width — useful
     when a row has more fields than the window has room for.

   All three are the same markup. Only these variables change.
   ========================================================================== */

/* A segmented control, not three loose chips: it is one setting with three
   positions, and it should look like one. */
.list-view-switch {
  display: flex;
  gap: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  overflow: hidden;
  flex: none;
}
.list-view-switch .chip {
  font-size: 12px;
  padding: 5px 11px;
  border: 0;
  border-radius: 0;
  background: transparent;
  line-height: 1.3;
}
.list-view-switch .chip + .chip { border-left: 1px solid var(--line); }
.list-view-switch .chip:hover:not(.active) { background: var(--surface-2); color: var(--ink); }
.list-view-switch .chip.active { background: var(--accent-soft); color: var(--accent); font-weight: 650; }

/* ---------------------------------------------------------------- 1. Roomy

   The default. Two lines to a row — what it is on top, what it belongs to
   underneath — with room to breathe between them, no banding, and the amount
   in full ink at the right. Reading forty invoices and picking one out. */
:root[data-list-view='comfortable'] {
  --row-font: 13.5px;
  --sub-font: 12px;
  --row-pad-y: 11px;
  --row-pad-x: 14px;
  --head-pad-y: 9px;
}

/* ---------------------------------------------------------------- 2. Dense

   A register. One line to a row, always: the second line of every cell is
   folded up beside the first, nothing wraps, and what will not fit scrolls
   sideways past a first column that stays where it is. Banded and ruled,
   because at this spacing the row above and the row below are not far enough
   apart to tell apart on their own. Roughly three times as many rows on a
   screen as Roomy. */
:root[data-list-view='compact'] {
  --row-font: 12.5px;
  --sub-font: 12px;
  --row-pad-y: 5px;
  --row-pad-x: 10px;
  --head-pad-y: 6px;
  --head-font: 10.5px;
  /* Banding on. This is the whole reason the dense view is readable at all. */
  --row-bg-alt: var(--row-band);
}
/* A rule between the columns. On a register this wide the eye needs to know
   which column it is in, not only which row. */
:root[data-list-view='compact'] tbody td + td,
:root[data-list-view='compact'] thead th + th { border-left: 1px solid var(--row-rule); }
/* One line a row. The second line of a cell — the party under the invoice
   number, the branch under the date — comes up beside the first with a
   separator, so nothing is lost and nothing is two lines tall. */
:root[data-list-view='compact'] td .sub {
  display: inline;
  margin-top: 0;
  margin-left: 5px;
}
:root[data-list-view='compact'] td .sub::before { content: '· '; }
:root[data-list-view='compact'] tbody td,
:root[data-list-view='compact'] thead th { white-space: nowrap; }
:root[data-list-view='compact'] .list-caption { padding-top: 6px; padding-bottom: 2px; }
:root[data-list-view='compact'] .btn.small { padding: 2px 7px; font-size: 11px; }
:root[data-list-view='compact'] .pill { padding: 0 7px; font-size: 11px; }
/* A note under a cell is a sentence, not a column; left as it is, but tight. */
:root[data-list-view='compact'] .note { margin-top: 2px; padding: 0 0 0 8px; font-size: 11.5px; }

/* ---------------------------------------------------------------- 3. Cards

   One block a record, every field beside its own heading. The layout a phone
   gets, asked for on a wide screen — where it lays out several across, so a
   list of records is still a list and not a single long column. */
@media (min-width: 901px) {
  :root[data-list-view='cards'] .table-wrap:has(table.cards) {
    overflow: visible;
    background: none;
    padding: 12px 14px 14px;
  }
  :root[data-list-view='cards'] table.cards { display: block; }
  /* Several across. `auto-fill` rather than a fixed count, so the same rule
     gives one card on a narrow window and three on a wide one. */
  :root[data-list-view='cards'] table.cards tbody {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(330px, 1fr));
    gap: 10px;
    /* Cards beside each other are the same height. Ragged bottoms read as a
       mistake, and the eye has to find the next card's top edge anyway. */
    align-items: stretch;
  }
  :root[data-list-view='cards'] table.cards thead { display: none; }
  /* The frozen first column belongs to a table; there is no table here. */
  :root[data-list-view='cards'] table.cards thead th:first-child,
  :root[data-list-view='cards'] table.cards tbody td:first-child {
    position: static;
    box-shadow: none;
  }
  :root[data-list-view='cards'] table.cards tr {
    display: block;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    padding: 0 0 4px;
    overflow: hidden;
  }
  /* The card is the row here too: it takes the hover, and its cells stay out
     of the way so the tint reaches the corners and the title bar with it. */
  :root[data-list-view='cards'] table.cards tr:hover { border-color: var(--accent); }
  :root[data-list-view='cards'] table.cards tr.clickable:hover { background: var(--row-bg-hover); }
  :root[data-list-view='cards'] table.cards tr.clickable:hover td { background: none; }
  :root[data-list-view='cards'] table.cards tr.clickable:hover td:first-child { background: var(--head-bg); }
  /* Heading on the left, value on the right, and the cell's second line under
     the value rather than beside it — a grid, because with flex the value and
     its second line become two items and the row reads as three columns. */
  :root[data-list-view='cards'] table.cards td {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0 16px;
    padding: 3px 13px;
    border: 0;
    background: none;
    text-align: right;
    /* A grid item stretches across its column unless told otherwise, and a
       status pill stretched across a card is a coloured bar, not a pill. */
    justify-items: end;
  }
  :root[data-list-view='cards'] table.cards td::before {
    content: attr(data-label);
    grid-column: 1;
    justify-self: start;
    color: var(--muted);
    font-size: 12px;
    font-weight: 400;
    text-align: left;
    white-space: nowrap;
  }
  :root[data-list-view='cards'] table.cards td .sub { grid-column: 2; margin-top: 0; }
  /* A card with no heading on it is a list of values nobody can read. */
  :root[data-list-view='cards'] table.cards td:empty { display: none; }
  /* The record's own name, as the card's title bar — not another labelled
     field, because it is what the other fields are about. */
  :root[data-list-view='cards'] table.cards td:first-child {
    display: block;
    text-align: left;
    /* Back to normal: the cells above are a two-column grid whose values are
       held to the right, and the browser applies that alignment to the block
       children of a plain block box too — which would push the party name
       under this card's number over to the right-hand edge. */
    justify-items: normal;
    font-weight: 650;
    font-size: 14px;
    padding: 9px 13px;
    margin-bottom: 4px;
    background: var(--head-bg);
    border-bottom: 1px solid var(--line);
  }
  :root[data-list-view='cards'] table.cards td:first-child::before { content: none; }
  :root[data-list-view='cards'] table.cards td:first-child .sub {
    display: block;
    font-weight: 400;
    margin-top: 1px;
  }
  /* The row's buttons, across the foot of its card. */
  :root[data-list-view='cards'] table.cards td:has(.btn),
  :root[data-list-view='cards'] table.cards td:has(.btn-row) {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 6px;
    padding: 8px 13px 4px;
    margin-top: 4px;
    border-top: 1px solid var(--row-line);
  }
  :root[data-list-view='cards'] table.cards td .btn-row { flex-wrap: wrap; justify-content: flex-start; }
  :root[data-list-view='cards'] table.cards td:has(.btn)::before,
  :root[data-list-view='cards'] table.cards td:has(.btn-row)::before { content: none; }
  /* A card is read down, so an amount does not need to be held to the right
     of a column that is no longer there — but it is still the figure. */
  :root[data-list-view='cards'] table.cards td.num { font-weight: 650; }
}
