.financial-heading {display:flex;align-items:center;justify-content:space-between;gap:24px;margin:24px 0 20px}
.financial-heading h2 {font-size:24px;letter-spacing:-.6px;margin:7px 0}
.financial-heading p {color:var(--muted);font-size:13px;line-height:1.7;margin:0}
.eyebrow {font-size:10px;letter-spacing:2px;color:var(--muted);font-weight:650}
.finance-space {margin-top:18px}
.finance-actions {display:flex;gap:12px;align-items:center;flex-wrap:wrap}
.finance-grid {display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:16px}
.finance-scroll {overflow:auto;max-height:270px;margin-top:16px}
.health-risk {font-size:13px;line-height:1.8;margin:10px 0}
.ocr-text {max-height:240px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;background:var(--bg);padding:15px;font-size:12px}
.intake-fields {border:0;padding:0;margin:0;min-width:0}
.finance-grid input,.finance-grid select {min-width:0;width:100%}
@media (max-width:800px) {.finance-grid {grid-template-columns:1fr}.financial-heading {align-items:flex-start;flex-direction:column}}
.archive-toolbar{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:12px 0}
.archive-table{overflow-x:auto;margin-bottom:14px}
.archive-filters{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:16px;margin-bottom:14px}
.archive-filters input.input{flex:1 1 220px;width:auto}
.archive-filters select.input{flex:0 1 180px;width:auto}
.archive-filters label{white-space:nowrap;font-size:13px;max-width:100%}
/* A long period name made the select, and with it the page, wider than a phone:
   there it goes under its label and is no wider than the card. */
.archive-filters label select.input{max-width:100%}
@media(max-width:800px){.archive-filters label{white-space:normal}}
.archive-table td:nth-child(4){min-width:165px}
.archive-name{display:block;max-width:450px;overflow-wrap:anywhere}
.archive-actions{display:flex;gap:6px;flex-wrap:wrap;min-width:220px}
.archive-history{display:flex;gap:8px;align-items:center;margin-top:8px;overflow-wrap:anywhere;font-size:12px}
.demo-warning{background:#fff5dc;border-color:#d4aa49;margin:14px 0;line-height:1.65}
.health-trend-row{display:grid;grid-template-columns:70px minmax(80px,1fr) 205px;gap:12px;align-items:center;font-size:12px;margin:12px 0}
.health-trend-income,.health-trend-expense{height:8px;border-radius:3px;margin:3px 0}
.health-trend-income{background:#136b52}.health-trend-expense{background:#c58b31}
.capital-panels{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:20px}
/* A grid item is as wide as its widest table unless told it may be narrower;
   in one column on a phone that pushed the whole page sideways. Its tables
   scroll inside it (.table-scroll) instead. */
.capital-panels>*{min-width:0}
.risk-dimensions{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:10px}
.risk-dimensions .pad{padding:14px}
.risk-dimensions a{text-decoration:none;color:inherit;font-size:12px}
.risk-dimensions strong{display:block;margin-top:12px;font-size:19px}
.risk-section{scroll-margin-top:24px;margin:25px 0}
.risk-item{margin:12px 0;border-left:3px solid #b78431}
.risk-facts{display:flex;flex-wrap:wrap;gap:22px;margin:15px 0}
.risk-facts small{display:block;color:var(--muted)}
.metric-inputs{white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px}
.target-cell{cursor:cell;white-space:nowrap;background:#f7faf8}
@media(max-width:800px){.capital-panels{grid-template-columns:1fr}.health-trend-row{grid-template-columns:60px minmax(60px,1fr)}.health-trend-row>span:last-child{grid-column:2}}
@media(max-width:1150px){.risk-dimensions{grid-template-columns:repeat(4,minmax(0,1fr))}}
@media(max-width:650px){.risk-dimensions{grid-template-columns:repeat(2,minmax(0,1fr))}}
.category-cell { min-width: 180px; max-width: 280px; }
.category-cell[ondblclick] { cursor: pointer; }
.category-notice { padding: 12px 16px; border-left: 3px solid var(--amber, #b7791f); background: var(--bg, #f6f8fa); font-size: 14px; line-height: 1.65; }
.category-summary { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 16px; margin: 20px 0; }
.category-summary > div { min-width: 0; padding: 12px; border: 1px solid var(--line, #dce2e8); }
.category-summary small { display: block; font-size: 14px; }
.category-summary strong { display: block; font-size: 24px; margin-top: 6px; }
.cost-structure .t td { vertical-align: top; }
@media (max-width: 760px) { .category-summary { grid-template-columns: 1fr; } }
@media (max-width: 760px) {
  .shell {grid-template-columns:minmax(0,1fr)}
  .side {position:static;height:auto;border-right:0;border-bottom:1px solid var(--line)}
  .side .nav {display:grid;grid-template-columns:repeat(3,minmax(0,1fr))}
  .side .navgroup {grid-column:1 / -1}
  .side .nav a {padding:8px 4px;gap:4px;min-width:0;overflow-wrap:anywhere}
  .side-foot {padding:8px 16px}
  .topbar {height:auto;min-height:60px;padding:12px 16px;flex-wrap:wrap}
  .topbar h1 {overflow-wrap:anywhere;min-width:0}
  .wrap {padding:16px 12px 40px}
  .ctxbar {flex-wrap:wrap;overflow-wrap:anywhere}
  #forecast-form .financial-heading>div {display:flex;flex-wrap:wrap;gap:8px}
  #forecast-form .archive-table table {min-width:720px}
}
.practice-brand{align-items:center;text-decoration:none;padding:12px 16px;gap:4px;min-height:92px;}
.practice-brand img{width:80px;height:80px;object-fit:contain;flex:none;}
.practice-brand span{color:var(--ink);}
.practice-brand b{display:block;}
.practice-brand small{display:block;font-size:8px;letter-spacing:.025em;color:var(--muted);}

/* A table wider than the screen scrolls inside its own card instead of
   pushing the whole page sideways. Phones are the case that matters:
   a page that scrolls horizontally makes every tap land somewhere else. */
.table-scroll{overflow-x:auto}

/* ── phone shell ──────────────────────────────────────────────────────────
   Two things made every page unusable on a phone.

   The navigation took 305px of an 812px screen, so the first thing anyone saw
   was the whole menu and they had to scroll past it to reach any content. It
   is now one compact bar: a small mark, the links in a single row that scrolls
   sideways the way the tab strip already does, and the language switch tucked
   beside the mark. The group headings go: with six destinations visible at
   once, "Clients" and "Firm" were labelling what the words already say.

   And a table wider than the screen pushed the whole page sideways, which makes
   every tap land somewhere other than where it looks. Any card holding a table
   scrolls inside itself instead. Cards whose table already fits show no
   scrollbar, so nothing changes for them. */
@media (max-width:760px){
  .side{position:relative}
  .side .brand{padding:10px 14px 6px;gap:8px;align-items:center}
  .side .brand img{width:32px;height:32px}
  .side .brand small{display:none}
  .side .brand b{font-size:14px}
  .side .navgroup{display:none}
  .side .nav{display:flex;flex-direction:row;flex-wrap:nowrap;overflow-x:auto;gap:2px;
             padding:0 10px 8px;scrollbar-width:none;-ms-overflow-style:none}
  .side .nav::-webkit-scrollbar{display:none}
  .side .nav a{flex:0 0 auto;flex-direction:row;align-items:center;white-space:nowrap;padding:8px 11px;overflow-wrap:normal}
  .side-foot{position:absolute;top:10px;right:12px;padding:0;border-top:0}
  /* A flex row with no wrap squeezes its children until the text breaks one
     character per line. Let these rows wrap instead. */
  .toolbar{flex-wrap:wrap;gap:10px}
  .toolbar .spacer{display:none}
  .toolbar .input{max-width:none;flex:1 1 100%}
  .seg{flex:0 0 auto}
  .seg button{white-space:nowrap}
  .finance-actions{flex-wrap:wrap}
  /* A table marked .stack turns into one block per row on a phone. Each value
     is prefixed with its own column heading, so nothing has to be scrolled
     sideways to be understood. Tables not marked .stack keep scrolling. */
  table.t.stack, table.t.stack tbody, table.t.stack tr,
  table.t.stack td{display:block;width:auto}
  table.t.stack thead{display:none}
  table.t.stack tr{padding:11px 16px 12px;border-bottom:1px solid var(--line)}
  table.t.stack tbody tr:last-child{border-bottom:0}
  table.t.stack td,
  table.t.stack td.r{padding:2px 0;border:0;display:flex;gap:12px;
                     align-items:baseline;text-align:left;font-size:13px}
  table.t.stack td::before{content:attr(data-label);flex:0 0 38%;
                           color:var(--muted);font-size:12px;line-height:1.5}
  table.t.stack td:first-child{padding:0 0 6px;font-size:14px}
  table.t.stack td:first-child::before{display:none}
  table.t.stack td:first-child>div{display:inline}
  table.t.stack td:first-child .sub{margin-left:8px}
  .card:has(> table.stack){overflow-x:visible}
  .card:has(> table){overflow-x:auto}
  .card:has(> .card-h + table){overflow-x:auto}
}

/* ── the invoice line editor ───────────────────────────────────────────────
   A form is not a report. The six-column table this replaces fitted a 520px
   modal only by squeezing the quantity and rate boxes down to a few characters
   and scrolling the rest out of view, which is the worst place to put a scroll:
   under the thing being typed into. */
.modal.roomy{max-width:760px}
.sl-lines{display:grid;gap:10px}
.sl-line{border:1px solid var(--line);border-radius:var(--r-sm);padding:12px 14px;
         display:grid;gap:8px;background:var(--surface-2)}
.sl-top{display:flex;gap:8px;align-items:center}
.sl-top .sl-item{flex:1 1 auto;min-width:0}
.sl-drop{flex:0 0 auto;color:var(--muted)}
.sl-nums{display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap}
.sl-field{display:flex;flex-direction:column;gap:3px;min-width:0}
.sl-field>span{font-size:11.5px;color:var(--muted)}
.sl-field .input{width:110px}
.sl-amt{margin-left:auto;text-align:right}
.sl-amt strong{font-variant-numeric:tabular-nums;font-size:15px;padding-bottom:7px}
@media (max-width:760px){
  .sl-nums{gap:10px}
  .sl-field .input{width:88px}
}

/* Something the invoice needs before it can be sent, stated where it is fixed
   rather than discovered on the printed sheet. */
.warn-bar {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  padding: 8px 12px; margin: 0 0 10px; border-radius: 8px;
  background: #fff7e6; border: 1px solid #f0c36d; color: #6b4e00; font-size: 13px;
}

/* ── the sign-in gate ─────────────────────────────────────────────────────
   Replaces the shell rather than covering it. The navigation names what this
   practice keeps, so it must not be readable behind a login box. */
body.gated .shell { display: none; }

#authgate {
  position: fixed; inset: 0; z-index: 9000;
  display: flex; align-items: center; justify-content: center;
  padding: 24px; overflow-y: auto;
  background: var(--bg, #f4f6f8);
}
.gate-card {
  width: 100%; max-width: 380px;
  background: #fff; border: 1px solid var(--line, #dfe3e8);
  border-radius: 12px; padding: 28px 26px;
  box-shadow: 0 10px 30px rgba(16, 32, 48, .08);
}
.gate-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.gate-brand img { width: 34px; height: 34px; object-fit: contain; }
.gate-brand b { display: block; font-size: 15px; }
.gate-brand small { display: block; font-size: 10px; letter-spacing: .08em; color: var(--muted); }
.gate-card h2 { margin: 0 0 6px; font-size: 19px; }
.gate-sub { margin: 0 0 18px; font-size: 13px; color: var(--muted); line-height: 1.55; }
.gate-card .field { margin-bottom: 12px; }
.btn.block { display: block; width: 100%; margin-top: 6px; }
.gate-error {
  margin-top: 14px; padding: 9px 11px; border-radius: 7px;
  background: #fdecea; border: 1px solid #f2b8b1; color: #8a1c10;
  font-size: 13px; line-height: 1.5;
}

/* Who is signed in, above the language switch. */
#whoami { padding: 10px 12px; border-top: 1px solid var(--line, #dfe3e8); }
#whoami .who-name { font-size: 13px; font-weight: 600; }
#whoami .who-role { font-size: 11px; color: var(--muted); margin-bottom: 7px; }

/* ── the shared calendar ──────────────────────────────────────────────── */
.cal-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cal-title { min-width: 8em; text-align: center; }

.cal-head, .cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.cal-head { margin-bottom: 4px; }
.cal-head div {
  text-align: center; font-size: 12px; color: var(--muted);
  padding: 4px 0; font-weight: 600;
}
.cal-cell {
  min-height: 74px; padding: 6px 7px; border: 1px solid var(--line, #dfe3e8);
  border-radius: 7px; background: #fff; cursor: pointer;
  display: flex; flex-direction: column; gap: 3px;
}
.cal-cell:hover { border-color: var(--accent, #2f7d62); }
.cal-cell.blank { border: 0; background: transparent; cursor: default; min-height: 0; }
.cal-cell.weekend { background: #fafbfc; }
/* A weekday with nobody in is nearly always a rest-day pattern set wrong.
   Marked rather than left to be noticed. */
.cal-cell.nobody { background: #fff7e6; border-color: #f0c36d; }
.cal-cell.today { border-color: var(--accent, #2f7d62); border-width: 2px; padding: 5px 6px; }
.cal-num { font-size: 13px; font-weight: 600; }
.cal-count { font-size: 12px; }
.cal-in { font-weight: 600; }
.cal-of, .cal-none { color: var(--muted); }
.cal-note {
  font-size: 11px; line-height: 1.35; color: var(--muted);
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}

/* the day panel */
.day-h { margin: 16px 0 6px; font-size: 14px; }
.day-list { list-style: none; margin: 0; padding: 0; }
.day-list li {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 5px 0; border-bottom: 1px solid var(--line, #eef1f4);
}
.day-list li:last-child { border-bottom: 0; }
.day-name { font-weight: 550; }
.readonly-note {
  padding: 8px 10px; background: #f7f8f9; border-radius: 6px;
  border: 1px solid var(--line, #dfe3e8); min-height: 20px;
}

/* On a phone a seven-column month is unreadable at 74px tall. The columns
   stay -- a week that is not seven across is not a calendar -- but the cells
   shrink to the number and a dot for the note. */
@media (max-width: 760px) {
  .cal-cell { min-height: 48px; padding: 4px 3px; gap: 1px; }
  .cal-num { font-size: 12px; }
  .cal-count { font-size: 10px; }
  .cal-note {
    font-size: 0; height: 5px; width: 5px; border-radius: 50%;
    background: var(--accent, #2f7d62); margin-top: 2px;
  }
  .cal-head div { font-size: 11px; }
}

/* attendance rows in the day panel */
.att-bulk {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  padding: 8px 0 10px; border-bottom: 1px solid var(--line, #eef1f4); margin-bottom: 4px;
}
.att-row { gap: 8px; }
.att-row .att-pick { width: auto; min-width: 8.5em; padding: 4px 8px; font-size: 13px; }
/* A row reads as in or out before anything is read: the list is scanned, not
   studied. The bar is on the left so it survives the phone layout below. */
.att-row.att-in { box-shadow: inset 3px 0 0 var(--accent, #2f7d62); padding-left: 9px; }
.att-row.att-out { box-shadow: inset 3px 0 0 var(--line, #cfd6dd); padding-left: 9px; }

@media (max-width: 760px) {
  .att-row { flex-wrap: wrap; }
  .att-row .spacer { display: none; }
  .att-row .att-pick { width: 100%; margin-top: 4px; }
}

/* the day's notes: a list of lines, each strikeable on its own */
.note-list { list-style: none; margin: 0 0 8px; padding: 0; }
.note-list li {
  display: flex; align-items: baseline; gap: 8px;
  padding: 5px 0; border-bottom: 1px solid var(--line, #eef1f4);
}
.note-list li:last-child { border-bottom: 0; }
.note-text { flex: 1; line-height: 1.45; }
.note-list .note-x { padding: 0 7px; line-height: 1.4; color: var(--muted); }
.note-list .note-x:hover { color: #8a1c10; }
.note-empty { margin: 0 0 8px; }

/* a cell with more lines than it can show says how many */
.cal-more {
  display: inline-block; margin-left: 4px; padding: 0 4px;
  border-radius: 6px; background: var(--line, #e7ebef); font-size: 10px;
}
@media (max-width: 760px) { .cal-more { display: none; } }

/* ── overview charts ──────────────────────────────────────────────────── */
.chart-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.chart-card { margin: 0; }
/* The ring's radius follows the SHORTER side, so height is what decides how
   much room the labels around it get. At 240 the top label sat 5px from the
   edge. */
.chart-box { width: 100%; height: 276px; }
.chart-box.tall { height: 280px; }
.chart-empty {
  display: flex; align-items: center; justify-content: center;
  height: 140px; color: var(--muted); font-size: 13px;
}

/* The figures behind each pie. Several slice colours sit below 3:1 on a white
   card, so the numbers have to be reachable without reading the colour -- this
   is that, not a nicety. Closed by default so it does not crowd the chart. */
.chart-details { margin-top: 6px; }
.chart-details summary {
  cursor: pointer; font-size: 12px; color: var(--muted); padding: 4px 0;
}
.chart-details summary:hover { color: var(--ink); }
.chart-table { margin-top: 4px; font-size: 12px; }
.chart-table td { padding: 4px 6px; }

@media (max-width: 860px) {
  .chart-row { grid-template-columns: 1fr; }
  /* Taller on a phone, not shorter: the ring keeps its size and the legend
     that replaces the labels around it needs a band of its own underneath. */
  .chart-box { height: 280px; }
  .chart-box.tall { height: 240px; }
}

/* A statutory holiday is a fact about the date, not a state somebody set, so
   it is marked on the cell rather than coloured like an attendance choice. */
.cal-cell.holiday { background: #f3f7fb; border-color: #c9d9ea; }
.cal-hol {
  font-size: 10px; line-height: 1.25; color: #2a5d8f; font-weight: 600;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
@media (max-width: 760px) {
  .cal-hol { font-size: 0; height: 4px; width: 100%; border-radius: 2px; background: #6d9fd0; }
}

/* ── reviewing a scan ─────────────────────────────────────────────────────
   The document beside the fields, because checking a figure means comparing
   it with the page it came from. It used to be a download link, which is a
   document nobody looks at while they work. */
/* Wide enough for the document and the fields side by side. The default
   modal is 520px, which collapsed the left column to 75px -- a preview that
   small is not a preview, it is a thumbnail nobody can check a figure on. */
.modal:has(.scan-review) { max-width: 1060px; }
.scan-review { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: 16px; }
.scan-doc { position: sticky; top: 0; align-self: start; }
.scan-frame {
  width: 100%; height: 420px; object-fit: contain;
  background: #f2f4f6; border: 1px solid var(--line, #E4E9E5); border-radius: 7px;
}
.scan-doc-actions { display: flex; gap: 6px; margin-top: 6px; }
.scan-fields { min-width: 0; }

/* The total is not posted, so it does not look like a field that will be:
   flat, not a box, with the verdict beside it. */
.scan-total {
  padding: 7px 10px; border-radius: 6px; font-variant-numeric: tabular-nums;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.scan-total.ok { background: #EAF4EF; color: var(--accent-ink, #0B4536); }
.scan-total.bad { background: #FBE3DF; color: var(--oxide, #96322B); font-weight: 600; }

@media (max-width: 900px) {
  .scan-review { grid-template-columns: 1fr; }
  .scan-doc { position: static; }
  .scan-frame { height: 300px; }
}

/* ── taking the photograph ───────────────────────────────────────────────

   The camera is the primary action on a phone and absent on a desktop, so
   the row is a stack that the buttons fill rather than a fixed pair: with
   one button it reads as one action, with two the camera leads. */
.scan-pick { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.scan-pick .btn { flex: 1 1 160px; }

/* Tall enough to hit with a thumb while holding a receipt in the other
   hand. 48px is the usual floor for a touch target and this is the one
   control on the screen that is always used that way. */
.scan-shoot {
  min-height: 48px; display: inline-flex; align-items: center;
  justify-content: center; gap: 9px; font-size: 1.02rem;
}

/* A lens rather than an emoji: an emoji is a font the device may not have,
   and renders at a size and colour this stylesheet does not control. */
.scan-lens {
  width: 17px; height: 14px; border: 2px solid currentColor; border-radius: 3px;
  position: relative; flex: none;
}
.scan-lens::before {
  content: ''; position: absolute; left: 4.5px; top: 2.5px;
  width: 6px; height: 6px; border: 2px solid currentColor; border-radius: 50%;
}
.scan-lens::after {
  content: ''; position: absolute; left: 3px; top: -4px;
  width: 7px; height: 3px; background: currentColor; border-radius: 2px 2px 0 0;
}

/* The shot, big enough to judge. Whether the text is sharp is the ONE
   question being asked here, and it cannot be answered on a thumbnail --
   which is why this is capped by viewport height, not by a pixel count. */
.scan-shot { margin: 0 0 10px; }
.scan-shot a { display: block; }
.scan-shot img {
  width: 100%; max-height: 46vh; object-fit: contain; display: block;
  background: #f2f4f6; border: 1px solid var(--line, #E4E9E5); border-radius: 7px;
}
.scan-shot figcaption {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 7px;
}
.scan-shot figcaption .btn { margin-left: auto; }

/* Resolution is the difference between a photograph that reads and one that
   returns nothing, so a short edge is said plainly and in the colour used
   for things that will go wrong -- not as a grey hint under the fold. */
.scan-thin {
  flex-basis: 100%; order: 1;
  padding: 6px 9px; border-radius: 6px;
  background: #FBE3DF; color: var(--oxide, #96322B); font-size: .86rem;
}
.scan-chosen { font-variant-numeric: tabular-nums; margin: 0 0 10px; }


/* A phone screen has to hold the shot AND the button that sends it. At 46vh
   the preview pushed Save below the fold, so the one action somebody came to
   this screen to perform was the one thing they could not see. The preview
   gives up the height; tapping it still opens the full-size image, which is
   where sharpness is properly judged anyway. */
@media (max-width: 600px) {
  .scan-shot img { max-height: 34vh; }
}


/* ── the import dialog scrolls one way ──────────────────────────────────

   It scrolled BOTH ways, and the sideways half hid half the mapping: the
   fields for 自动分类, 单据日期, 客户/供应商 and 税前金额 sat past the right
   edge of a 520px dialog with nothing to suggest they were there.

   Two causes, and both had to go.

   .finance-grid is two columns and collapses to one at max-width:800px --
   which is the VIEWPORT's width, not the dialog's. On a wide screen the
   query never fires, so two columns were squeezed into 520px minus padding.
   Inside a modal it is always one column, because the modal is always narrow.

   .modal .card-b is a grid, and a grid item defaults to min-width:auto: it
   refuses to shrink below its content's intrinsic width. The eight-column
   preview table therefore pushed the whole dialog wider than the screen
   rather than scrolling inside its own box. minmax(0, 1fr) is what lets it
   shrink, and .finance-scroll then does the scrolling where it belongs.  */

.modal .card-b{grid-template-columns:minmax(0,1fr);}
.modal .card-b > *{min-width:0;}
.modal .finance-grid{grid-template-columns:1fr;}
.modal .finance-scroll{max-width:100%;overflow:auto;}
.modal .finance-scroll table{width:max-content;min-width:100%;}

/* ── the duplicate choice ────────────────────────────────────────────────
   Whole rows are clickable, and each carries the supplier, the description
   and where the entry came from. Deciding whether two entries are the same
   purchase is not something anybody can do from an id and a number. */
.dup-list{display:grid;gap:8px;margin:10px 0}
.dup-row{display:flex;gap:10px;align-items:flex-start;padding:10px 12px;cursor:pointer;
  border:1px solid var(--line,#E4E9E5);border-radius:7px}
.dup-row:hover{background:var(--surface-3,#f4f6f5)}
.dup-row:has(input:checked){border-color:var(--accent-ink,#0B4536);
  background:var(--accent-soft,#EAF4EF)}
.dup-row input{margin-top:3px;flex:none}
.dup-row span{display:block;min-width:0}
.dup-row .sub{font-size:12px;color:var(--muted)}

.dup-row.taken{opacity:.62;cursor:default;background:var(--surface-3,#f4f6f5)}
.dup-row.taken:hover{background:var(--surface-3,#f4f6f5)}
.dup-row .taken-why{color:var(--oxide,#96322B);margin-top:4px}

/* An import row has no document to look at -- the file is the whole import,
   not this line -- so the fields take the width the preview would have had. */
.scan-review.no-doc{grid-template-columns:minmax(0,1fr);}
.modal:has(.scan-review.no-doc){max-width:640px;}


/* ── finding one document among many ──────────────────────────────────── */
.intake-filter{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.intake-filter .input{flex:1 1 280px;min-width:0}
.intake-states{display:flex;gap:6px;flex-wrap:wrap}
.chip{border:1px solid var(--line,#E4E9E5);background:var(--surface,#fff);
  border-radius:999px;padding:4px 11px;font-size:12.5px;cursor:pointer;
  color:var(--ink-2,#44504a)}
.chip:hover{background:var(--surface-3,#f4f6f5)}
.chip.on{background:var(--accent-soft,#EAF4EF);border-color:var(--accent-ink,#0B4536);
  color:var(--accent-ink,#0B4536);font-weight:600}

/* A sortable header looks like one before it is clicked, not after. */
th.sortable{cursor:pointer;user-select:none;white-space:nowrap}
th.sortable:hover{color:var(--accent-ink,#0B4536)}
th.sortable .arrow{margin-left:4px;font-size:9px;opacity:.7}
th.sortable.on{color:var(--accent-ink,#0B4536)}


/* ── acting on several at once ────────────────────────────────────────── */
.t td.tick, .t th.tick{width:32px;text-align:center;padding-left:10px;padding-right:0}
.t td.tick input, .t th.tick input{cursor:pointer}

/* The bar appears only with a selection, so it never takes space from the
   list it acts on. */
.bulk-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:12px 0 0;
  padding:10px 14px;border-radius:8px;background:var(--accent-soft,#EAF4EF);
  border:1px solid var(--accent-ink,#0B4536)}
.bulk-bar[hidden]{display:none}
.bulk-bar .picked{color:var(--accent-ink,#0B4536);margin-right:4px}
.bulk-bar .picked b{font-size:15px}

.bulk-list{max-height:230px;overflow:auto;margin:10px 0;display:grid;gap:6px}
.bulk-list > div{padding:7px 10px;border-radius:6px;background:var(--surface-3,#f4f6f5)}
.bulk-list .sub{display:block;font-size:12px;color:var(--muted)}
.bulk-bad{background:#FBE3DF !important}
.bulk-bad .why{color:var(--oxide,#96322B)}


/* What the ring could not draw, said where the ring is. */
.chart-note{margin:8px 0 0;font-size:12px;line-height:1.5;color:var(--oxide,#96322B);
  background:#FBE3DF;border-radius:6px;padding:7px 10px}

/* The documents list. It sat in a 270px scroll box (.finance-scroll), which
   showed six rows at a time inside the page's own scroll. It is paged now, so
   a page is shown whole and the box only scrolls sideways on a narrow screen. */
.intake-table{overflow-x:auto}
/* Nine columns since the supplier one: at the tables' usual 20px a side, the
   Open button was squeezed into a column of single characters and the type
   into four lines. Narrower sides here; short cells keep to one line; the long
   text (file, supplier, category) wraps; past that the box scrolls. */
.intake-table table.t td,.intake-table table.t th{padding-left:10px;padding-right:10px}
.intake-table td.nowrap,.intake-table td.kind,.intake-table td.nowrap .btn,.intake-table td.nowrap .pill{white-space:nowrap}
.intake-table td.wrap{overflow-wrap:anywhere}

/* A company document that a renewal has replaced: kept, listed, not current. */
.t tr.muted-row td{color:var(--muted)}
