:root{
  /* The neutrals carry a green bias on purpose. They used to be blue --
     #f4f6f8 and #1c2530 -- against a green brand, and the two pulled apart.
     The teal itself has not moved; only the greys around it. */
  --bg:#f5f7f5; --card:#fff; --ink:#14201b; --muted:#5b6c62;
  --line:#dce3dd; --brand:#0b6b5a; --brand2:#0e8a73; --bad:#a6271c; --ok:#0b6b5a;
  /* The second business gets its own bar colour. Only the bar: --brand is the
     accent on three hundred other things, and recolouring all of it would be a
     different app rather than the other half of this one. A warm clay against
     the teal, dark enough to keep white text well clear of AA. */
  --brand-shop:#7a4a2b;
  /* Codes, batches, expiries and money are read as shapes, not words. A
     monospaced face with tabular figures makes PRAPI5D against PRAP15D, and
     1039.20 against 1039.02, a difference you see rather than one you check.
     A system stack because the CSP has no font-src: default-src 'self' blocks
     Google Fonts outright, and a self-hosted face buys little on a counter
     tool one person uses. */
  --register:ui-monospace,"Cascadia Mono","SF Mono",Menlo,Consolas,monospace;
}
*{box-sizing:border-box}
body{margin:0;font:15px/1.4 system-ui,Segoe UI,Roboto,sans-serif;background:var(--bg);color:var(--ink)}

/* ---- a screen arrives finished -------------------------------------------
   pageboot.js holds <main> back until the data the page opens with is in and
   the page has stopped rearranging itself, then lets go of all of it at once.
   See that file for what counts as finished.

   visibility, not display: held this way the page is laid out and measurable
   the whole time it is hidden, which is what the charts and the suggestion
   dropdowns need -- they size themselves off elements that would otherwise be
   measuring zero. The bar across the top is never held. The server renders it,
   so it is right from the first byte, and leaving it up is what makes the wait
   read as this screen loading rather than as nothing happening.

   Both rules are keyed off a class the script adds, so a browser that never
   runs it -- or an older cached copy of it -- simply gets the old behaviour
   rather than a page that never appears. */
html.booting main{visibility:hidden}
html.revealed main{animation:pgin .15s ease-out}
/* Opacity only. A transform here would make <main> the containing block for
   everything fixed inside it, which is where the row dialogs sit. */
@keyframes pgin{from{opacity:0}}

/* A screen that is taking its time says so. Nothing appears for the first
   450ms -- most loads are finished well inside that, and a progress bar that
   flashes up and vanishes is itself the jitter this is here to remove. White,
   because the only thing it is ever drawn over is the header, and that is
   teal on one business and clay on the other. */
html.booting::after{content:"";position:fixed;left:0;top:0;width:100%;height:3px;
  z-index:60;pointer-events:none;opacity:0;
  background:linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,.95),rgba(255,255,255,0));
  background-size:38% 100%;background-repeat:no-repeat;
  animation:pgwait 1.15s .45s linear infinite}
/* opacity lives in the keyframes rather than in a fill mode: with `backwards`
   the bar would be solid through the 450ms delay, which is the one thing it
   must not be. */
@keyframes pgwait{from{opacity:1;background-position:-38% 0}
  to{opacity:1;background-position:138% 0}}
@media (prefers-reduced-motion:reduce){
  html.revealed main{animation:none}
  html.booting::after{animation-name:none}
}
header{display:flex;align-items:center;gap:10px;padding:14px 22px;background:var(--brand);color:#fff}
/* The bar wears the colour of the business it is showing. Two independent sets
   of books behind one sign-in is exactly where a bill gets written into the
   wrong one, and a strip that changes colour is seen before it is read. */
header.ent-shop{background:var(--brand-shop)}
/* Nothing in the bar may break across two lines. A header that reflows as
   accounts are added is a header that will do it again -- and it already did:
   the People link pushed the brand onto a second line, and "Vinod Kumar Gupta"
   broke over three lines below 1400px, which read as the whole nav wrapping. */
header .nav a, header .chip, header .user{white-space:nowrap}
/* The mark, the shop's name, and beneath it the business currently open. The
   second line costs no width -- it is shorter than the name above it -- and is
   the only thing in the bar that says which set of books you are in.
   The leaf is white on the brand bar, so logo-mark.svg carries its own fill:
   an <img> cannot inherit currentColor from the page around it.
   All of it scoped to the header on purpose. A bare .brand also matched the
   Brand cell in the invoice line table -- <td class="brand edit-cell"> -- which
   turned a table cell into a flex container, so it stopped stretching to the
   row and sat a pixel low at 31px against its neighbours' 45px. */
header .brandwrap{position:relative;flex:none}
header .brand{display:flex;align-items:center;gap:9px;text-decoration:none;color:inherit;
  background:none;border:0;padding:0;margin:0;font:inherit;text-align:left;cursor:pointer}
header .brand img{display:block;flex:none}
header .brand .wordmark{display:flex;flex-direction:column;line-height:1.14;white-space:nowrap}
header .brand .nm{font-size:17px;font-weight:600}
header .brand .ent{font-size:10.5px;font-weight:700;letter-spacing:.11em;
  text-transform:uppercase;opacity:.74}
header .brand:hover .nm{text-decoration:underline}
/* A caret only where there is somewhere to go: a person with one business is
   shown a plain link home, not a menu holding a single choice. */
header .brand .caret{flex:none;width:0;height:0;margin-left:1px;opacity:.85;
  border:4px solid transparent;border-top:5px solid currentColor;transform:translateY(2px)}
header .brand[aria-expanded="true"] .caret{transform:translateY(-1px) rotate(180deg)}

/* The switcher is in the page already, hidden rather than absent, so opening
   it waits for nothing and moves nothing behind it. */
header .switcher{position:absolute;top:calc(100% + 8px);left:0;z-index:40;min-width:184px;
  display:flex;flex-direction:column;gap:2px;padding:5px;
  background:var(--card);border:1px solid var(--line);border-radius:10px;
  box-shadow:0 12px 30px rgba(20,32,27,.22)}
header .switcher[hidden]{display:none}   /* display:flex would outrank the default */
header .switcher a{display:flex;align-items:center;gap:9px;padding:9px 11px;border-radius:7px;
  color:var(--ink);text-decoration:none;font-size:14px;font-weight:600}
/* The dot is always there and only sometimes visible, so the two labels start
   at the same place whichever one is current. */
header .switcher a::before{content:"";flex:none;width:7px;height:7px;border-radius:50%;
  background:currentColor;opacity:0}
header .switcher a.on::before{opacity:1}
header .switcher a:hover{background:#eef7f4}
header .switcher a.on{color:var(--brand)}
header.ent-shop .switcher a:hover{background:#f7f0e9}
header.ent-shop .switcher a.on{color:var(--brand-shop)}
.login-logo{display:block;margin:0 auto 12px}
.pill{font-size:12px;padding:3px 10px;border-radius:20px;background:rgba(255,255,255,.2)}
.pill.ok{background:#0a5}.pill.bad{background:#c0392b}
/* The health dot, on the Cloud link. Colour alone would be a poor signal, so
   the link's title says what it means and a screen reader gets the same words. */
.nav-cloud .dot{
  display:inline-block;width:7px;height:7px;border-radius:50%;
  margin-left:6px;vertical-align:middle;background:#9bb3a8;
}
.nav-cloud .dot.ok{background:#31d17e;box-shadow:0 0 0 2px rgba(49,209,126,.25)}
.nav-cloud .dot.bad{background:#ff6b5a;box-shadow:0 0 0 2px rgba(255,107,90,.3)}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
main{max-width:1080px;margin:18px auto;padding:0 16px;display:flex;flex-direction:column;gap:16px}
.card{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:16px}
h2{font-size:15px;margin:0 0 10px}
.grid{display:grid;grid-template-columns:2fr 1fr 1fr;gap:14px}
/* Bill details carries four fields, not three. */
.grid.bill{grid-template-columns:1.7fr .8fr 1.8fr 1fr}
@media(max-width:900px){.grid.bill{grid-template-columns:1fr 1fr}}
/* Writing a bill, in one card at the top of the screen that also lists them.
   It was three cards on a page of its own -- bill details, medicines, then a
   remark and Save -- and they were never three things to think about: they are
   four parts of writing one bill, so the rules between them are spacing rather
   than three separate boxes with three separate shadows. */
#writeBill .grid.bill{margin-bottom:14px}
#writeBill #lines{margin-top:2px}
/* The remark and the way to commit the bill, on one line, divided from the
   totals above them because that is the moment the bill stops being edited. */
#writeBill .billfoot{display:flex;align-items:flex-end;gap:16px;flex-wrap:wrap;
  margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
#writeBill .billfoot .field{flex:1 1 260px;min-width:0;margin:0}
#writeBill .billfoot .actions{margin:0;flex:0 0 auto}
@media(max-width:560px){ #writeBill .billfoot .actions{width:100%} }
.field{position:relative;display:flex;flex-direction:column;gap:5px}
label{font-size:12px;color:var(--muted)}
.sub, p.sub{color:var(--muted);font-size:12.5px;margin:-2px 0 12px;line-height:1.45}
input{padding:8px 10px;border:1px solid var(--line);border-radius:7px;font:inherit;width:100%;transition:border-color .15s,box-shadow .15s,background-color .15s}
input:focus{outline:2px solid var(--brand2);border-color:var(--brand2)}
.dropdown{position:absolute;top:100%;left:0;right:0;z-index:9;background:#fff;border:1px solid var(--line);
  border-radius:7px;box-shadow:0 8px 24px rgba(0,0,0,.1);max-height:260px;overflow:auto}
.opt{padding:8px 10px;cursor:pointer;border-bottom:1px solid var(--line);font-size:13px}
.opt:hover{background:#eef7f4}
.chosen{margin-top:6px;font-size:13px;color:var(--brand);font-weight:600}
.hidden{display:none}
table{width:100%;border-collapse:collapse;font-size:13px}
th,td{padding:6px 8px;border-bottom:1px solid var(--line);text-align:left}
th{font-size:11px;text-transform:uppercase;letter-spacing:.03em;color:var(--muted)}
.num{text-align:right}
/* Medicine and Brand stay in the reading face; everything else on a line is a
   code or a figure. */
.sn,
td input.code, td input.qty,
td.batch, td.exp, td.mrp, td.disc, td.rate, td.total,
.code-drop .c-code, .code-drop .c-batch, .code-drop .c-inv,
.code-drop .c-meta, .code-drop .c-mrp, .code-drop .stk{
  font-family:var(--register);
  font-variant-numeric:tabular-nums;
  letter-spacing:-.01em;
}
td input.code, td input.qty{font-size:14px}
/* Every .num cell in this app holds a figure, so the register face reaches all
   of them -- money, quantities, sizes -- without touching any markup. `.reg` is
   for the rest of the data: codes, batches, expiries, dates, invoice numbers.
   Names, brands and descriptions are words and stay in the reading face. */
td.num, td.reg{
  font-family:var(--register);
  font-variant-numeric:tabular-nums;
  letter-spacing:-.01em;
}
table td.num, table td.reg{font-size:13.5px}
td.mrp, td.disc, td.rate, td.total{font-size:13.5px}
td.total{font-weight:600;color:var(--ink)}
/* What RGHS pays, beside what the shop is charging. Quieter than the figures
   either side of it: it is somebody else's number, on the row for reference,
   and it must not read as part of the arithmetic that makes the total. */
td.rghs{color:var(--muted)}
/* A figure standing in for one RGHS has never given: the shop's own rate,
   carrying the dotted underline this app already uses on the Medicines screen
   for a number it is not sure of. Quiet on purpose -- it is still the best
   figure available for that line, and the column is a thing to look at, not a
   warning. */
td.rghs.own{
  text-decoration:underline dotted #b9c6bd; text-underline-offset:3px;
  cursor:help;
}
td input{padding:5px 7px}
td input.code{width:120px;text-transform:uppercase}
td input.qty{width:70px}
.sn{color:var(--muted)}
/* The figure the operator and the customer both look at. It was 17px grey
   text among two others of the same weight; it is now the largest thing on the
   screen, and the caution about stock sits in the same strip so one band
   answers both what this costs and whether anything is wrong. */
.totals{
  display:flex; align-items:baseline; justify-content:flex-end; gap:26px;
  padding:14px 14px; margin-top:10px; font-size:13.5px; color:var(--muted);
  background:#eef2ef; border:1px solid var(--line); border-radius:8px;
}
.totals b{
  margin-left:6px; color:var(--ink); font-weight:600;
  font-family:var(--register); font-variant-numeric:tabular-nums;
}
/* The RGHS figure is one of the quiet ones -- the same size and weight as
   Subtotal and Discount, not competing with the Total beside it, because it is
   a comparison offered and not the amount of this bill. What it could not
   include is written in smaller and lighter still: enough to stop the number
   being read as the whole bill, not enough to look like an error. */
.totals #rghsTotal{color:var(--brand)}
.totals .unpriced{margin-left:6px; font-size:11.5px; color:var(--muted); cursor:help}
/* Charged over what RGHS approves is the amber the Rates screen uses for the
   same thing, charged under is the brand teal, and agreement is quiet. One
   comparison, one set of colours, wherever in the app it is made. */
.totals .diff{cursor:help}
.totals .diff.over{color:#a35a12}
.totals .diff.under{color:var(--brand)}
.totals .diff.same{color:var(--muted); font-weight:400}
.totals .grand{display:flex; align-items:baseline; gap:9px; margin-left:6px}
.totals .grand .tl{
  font-size:11px; letter-spacing:.11em; text-transform:uppercase; color:var(--muted);
}
.totals .grand b{
  margin-left:0; font-size:29px; font-weight:600; line-height:1;
  color:var(--brand); letter-spacing:-.02em;
}
.actions{display:flex;align-items:center;gap:12px;margin-top:10px}
button{font:inherit;padding:8px 16px;border-radius:7px;border:1px solid var(--line);cursor:pointer;background:#fff}
button.primary{background:var(--brand);color:#fff;border-color:var(--brand);font-weight:600}
button.primary:hover{background:var(--brand2)}
button.ghost{background:#fff;color:var(--muted)}
.del{padding:3px 9px}
#saveMsg.ok{color:var(--ok);font-weight:600}
#saveMsg.bad{color:var(--bad);font-weight:600}
#saveMsg.warn{color:#8a6100;font-weight:600}
@media(max-width:720px){.grid{grid-template-columns:1fr}table{font-size:12px}}

/* auth */
.user{font-size:13px;opacity:.9;margin-left:12px}
.logout{background:rgba(255,255,255,.15);color:#fff;border:1px solid rgba(255,255,255,.4);
  padding:5px 12px;font-size:13px}
.logout:hover{background:rgba(255,255,255,.28)}
.login-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;background:var(--bg)}
.login-card{background:#fff;border:1px solid var(--line);border-radius:12px;padding:30px 28px;
  width:320px;display:flex;flex-direction:column;box-shadow:0 12px 40px rgba(0,0,0,.08)}
.login-card h1{color:var(--brand);font-size:20px;margin:0}
.login-card .sub{color:var(--muted);font-size:13px;margin:4px 0 18px}
.login-card label{margin:10px 0 4px}
.login-card button{margin-top:18px}
#err{margin-top:10px;font-size:13px;min-height:16px}

/* code suggestions dropdown — one line per batch.
   `right` from .dropdown must be cleared or the panel stretches to the page
   edge. Column widths come from a colgroup measured against the widest value
   in the data (see measureColumns in app.js), so they are the same on every
   search; only Medicine is capped, and it scrolls inside its own cells. */
.code-drop{position:absolute;right:auto;z-index:60;max-height:340px;overflow:auto;
  width:max-content;max-width:96vw;font-size:13px}
/* fixed layout: the colgroup widths measured from the data are authoritative,
   so every column is identical on every search and nothing is truncated */
.code-drop .sug-table{table-layout:fixed;border-collapse:collapse}
.code-drop .sug-table th{position:sticky;top:0;z-index:2;background:#eef2f4;
  border-bottom:1px solid var(--line);font-size:11px;text-transform:uppercase;
  letter-spacing:.03em;color:var(--muted);font-weight:700;padding:6px 10px;
  text-align:left;white-space:nowrap}
.code-drop .sug-table td{padding:6px 10px;border-bottom:1px solid var(--line);
  white-space:nowrap;vertical-align:middle}
.code-drop tr.sug{cursor:pointer}
.code-drop tr.sug:hover td{background:#eef7f4}
.code-drop .c-code{font-weight:700;color:var(--brand);text-transform:uppercase;font-size:12px;
  letter-spacing:.02em}
.code-drop .c-name{color:var(--ink);padding-right:0}
/* only the medicine name scrolls; the cells scroll in sync (see app.js) so the
   column moves as one. A thin bar appears only on names that overflow. */
.code-drop .cellscroll{overflow-x:auto;overflow-y:hidden;white-space:nowrap;
  scrollbar-width:thin;padding-bottom:1px}
.code-drop .cellscroll::-webkit-scrollbar{height:5px}
.code-drop .cellscroll::-webkit-scrollbar-thumb{background:#c3ccd4;border-radius:3px}
.code-drop .c-batch{font-size:12px;color:#3a4652}
.code-drop .c-inv{font-size:12px;color:#8a6d3b}
.code-drop .c-meta{font-size:12px;color:var(--muted)}
.code-drop .c-mrp{text-align:right;font-variant-numeric:tabular-nums;color:var(--ink)}
.code-drop .c-rghs{text-align:right;font-variant-numeric:tabular-nums;color:var(--ink)}
.code-drop .stk{text-align:right;font-weight:700}
.code-drop .stk.in{color:var(--brand)}
.code-drop .stk.out{color:var(--bad)}

/* nav + admin pages */
.nav{display:flex;gap:10px;margin-left:18px}
.nav a{color:#fff;text-decoration:none;font-size:13px;padding:6px 12px;border-radius:6px;opacity:.85}
.nav a:hover{background:rgba(255,255,255,.15);opacity:1}
.nav a.active{background:rgba(255,255,255,.22);opacity:1;font-weight:600}
.filters{display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap}
.filters .field{flex:0 0 auto}
.filters .field input{width:170px}
.filters .field input[type=date]{width:150px}
/* One box over a whole list, in a row of filters sized for narrow ones. It
   takes the space the others do not: what goes into it is a medicine name or a
   phrase off a bill, not a date, and a 170px box turns either into a keyhole. */
.filters .field.wide{flex:1 1 320px;min-width:0}
.filters .field.wide input{width:100%}
.filters button{white-space:nowrap;align-self:flex-end}
.summary{margin:12px 0;font-size:14px;color:var(--muted);font-weight:600}
.chk{font-size:13px;color:var(--muted);display:flex;align-items:center;gap:6px}
.chk input{width:auto}
/* The three access boxes. In the Add card they are a row of their own; in the
   People table they are inside a cell, and a cell must not become a flex
   container -- that is the trap the brand link fell into, where the cell then
   stopped stretching to its row. */
.actions .acc{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
td.acc{white-space:nowrap}
td.acc .chk{display:inline-flex;gap:5px;margin-right:12px}
td.acc .chk:last-child{margin-right:0}
td.acc .chk:has(input:disabled){opacity:.55}
/* Your own account, when nothing has been given to it. There is no plain .bad
   colour in this file -- only #saveMsg.bad -- so this says it itself. Amber
   rather than red: it is not a mistake the person reading it made, it is the
   same "somebody still has to do something" as a batch with no expiry. */
#pAccess.bad{color:#7a5a10;background:#fdf6e3;border-left:3px solid #e0b34d;
  border-radius:6px;padding:8px 11px;margin:0 0 12px}
td input{width:100%}
td input.code{width:90px}

/* stock / history / resources */
/* A batch with nothing left reads as spent -- but it is not disabled, and it
   can still be archived or edited. Fading the whole row with opacity dragged
   its buttons down with it, so Archive looked dead when it was always live.
   Only the text fades now; the controls keep their own colours. */
.outrow td{color:#667382}
.outrow td b{color:#667382}
.outrow .edit{color:var(--ink)}
.tag{font-size:11px;background:#eef2f4;color:var(--muted);padding:2px 7px;border-radius:5px}
.nochange{font-size:12px;color:var(--muted)}
.meter{margin:14px 0}
.meter-top{display:flex;justify-content:space-between;font-size:14px;margin-bottom:5px}
.meter-top em{color:var(--muted);font-style:normal}
.bar{height:12px;background:#eef2f4;border-radius:7px;overflow:hidden}
.fill{height:100%;border-radius:7px;transition:width .4s}
.fill.lo{background:var(--brand)}.fill.mid{background:#e0a500}.fill.hi{background:var(--bad)}
.meter-sub{font-size:12px;color:var(--muted);margin-top:3px}

/* object explorer context menu */
.ctxmenu{position:absolute;z-index:100;background:#fff;border:1px solid var(--line);
  border-radius:8px;box-shadow:0 8px 28px rgba(0,0,0,.16);min-width:150px;overflow:hidden;padding:4px 0}
.ctxmenu div{padding:8px 14px;font-size:13px;cursor:pointer}
.ctxmenu div:hover{background:#eef7f4}
.ctxmenu div.danger{color:var(--bad)}
.ctxmenu div.danger:hover{background:#fdecea}


/* The chips on the right of the bar: Cloud, and People for administrators.
   .chip is the look; .nav-cloud is only what is true of Cloud alone -- it is
   first, so it takes the free space, and it is the one carrying the dot. */
.chip{color:#fff;text-decoration:none;font-size:13px;font-weight:600;
  padding:6px 12px;border-radius:6px;background:rgba(255,255,255,.15)}
.chip:hover{background:rgba(255,255,255,.28)}
.chip.active{background:rgba(255,255,255,.32)}
.nav-cloud{margin-left:auto}

/* ---- responsive / mobile ---- */
.burger{display:none;background:transparent;border:none;color:#fff;font-size:24px;
  cursor:pointer;line-height:1;padding:2px 8px}

/* The bar in full wants 1351px. Rather than let it run off the right edge
   between there and the burger -- which it did, losing Logout at 1280px and
   most of the right-hand side by 1024px -- it tightens once, then gives up
   and hands over to the menu. */
@media(max-width:1400px){
  header{gap:8px;padding-left:16px;padding-right:16px}
  .nav{gap:5px;margin-left:8px}
  .nav a{padding:6px 8px}
  .chip{padding:6px 9px}
  .user{margin-left:8px;max-width:96px;overflow:hidden;text-overflow:ellipsis}
}
@media(max-width:1180px){
  header{flex-wrap:wrap;position:relative}
  .burger{display:block;margin-left:auto}
  .nav,.chip,.user,.logout{display:none}
  header.menu-open{padding-bottom:8px}
  /* opened, the menu has room again -- undo the tightening */
  header.menu-open .user{max-width:none;overflow:visible}
  header.menu-open .nav{display:flex;flex-direction:column;gap:2px;width:100%;margin:8px 0 0}
  header.menu-open .nav a{padding:11px 10px;border-radius:6px;font-size:15px}
  header.menu-open .chip{display:block;width:100%;margin:6px 0 0;text-align:left;padding:11px 12px}
  header.menu-open .user{display:block;width:100%;margin:8px 0 0;opacity:.8}
  header.menu-open .logout{display:block;width:100%;margin:6px 0 0;text-align:center;padding:11px}
}

/* Below here it is a phone, and the rules are about touch and small type. */
@media(max-width:820px){
  header{padding:12px 16px}
  /* wide tables scroll inside their card on phones */
  .card{overflow-x:auto}
  main{padding:0 10px}
  .grid{grid-template-columns:1fr}
  h1{font-size:16px}
  input,button,td input{font-size:16px}  /* prevents iOS zoom on focus */
  table{min-width:560px}
  .code-drop .sug-table{min-width:0}
  .totals{flex-wrap:wrap;gap:14px}
}
@media(max-width:820px){ .filters{flex-direction:column;align-items:stretch} .filters .field{min-width:0} }

/* radios + select */
.radios{display:flex;gap:16px;align-items:center;padding-top:6px}
.radios label{display:flex;align-items:center;gap:5px;font-size:14px;color:var(--ink);cursor:pointer}
.radios input{width:auto}
select{padding:8px 10px;border:1px solid var(--line);border-radius:7px;font:inherit;width:100%;background:#fff}
select:focus{outline:2px solid var(--brand2);border-color:var(--brand2)}

/* extension page */
.dlbtn{display:inline-block;background:var(--brand);color:#fff;text-decoration:none;
  padding:10px 18px;border-radius:8px;font-weight:600}
.dlbtn:hover{background:var(--brand2)}
.steps{line-height:1.9;padding-left:20px}
.steps code{background:#eef2f4;padding:1px 6px;border-radius:4px;font-size:13px}
h3{font-size:14px;margin:18px 0 6px}


/* invoice submitted status */
/* archive / restore on the invoices list */
button.archive,button.restore{font-size:12px;padding:3px 10px;border-radius:6px;
  border:1px solid var(--line);background:#fff;cursor:pointer}
button.archive{color:var(--bad)}
button.archive:hover{background:#fdecea;border-color:var(--bad)}
button.restore{color:var(--brand);font-weight:600}
button.restore:hover{background:#e6f4ef;border-color:var(--brand)}
button.archive:disabled,button.restore:disabled{opacity:.5;cursor:default}
/* the bin is a different place, not just a filter - tint it so that is obvious */
#list.binview tbody tr,#recent.binview tbody tr{background:#fcfcfa}
#list.binview tbody td,#recent.binview tbody td{color:var(--muted)}
#list.binview tbody td a b,#recent.binview tbody td a b{color:var(--ink)}

/* SIMS capture panel on the invoice detail view */
.simsbox{margin-top:18px;padding:14px 16px;border:1px solid var(--line);
  border-radius:10px;background:#fbfcfb}
.simsbox.empty{color:var(--muted);font-size:13px;background:none}
.simsbox h3{margin:0 0 4px}
.simsbox h3 .sub{margin:0;font-weight:400}
.simsgroup{font-size:11px;text-transform:uppercase;letter-spacing:.03em;
  color:var(--muted);font-weight:700;margin:14px 0 6px;
  padding-bottom:4px;border-bottom:1px solid var(--line)}
.simsgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));
  gap:8px 18px;margin:0}

/* The documents captured from SIMS, on the same invoice detail view. Shown
   rather than linked: this is the paper the bill is checked against, and
   having to open it in another tab first was the thing that made checking a
   bill slower than reading one. The cost is real -- a prescription is most of
   a megabyte, fetched whenever a bill is opened -- and is paid deliberately.
   The links stay for opening full size and for saving a copy. */
.docsbox{margin-top:14px;padding:12px 16px;border:1px solid var(--line);
  border-radius:10px;background:#fbfcfb}
.docsbox h3{margin:0 0 10px}
/* One card per document. The header is the document's caption and the page is
   the card's own content, so there is a single edge around both instead of a
   bordered frame sitting inside a bordered box -- which is what it was, and
   what made it read as an attachment rather than as part of the bill. */
.doc{border:1px solid var(--line);border-radius:10px;background:var(--card);
  overflow:hidden;margin-top:10px}
.doc:first-of-type{margin-top:0}
.dochead{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:8px 12px;border-bottom:1px solid var(--line);background:#fbfcfb}
/* The same eyebrow the SIMS capture uses for its groups, three inches up the
   same screen. Borrowed rather than invented: a second way of labelling a
   section is a second thing to learn. */
.docgroup{font-size:11px;text-transform:uppercase;letter-spacing:.03em;
  color:var(--muted);font-weight:700}
.dochead .sub{flex:1 1 200px;font-size:12px;margin:0}
/* The shape the archive and restore buttons already use, so an action here
   looks like an action everywhere else on the page. */
.docbtn{font-size:12px;padding:3px 10px;border-radius:6px;font-weight:600;
  border:1px solid var(--line);background:#fff;color:var(--brand);
  text-decoration:none;white-space:nowrap}
.docbtn:hover{background:#e6f4ef;border-color:var(--brand)}
/* A print copy that is not ready, or that did not clean well. Present so the
   operator knows the option exists and why it is not being offered, rather
   than a button that quietly is not there. */
.docbtn.off{color:var(--muted);border-style:dashed;cursor:default}
/* Not a button: it says what was done to the document, beside the buttons that
   act on it. The original is always one of those buttons. */
.docnote{font-size:11.5px;color:var(--muted);align-self:center}
.docnote.bad{color:#7a5a10}
.docbtn.plain{border-style:dashed}
.docbtn.off:hover{background:none;border-color:var(--line)}
/* The document itself. Tall enough to read a prescription without scrolling
   the page, and it scrolls inside itself for the rest -- the receipt is laid
   out for an 8.3in page and will be wider than this on a counter screen. */
/* No border and no radius of its own: the card carries both. The mount is the
   page's own background rather than the charcoal Chrome puts behind a PDF, so
   a prescription sits on the app instead of in a viewer. */
/* One scrollbar for a document, not two.
   The frame was a fixed 540px sitting inside a pane that scrolls, so anything
   taller scrolled inside something that also scrolled -- two bars side by
   side, and the outer one moving the wrong thing under the finger.
   An RGHS receipt is HTML and same-origin, so once it has loaded its height
   can be read and the frame grown to exactly it: the document then takes the
   room it needs and only the box scrolls. That is `height` set inline, below.
   A prescription is a PDF and cannot be measured -- Chrome's viewer lays it
   out and scrolls it itself, and nothing outside it can ask how tall it is.
   Those get `ownscroll`: a frame the height of the box, so there is still only
   one bar on the pane, the viewer's own. */
.docview{display:block;width:100%;height:540px;border:0;background:var(--bg);
  overscroll-behavior:contain}
.docview.ownscroll{height:min(78vh,900px)}
@media(max-width:560px){ .docview{height:380px} .docview.ownscroll{height:70vh} }
.simscell dt{font-size:11px;color:var(--muted);margin:0}
.simscell dd{margin:1px 0 0;font-size:13.5px;color:var(--ink);
  word-break:break-word;line-height:1.35}
@media(max-width:560px){ .simsgrid{grid-template-columns:1fr} }

.badge{display:inline-block;font-size:11px;padding:2px 8px;border-radius:20px;font-weight:600}
.badge.submitted{background:#e6f4ef;color:#0b6b5a}
.badge.draft{background:#f0f2f4;color:#6b7785}
tr.done{background:#fafcfb}


/* editable stock rows */
tr.editing{background:#fff8e6}
tr.editing input{padding:4px 6px;font-size:13px}
.edit{padding:2px 10px;font-size:12px;background:#fff;border:1px solid var(--line);border-radius:5px;cursor:pointer}
.edit:hover{border-color:var(--brand);color:var(--brand)}
.save{padding:3px 11px;font-size:12px;background:var(--brand);color:#fff;border:none;border-radius:5px;cursor:pointer}
.cancel{padding:3px 8px;font-size:12px;background:#fff;border:1px solid var(--line);border-radius:5px;cursor:pointer}

input[readonly]{background:#f4f6f8;color:#6b7785}

/* stock: next-code hint + sortable headers */
.nexthint{color:var(--brand);font-weight:600}
#list thead th[data-col]{cursor:pointer;user-select:none}
#list thead th[data-col]:hover{color:var(--brand)}
#list thead th.sort-asc::after{content:" ▲";font-size:10px}
#list thead th.sort-desc::after{content:" ▼";font-size:10px}

/* purchases list: edit/delete + sortable headers */
#recent thead th[data-col],#files thead th[data-col]{cursor:pointer;user-select:none}
#recent thead th[data-col]:hover,#files thead th[data-col]:hover{color:var(--brand)}
#recent thead th.sort-asc::after,#files thead th.sort-asc::after{content:" ▲";font-size:10px}
#recent thead th.sort-desc::after,#files thead th.sort-desc::after{content:" ▼";font-size:10px}
.p-edit{padding:2px 10px;font-size:12px;background:#fff;border:1px solid var(--line);border-radius:5px;cursor:pointer}
.p-edit:hover{border-color:var(--brand);color:var(--brand)}
.p-save{padding:3px 11px;font-size:12px;background:var(--brand);color:#fff;border:none;border-radius:5px;cursor:pointer}
.p-cancel{padding:3px 8px;font-size:12px;background:#fff;border:1px solid var(--line);border-radius:5px;cursor:pointer}
.rowhint{font-size:11px;color:var(--brand);font-weight:600;margin-top:2px}

/* history: per-row change detail */
.expand{padding:2px 10px;font-size:12px;background:#fff;border:1px solid var(--line);
  border-radius:5px;cursor:pointer;color:var(--brand);font-weight:600;white-space:nowrap}
.expand:hover{border-color:var(--brand);background:#eef7f4}
tr.detail{background:#fafcfb;font-size:12px}
tr.detail td{padding:4px 8px;border-bottom:1px dotted var(--line);color:#3a4652}
tr.detail .tag{font-size:10px}
tr.detail.skipped td{color:var(--bad)}
.mono{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;color:var(--muted)}
.who-sys{font-size:12px;color:var(--muted);background:#eef2f4;padding:2px 7px;border-radius:5px;font-weight:600}

/* history: recorded before/after vs the value now */
.statetbl{width:auto;margin:5px 0 2px;font-size:11px;border-collapse:collapse}
.statetbl th{text-transform:none;letter-spacing:0;font-size:11px;color:var(--muted);
  font-weight:600;text-align:left;padding:1px 10px 1px 0;border:none}
.statetbl td{padding:1px 8px 1px 0;border:none}
.statetbl .was{color:var(--muted)}
.statetbl .arrow{color:var(--muted);padding:0 2px}
.statetbl .became{font-weight:600;color:var(--ink)}
.statetbl .now{color:var(--muted)}
.statetbl .now.moved{color:var(--bad);font-weight:600}
.statenote{font-size:11px;color:var(--bad);margin-top:4px}

/* inline hint under a field (e.g. TID -> SIMS capture) */
.hint{font-size:12px;color:var(--muted);margin-top:3px;min-height:15px}
.hint.ok{color:var(--brand);font-weight:600}

/* note callout box */
.note-box{display:flex;align-items:flex-start;gap:9px;background:#eef7f4;border:1px solid #cce5de;
  border-left:3px solid var(--brand);border-radius:6px;padding:9px 12px;margin:0 0 14px;
  font-size:12.5px;line-height:1.45;color:#174239}
.note-ico{flex:0 0 auto;margin-top:2px;color:var(--brand)}

/* compulsory fields & validation */
.req{color:var(--bad);font-weight:700;font-size:12px;margin-left:2px;vertical-align:baseline}
input.invalid, select.invalid{border-color:#d9534f;background:#fffafa;box-shadow:0 0 0 1px #d9534f inset}
input.invalid:focus, select.invalid:focus{outline:2px solid rgba(217,83,79,.35);border-color:#d9534f}

/* receipt capture sheet (built for a phone first) */
.rc-back{position:fixed;inset:0;z-index:200;background:rgba(20,28,36,.55);
  display:flex;align-items:flex-end;justify-content:center}
.rc-sheet{position:relative;background:#fff;width:100%;max-width:640px;max-height:92vh;min-height:70vh;
  border-radius:14px 14px 0 0;display:flex;flex-direction:column;
  box-shadow:0 -8px 34px rgba(0,0,0,.28)}
@media(min-width:641px){ .rc-back{align-items:center} .rc-sheet{border-radius:14px} }
.rc-head{display:flex;align-items:center;gap:10px;padding:14px 16px;
  border-bottom:1px solid var(--line)}
.rc-head b{flex:1;font-size:15px}
.rc-count{font-size:12px;color:var(--muted)}
.rc-x{padding:4px 10px;border:none;background:none;font-size:18px;color:var(--muted);cursor:pointer}
.rc-pages{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-wrap:wrap;gap:12px;
  align-content:flex-start;min-height:140px}
.rc-empty{width:100%;margin:0}
.rc-thumb{position:relative;width:104px}
.rc-thumb img{width:104px;height:138px;object-fit:cover;border-radius:8px;
  border:1px solid var(--line);display:block;background:#f4f6f8}
.rc-no{position:absolute;left:5px;top:5px;background:rgba(20,28,36,.72);color:#fff;
  font-size:11px;font-weight:700;padding:1px 7px;border-radius:10px}
.rc-del{position:absolute;right:4px;top:4px;width:24px;height:24px;padding:0;
  border-radius:50%;border:none;background:rgba(20,28,36,.72);color:#fff;
  font-size:13px;line-height:24px;cursor:pointer}
.rc-msg{padding:0 16px;font-size:13px;color:var(--muted);min-height:18px}
.rc-foot{display:flex;gap:10px;padding:14px 16px;border-top:1px solid var(--line)}
.rc-foot button{flex:1;padding:13px 16px;font-size:15px}   /* thumb-sized targets */
.rc-save{font-weight:600}
.rc-save:disabled{opacity:.45;cursor:default}

/* receipt column on the purchases list */
.rcell{white-space:nowrap}
.pgbadge{display:inline-block;font-size:11px;padding:2px 7px;border-radius:10px;
  background:#e6f4ef;color:var(--brand);font-weight:600}
.pgbadge.wait{background:#fdf3e0;color:#8a6d3b}
.ocrstat{margin:0 0 0 4px;align-self:center;white-space:nowrap}

/* rotate / crop editor inside the capture sheet */
.rc-thumb{padding-bottom:26px}
.rc-edit{position:absolute;left:0;right:0;bottom:0;padding:4px 0;font-size:11px;
  border:1px solid var(--line);border-radius:0 0 8px 8px;background:#f4f6f8;
  color:var(--muted);cursor:pointer;width:104px}
.rc-edit:hover{background:#eef7f4;color:var(--brand)}
.rc-editor{position:absolute;inset:0;background:#fff;z-index:5;display:flex;
  flex-direction:column;border-radius:14px}
.rc-edhead{display:flex;gap:10px;align-items:baseline;padding:14px 16px;
  border-bottom:1px solid var(--line)}
.rc-edhead .sub{margin:0}
.rc-stage{position:relative;flex:1;display:flex;align-items:center;justify-content:center;
  background:#1c2530;overflow:hidden;padding:10px}
.rc-canvas{max-width:100%;display:block;touch-action:none}
.rc-crop{position:absolute;border:2px solid #fff;box-shadow:0 0 0 9999px rgba(20,28,36,.5);
  touch-action:none;cursor:move}
.rc-crop i{position:absolute;width:26px;height:26px;background:#fff;border-radius:50%;
  border:2px solid var(--brand);touch-action:none}
.rc-crop i[data-h=nw]{left:-13px;top:-13px;cursor:nwse-resize}
.rc-crop i[data-h=ne]{right:-13px;top:-13px;cursor:nesw-resize}
.rc-crop i[data-h=sw]{left:-13px;bottom:-13px;cursor:nesw-resize}
.rc-crop i[data-h=se]{right:-13px;bottom:-13px;cursor:nwse-resize}
.rc-edfoot{display:flex;gap:8px;padding:12px 16px;border-top:1px solid var(--line)}
.rc-edfoot button{flex:1;padding:12px 8px;font-size:15px}
.rc-rot{font-size:20px;line-height:1}

/* "what did OCR read" viewer */
.rc-view{flex:1;overflow-y:auto;padding:14px 16px}
.rcv-page{border:1px solid var(--line);border-radius:10px;margin-bottom:14px;overflow:hidden}
.rcv-head{display:flex;align-items:center;gap:10px;padding:9px 12px;background:#fafbfc;
  border-bottom:1px solid var(--line);flex-wrap:wrap}
.rcv-head .sub{margin:0}
.ocrchip{font-size:11px;font-weight:700;padding:2px 9px;border-radius:10px}
.ocrchip.ok{background:#e6f4ef;color:var(--brand)}
.ocrchip.wait{background:#fdf3e0;color:#8a6d3b}
.ocrchip.bad{background:#fdecea;color:var(--bad)}
.rcv-body{display:flex;gap:14px;padding:12px;flex-wrap:wrap}
.rcv-img{width:190px;border:1px solid var(--line);border-radius:8px;display:block}
.rcv-side{flex:1;min-width:220px}
.rcv-fields h4{margin:0 0 6px;font-size:11px;text-transform:uppercase;
  letter-spacing:.03em;color:var(--muted)}
.rcv-fields h4 .sub{text-transform:none;letter-spacing:0;font-weight:400;margin-left:5px}
.rcv-fields dl{margin:0 0 10px;display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:7px 16px}
.rcv-fields dt{font-size:11px;color:var(--muted)}
.rcv-fields dd{margin:1px 0 0}
.rcv-fields code{font-size:12.5px;background:#eef2f4;padding:1px 6px;border-radius:4px;
  word-break:break-all}
.rc-toggle{font-size:12px;padding:4px 12px}
.rcv-side pre{margin:9px 0 0;padding:10px;background:#f4f6f8;border-radius:8px;
  font-size:12px;line-height:1.45;max-height:280px;overflow:auto;white-space:pre-wrap;
  word-break:break-word}
@media(max-width:560px){ .rcv-img{width:100%} }
.rcv-del{margin-left:auto;font-size:12px;padding:4px 11px;color:var(--bad);
  border:1px solid var(--line);border-radius:6px;background:#fff;cursor:pointer}
.rcv-del:hover:not(:disabled){background:#fdecea;border-color:var(--bad)}
.rcv-del:disabled{opacity:.55;cursor:default}

/* three-button row menu */
.rc-menu{position:absolute;z-index:210;background:#fff;border:1px solid var(--line);
  border-radius:9px;box-shadow:0 10px 30px rgba(0,0,0,.18);padding:5px 0;min-width:190px}
.rc-mi{padding:10px 16px;font-size:14px;cursor:pointer;white-space:nowrap}
.rc-mi:hover{background:#eef7f4}
.rc-mi.off{opacity:.35;cursor:default}
.rc-mi.off:hover{background:none}
button.p-scan,button.p-view,button.p-del2{padding:4px 12px;font-size:12.5px}
button.p-scan{color:var(--brand);font-weight:600}
button.p-del2{color:var(--bad)}
button.p-view:disabled,button.p-del2:disabled{opacity:.35;cursor:default;color:var(--muted)}

/* delete picker */
.rc-picklist{display:flex;flex-direction:column;gap:8px;margin-top:10px}
.rc-pick1{display:flex;align-items:center;gap:12px;padding:8px;border:1px solid var(--line);
  border-radius:9px;cursor:pointer}
.rc-pick1:hover{background:#fafbfc}
.rc-pick1 input{width:20px;height:20px;flex:0 0 auto}
.rc-pick1 img{width:56px;height:74px;object-fit:cover;border-radius:6px;
  border:1px solid var(--line);background:#f4f6f8}
.rc-pick1 small{font-size:11px}
.rc-nuke{color:var(--bad);font-weight:600}
.rc-nuke:disabled,.rc-all:disabled{opacity:.4;cursor:default}
.ocrchip.run{background:#e7f0fb;color:#1c5fa8}
.ocrstat.busy{color:#8a6d3b;font-weight:600}

/* cloud map: what exists, and what is moving between it */
.graphwrap{overflow-x:auto;margin:6px 0 10px}
.cloudmap{width:100%;min-width:720px;height:auto;display:block}
.cloudmap .nbox{fill:#fff;stroke-width:1.5}
.cloudmap .nlabel{font:600 14px system-ui;fill:var(--ink)}
.cloudmap .nsub{font:11.5px system-ui;fill:var(--muted)}
.cloudmap .nmeta{font:11px system-ui;fill:var(--muted)}
.cloudmap .dot{stroke:#fff;stroke-width:1.5}
.cloudmap .dot.on{fill:#0b6b5a}
.cloudmap .dot.warn{fill:#e0a500}
.cloudmap .dot.off{fill:#c3ccd4}
.cloudmap .wire{fill:none;stroke:#dbe2e8;stroke-width:2}
.cloudmap .edge.live .wire{stroke:#bfe0d6}
/* the moving dash is the whole point: a still line means a still link */
.cloudmap .pulse{fill:none;stroke:var(--brand);stroke-width:2.5;
  stroke-dasharray:7 15;stroke-linecap:round;animation:flow 1.1s linear infinite}
@keyframes flow{to{stroke-dashoffset:-44}}
.cloudmap .elabel{font:10.5px system-ui;fill:var(--muted);text-anchor:middle}
.cloudmap .elabel.live{fill:var(--brand);font-weight:600}
.legend{display:flex;flex-wrap:wrap;gap:16px;font-size:12px;color:var(--muted)}
.legend i{display:inline-block;vertical-align:middle;margin-right:5px}
.legend i.dot{width:9px;height:9px;border-radius:50%}
.legend i.dot.on{background:#0b6b5a}.legend i.dot.warn{background:#e0a500}
.legend i.dot.off{background:#c3ccd4}
.legend i.wirekey{width:22px;height:2px;background:#dbe2e8}
.legend i.wirekey.live{background:var(--brand)}
@media(prefers-reduced-motion:reduce){.cloudmap .pulse{animation:none}}

/* a PDF queued for splitting, sitting alongside the photographed pages */
.rc-pdf{display:flex;align-items:center;gap:9px;width:100%;padding:9px 11px;
  border:1px solid var(--line);border-radius:8px;background:#fafbfc}
.rc-pdficon{font-size:11px;font-weight:700;letter-spacing:.4px;padding:3px 8px;
  border-radius:5px;background:#fdecea;color:var(--bad)}
.rc-pdfname{font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;max-width:46%}
.rc-pdf .sub{margin:0}
.rc-delpdf{margin-left:auto;width:24px;height:24px;padding:0;border-radius:50%;
  border:none;background:rgba(20,28,36,.72);color:#fff;font-size:13px;
  line-height:24px;cursor:pointer}

/* a PDF has no thumbnail, so its tile stands in for one */
.rcv-pdf{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:2px;width:120px;height:150px;border:1px solid var(--line);border-radius:8px;
  background:#fafbfc;font-weight:700;color:var(--bad);font-size:15px}
.rcv-pdf small{font-weight:600;color:var(--muted);font-size:11px}

/* download the file exactly as it was uploaded.
   The meta line does the pushing so the buttons stay grouped at the right. */
.rcv-head .sub{margin:0 auto 0 0}
.rcv-head .rcv-del{margin-left:0}
.rcv-dl{font-size:12px;font-weight:600;text-decoration:none;
  padding:3px 9px;border-radius:10px;background:#e6f4ef;color:var(--brand);
  white-space:nowrap}
.rcv-dl:hover{background:#d7ece4}
.rcv-dl.alt{background:#eef1f5;color:var(--muted)}
.rcv-dl.alt:hover{background:#e2e7ee;color:var(--ink)}
.ctxmenu div.hidden{display:none}

/* the table OCR found on a page, shown beside the transcript */
.rcv-tablewrap{margin:10px 0 4px}
.rcv-tablewrap h4{margin:0 0 6px;font-size:13px}
.rcv-tables{max-height:340px;overflow:auto;border:1px solid var(--line);border-radius:8px}
.rcv-table{border-collapse:collapse;font-size:11px;width:max-content;min-width:100%}
.rcv-table td{border:1px solid var(--line);padding:3px 6px;vertical-align:top;
  white-space:nowrap;max-width:220px;overflow:hidden;text-overflow:ellipsis}
.rcv-table tr:first-child td{background:#fafbfc;font-weight:600;position:sticky;top:0}
.rcv-table tr:nth-child(even) td{background:#fcfdfe}

/* pagination bar under a list table */
.pager{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  padding:9px 2px 2px;font-size:12px;color:var(--muted)}
.pager.hidden{display:none}
.pg-nav{display:inline-flex;align-items:center;gap:4px}
.pager button{min-width:28px;padding:3px 8px;font-size:12px;line-height:18px}
.pager button:disabled{opacity:.4;cursor:default}
.pg-where{padding:0 6px;font-variant-numeric:tabular-nums;white-space:nowrap}
.pg-count{font-variant-numeric:tabular-nums}
.pg-size{margin-left:auto;display:inline-flex;align-items:center;gap:6px}
.pg-size select{padding:3px 6px;font-size:12px}

/* sortable headings and the per-column filter row (TableKit) */
thead th.sortable{cursor:pointer;user-select:none}
thead th.sortable:hover{color:var(--brand)}
thead th.sort-asc::after{content:" ▲";font-size:10px}
thead th.sort-desc::after{content:" ▼";font-size:10px}
tr.colfilters th{padding:3px 4px 5px;background:#fafbfc;border-bottom:1px solid var(--line)}
tr.colfilters input,tr.colfilters select.colpick{width:100%;min-width:44px;
  box-sizing:border-box;padding:3px 6px;
  font-size:11px;font-weight:400;border:1px solid var(--line);border-radius:5px;
  background:#fff}
tr.colfilters input:focus,tr.colfilters select.colpick:focus{outline:none;
  border-color:var(--brand)}
/* A column picked from rather than typed into. It keeps the row's height and
   the box's look; only the arrow says it is a list, and the longest status
   RGHS uses is wider than the column, so the box clips rather than stretches
   the table. */
tr.colfilters select.colpick{height:24px;cursor:pointer;
  text-overflow:ellipsis;font-family:inherit;color:var(--ink)}

/* per-line link back to the purchase receipt, on the invoice detail */
td.rcpts{white-space:nowrap}
td.rcpts .pinv{display:inline-block;margin-right:6px;font-size:11px;font-weight:600;
  color:var(--muted)}
td.rcpts a{display:inline-block;margin-right:4px;padding:1px 7px;border-radius:9px;
  font-size:11px;font-weight:600;text-decoration:none;background:#e6f4ef;color:var(--brand)}
td.rcpts a:hover{background:#d7ece4}
td.rcpts a.alt{background:#eef1f5;color:var(--muted)}
td.rcpts a.alt:hover{background:#e2e7ee;color:var(--ink)}
td.rcpts .pinv.approx{color:#8a6d3b;border-bottom:1px dotted #c9a227;cursor:help}

/* folder view on the Files page */
.crumb{font-size:13px;margin:0 0 8px;color:var(--muted)}
.crumb a{color:var(--brand);text-decoration:none}
.crumb a:hover{text-decoration:underline}
.crumb .sep{margin:0 6px;opacity:.6}
/* Everything in this table opens on a single click -- a folder opens itself,
   a file opens its menu -- so every row says so. */
#files tbody tr{cursor:pointer}
#files tbody tr:hover td{background:#f7faf9}
tr.folder:hover td{background:#f2f7f5}
tr.folder td:first-child{font-weight:600}
tr.folder .fico{margin-right:8px}
tr.folder .sub{margin-left:8px;font-weight:400}

/* ---- table rules, darkened -------------------------------------------------
   The grid was #e2e7ec, which is nearly invisible against a white card and
   makes a thirteen-column stock table hard to read across. Rows now get a
   clearly darker rule, the last header row a heavier one so the headings read
   as a block, and columns a lighter vertical so a wide table can be scanned
   sideways without the whole thing looking like a cage. */
:root{--grid:#c2ccd7; --grid-strong:#8f9dab; --grid-soft:#dbe2e9}

table{border:1px solid var(--grid)}
th,td{border-bottom:1px solid var(--grid)}
/* whichever header row is last carries the heavy rule, so a table with a
   filter row under its headings gets one separator rather than two */
thead tr:last-child th{border-bottom:2px solid var(--grid-strong)}
thead th{background:#f6f8fa}
tbody td + td, thead th + th{border-left:1px solid var(--grid-soft)}
tbody tr:last-child td{border-bottom:none}

/* the filter row sits inside the header block, so it keeps the header tint
   and hands the heavy rule to itself as the last row */
tr.colfilters th{background:#f6f8fa;border-bottom:2px solid var(--grid-strong)}

/* small inline tables are not grids and should not be boxed, and the OCR
   table already sits inside a bordered scroll box -- a second frame on the
   table itself would double the line */
.statetbl,.code-drop .sug-table,.rcv-table{border:none}
.statetbl td,.statetbl th{border-left:none}
.badge.rejected{background:#fdecea;color:var(--bad)}

/* a rejected invoice says so across the whole panel, not just in a badge */
/* An invoice row opens the bill, so it says so before it is clicked. */
tr.row{cursor:pointer}
/* And a purchase row opens its items. Only the cells that are not full of
   buttons: the actions column has its own targets and should not look like a
   way into something else. */
#recent tbody tr[data-id] td:not(.rcell):not(:last-child){cursor:pointer}

/* ---- the purchase items dialog -----------------------------------------
   Same bargain as the invoice one. These are editable fields, so scrolling
   away from the row to reach them and back to see what changed was the worst
   of the three pages. */
#purBox{border:none;border-radius:12px;padding:14px 20px 16px;
  max-width:min(1100px,96vw);width:1100px;max-height:92vh;
  box-shadow:0 18px 48px rgba(20,32,27,.22);color:var(--ink)}
/* Only while it is open. A <dialog> is display:none until then, and a
   plain display rule overrides that -- which left the box on the page
   after it had been closed, still showing its contents. */
#purBox[open]{display:flex;flex-direction:column}
#purBox::backdrop{background:rgba(20,32,27,.42)}
#purBox #pItems{overflow-y:auto;overflow-x:auto;flex:1;min-height:0;
  overscroll-behavior:contain}
#purBox .dlghead{position:sticky;top:0;background:var(--card,#fff);z-index:2;
  padding-bottom:8px;border-bottom:1px solid var(--line);margin-bottom:8px}
/* The bar under the box: one Save for both halves of the receipt, the way out
   beside it, and what happened to the left of them. Outside the scrolling
   part, so a receipt with forty lines cannot push the Save off the bottom and
   the two controls are in the same place on every receipt. */
#purBox .dlgfoot{display:flex;align-items:center;gap:10px;flex:none;
  padding-top:10px;margin-top:8px;border-top:1px solid var(--line)}
/* The message takes the free space, so the two buttons stay at the end where a
   hand reaches for them however long the sentence is. It wraps rather than
   pushing them off: it carries the reason a save failed, which is a sentence
   and not a word. */
#purBox .dlgfoot #pSaveMsg{flex:1;margin:0;min-width:0}
#purBox .dlgfoot #pSaveMsg.ok{color:var(--brand);font-weight:600}
#purBox .dlgfoot #pSaveMsg.bad{color:var(--bad,#b0413e);font-weight:600}
/* Which half of the box you are looking at. Small and quiet -- the box already
   says which receipt it is, in its own bar. */
#purBox .dlgsec{font-size:12px;text-transform:uppercase;letter-spacing:.04em;
  color:var(--muted);margin:14px 0 6px;font-weight:700}
#purBox .dlgsec:first-child{margin-top:2px}
#purBox .dlgsec .sub{text-transform:none;letter-spacing:0;font-weight:400;margin:0}
/* The receipt's own five fields. The same grid the New purchase form uses, so
   correcting a receipt looks like writing one. */
#purBox .pdetails{margin-bottom:4px}
/* The lines that came in on it. Dense, because it is a ledger and the whole
   point is seeing every line at once. */
#purBox .itemedit{width:100%;border-collapse:collapse}
#purBox .itemedit th{font-size:11px;text-transform:uppercase;letter-spacing:.03em;
  color:var(--muted);padding:5px 6px;border-bottom:1px solid var(--line);text-align:left}
#purBox .itemedit td{padding:4px 6px;border-bottom:1px solid var(--line)}
#purBox .itemedit td.num,#purBox .itemedit th.num{text-align:right}
#purBox .itemedit input{padding:5px 7px;font-size:13px}
#purBox .itemedit input.num{text-align:right;font-variant-numeric:tabular-nums}
/* A field the operator has typed in and not saved yet. The box holds two
   separate writes behind one button, so which fields are waiting on it is
   worth being able to see rather than remember. */
#purBox #pItems input:not([data-was=""]):focus{outline:2px solid var(--brand);
  outline-offset:-2px}

#detail{position:relative}

/* ---- the invoice dialog -------------------------------------------------
   The bill used to load at the foot of the page, which meant scrolling away
   from the row just clicked and losing your place in a list of thousands.
   It opens over the list instead. Wider than the medicine one because the
   line table carries eleven columns, and it scrolls inside itself so a bill
   with a prescription in it never pushes the close button off the screen. */
#invBox,#pairBox{border:none;border-radius:12px;padding:14px 20px 16px;
  max-width:min(1180px,96vw);width:1180px;max-height:92vh;
  box-shadow:0 18px 48px rgba(20,32,27,.22);color:var(--ink)}
/* Only while it is open. A <dialog> is display:none until then, and a
   plain display rule overrides that -- which left the box on the page
   after it had been closed, still showing its contents. */
#invBox[open],#pairBox[open]{display:flex;flex-direction:column}
#invBox::backdrop,#pairBox::backdrop{background:rgba(20,32,27,.42)}
#invBox #detail,#pairBox #detail{overflow-y:auto;overflow-x:auto;flex:1;min-height:0;
  overscroll-behavior:contain}

/* The four tabs, on the heading row itself: the bill's number and patient on
   the left, the tabs pushed to the right of them, the way out last. One line
   rather than two, and the whole bar is sticky, so wherever you have scrolled
   the tabs and the cross are in the same place. */
.dlgtabs{display:flex;gap:2px;flex-wrap:wrap;margin-left:auto}
.dlgtabs [role=tab]{background:none;border:1px solid transparent;
  border-radius:7px;padding:5px 11px;font-size:12.5px;font-weight:600;
  color:var(--muted);cursor:pointer;white-space:nowrap}
.dlgtabs [role=tab]:hover{background:var(--line);color:var(--ink)}
.dlgtabs [role=tab][aria-selected=true]{color:#fff;background:var(--brand);
  border-color:var(--brand)}
.dlgtabs [role=tab]:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
/* A tab with nothing behind it: dimmed, still reachable, because "there is no
   prescription on this bill" is an answer somebody may be looking for. */
.dlgtabs [role=tab].empty{opacity:.45}
.dlgtabs [role=tab].empty[aria-selected=true]{opacity:1}
/* The cross keeps its place at the end; the tabs take the free space instead. */
.dlghead .dlgtabs + .dlgx{margin-left:8px}
/* Until the bar wraps. On a phone the tabs take the whole first line and the
   cross drops to a second one, where an 8px margin leaves it stranded at the
   left-hand edge under them. Pushed back to the end, which is where it is on
   every other width and where a hand reaches for it. */
@media(max-width:560px){ .dlghead .dlgtabs + .dlgx{margin-left:auto} }

/* One pane at a time. They are all built when the bill opens, so switching
   costs nothing and no request is made twice. */
/* What RGHS says about the card, above the shop's own record of it. Same
   shape as the panel below so the two read as a pair, and a shortfall is
   coloured because a claim paid less than it was billed for is the one row
   somebody is looking for. */
.accttable{width:100%;border-collapse:collapse;margin-top:6px}
.accttable th,.accttable td{padding:5px 8px;border-bottom:1px solid var(--line);
  font-size:12.5px;text-align:left;white-space:nowrap}
.accttable th{color:var(--muted);font-weight:600;font-size:11px;
  text-transform:uppercase;letter-spacing:.04em}
.accttable td.num,.accttable th.num{text-align:right;
  font-variant-numeric:tabular-nums}
.accttable td.short{color:var(--bad,#b0413e);font-weight:600}
.accttable tfoot td{font-weight:700;border-top:2px solid var(--line);
  border-bottom:none}
/* The operator's note, in the account tab's claim table. Everything else in
   that table is a short value kept on one line; a sentence held the same way
   would stretch the panel past the dialog, so this one cell wraps and is
   capped -- and is wide enough to look like somewhere you can type even when
   it is empty. */
.accttable td.notes{white-space:normal;max-width:220px;min-width:110px}

/* A bill on the account list opens that bill. The one already open is not a
   link to itself, so it does not offer to be clicked. */
.accthist tr.opens{cursor:pointer}
.accthist tr.opens:hover{background:var(--hover,#f3f6f4)}

#detail .pane{display:none}
#detail .pane.on{display:block}
.pad{padding:14px 2px}
/* The heading bar stays put while the bill scrolls under it, so the cross is
   always where it was. */
#invBox .dlghead,#pairBox .dlghead{position:sticky;top:0;background:var(--card,#fff);z-index:2;
  padding-bottom:8px;border-bottom:1px solid var(--line);margin-bottom:8px}
#invBox.rejected{background:linear-gradient(0deg,#fff9f8,#fff9f8),var(--card)}
#invBox.rejected .dlghead{background:#fff9f8}
.rejstamp{position:absolute;top:38%;left:50%;transform:translate(-50%,-50%) rotate(-18deg);
  font-size:clamp(48px,11vw,110px);font-weight:800;letter-spacing:.06em;
  color:rgba(192,57,43,.16);border:6px solid rgba(192,57,43,.16);border-radius:12px;
  padding:4px 26px;pointer-events:none;user-select:none;white-space:nowrap;z-index:1}
@media print{.rejstamp{color:rgba(192,57,43,.4);border-color:rgba(192,57,43,.4)}}

/* cells on the invoice line that the stock lookup fills but the operator may
   complete or correct -- a batch with no expiry recorded should not stop a bill */
td.edit-cell{cursor:text}
td.edit-cell:hover{background:#f7fafc}
td.edit-cell:focus{outline:2px solid var(--brand2);outline-offset:-2px;background:#fff}
td.edit-cell.needs{background:#fdf6e3;box-shadow:inset 0 -2px 0 #e0b34d}
td.edit-cell.needs:focus{box-shadow:none}
/* a quantity that goes past the recorded stock — cautioned in the same amber
   as a field that still needs typing, because neither is an error */
td input.qty.over{background:#fdf6e3;border-color:#e0b34d}
td input.qty.over:focus{outline-color:#e0b34d}
.stock-note{
  color:#8a6100; font-size:13px; font-weight:600;
  background:#fbf3e0; border:1px solid #e0b34d; border-radius:8px;
  padding:9px 14px; margin-top:10px;
}
.stock-note:empty{display:none}


/* account pages */
h3.sec{
  font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);
  margin:22px 0 2px;padding-top:14px;border-top:1px solid var(--line);font-weight:600;
}
label.chk{display:flex;align-items:center;gap:7px;font-size:13.5px;color:var(--muted);cursor:pointer}
label.chk input{width:auto}
td.rowacts{white-space:nowrap}
td.rowacts button{padding:3px 10px;font-size:12.5px;margin-right:4px}
td.rowacts button:disabled{opacity:.4;cursor:not-allowed}
/* Edit is a link -- it opens the bill in the form above by address, so it can
   be middle-clicked and bookmarked -- and has to sit level with the button
   beside it rather than looking like prose in a row of controls. */
td.rowacts a{display:inline-block;padding:3px 10px;font-size:12.5px;margin-right:4px;
  border:1px solid var(--line);border-radius:7px;color:var(--ink);
  text-decoration:none;background:#fff}
td.rowacts a:hover{border-color:var(--brand);color:var(--brand)}
a.user{color:#fff;text-decoration:none}
a.user:hover{text-decoration:underline}

/* the help page */
.lede{font-size:16px;color:var(--muted);max-width:72ch;margin:2px 0 0;line-height:1.6}
ol.steps.numbered{line-height:1.6;display:grid;gap:13px;max-width:80ch}
ol.steps.numbered li{color:var(--muted)}
ol.steps.numbered li b{color:var(--ink)}
ol.steps.numbered li i{font-style:normal;color:var(--ink)}
ol.steps.numbered li::marker{color:var(--brand);font-weight:700}
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(238px,1fr));gap:10px;margin-top:6px}
a.tile{
  display:block;text-decoration:none;border:1px solid var(--line);border-radius:8px;
  padding:12px 14px;background:#fff;transition:border-color .12s,background-color .12s;
}
a.tile:hover{border-color:var(--brand);background:#f3f8f6}
a.tile b{display:block;color:var(--ink);font-size:14.5px;margin-bottom:3px}
a.tile span{display:block;color:var(--muted);font-size:12.5px;line-height:1.45}
dl.facts{margin:6px 0 0;display:grid;gap:12px;max-width:82ch}
dl.facts dt{color:var(--ink);font-weight:600;font-size:14.5px}
dl.facts dd{margin:2px 0 0;color:var(--muted);font-size:14px;line-height:1.55}
ul.plain{margin:6px 0 12px;padding-left:20px;display:grid;gap:8px;max-width:80ch}
ul.plain li{color:var(--muted);line-height:1.55}
ul.plain li b{color:var(--ink)}
@media(prefers-reduced-motion:reduce){a.tile{transition:none}}

/* The two government pages. Marked out from the app's own links because they
   lead somewhere else entirely -- a different system, a separate sign-in, and
   the one place a bill actually gets filed. */
.govlinks{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:10px;margin:10px 0 18px}
a.gov{
  display:block;text-decoration:none;padding:12px 14px;border-radius:8px;
  border:1px solid var(--rule-gov,#cfe0d8);background:#f2f8f5;
  transition:border-color .12s,background-color .12s;
}
a.gov:hover{border-color:var(--brand);background:#e9f4ef}
a.gov b{display:block;color:var(--brand);font-size:14.5px;margin-bottom:3px}
a.gov span{display:block;color:var(--muted);font-size:12.5px;line-height:1.45;margin-bottom:6px}
a.gov code{
  font-family:var(--register);font-size:11.5px;color:var(--muted);
  background:transparent;padding:0;word-break:break-all;
}
@media(prefers-reduced-motion:reduce){a.gov{transition:none}}

/* Browsers draw placeholder text far lighter than any colour set here, which
   is what makes an empty field look empty rather than optional. */
input::placeholder, textarea::placeholder{color:#6b7785;opacity:1}
/* a column filter answered by the server rather than in the browser */
tr.colfilters input.server-filter{background:#f3f8ff;border-color:#b9cfe8}
tr.colfilters input.server-filter:focus{border-color:var(--brand)}


/* ============================================================== the Shop
   The second business. Everything below is its own screens: the shelves, the
   counter, the partner shop's phone page, and the dashboard's two charts.
   The bar's own colour lives up with the header rules; this is the inside of
   the pages. */

/* ---- shelves and stock ---- */
.warn{color:#8a6410}
td.held, .held{color:#8a4b2a;font-weight:600}     /* promised to the partner shop */
tr.off td{opacity:.55}
button.danger{color:var(--bad);font-weight:600}
button.danger:hover{border-color:var(--bad);background:#fdecea}

/* The code picker on a bill line. Sits under the cell it was opened from,
   which is why the cell is the positioning context. */
#lines td{position:relative}
.sugs:not(:empty){position:absolute;z-index:30;left:0;top:100%;min-width:340px;
  max-height:280px;overflow:auto;background:var(--card);border:1px solid var(--line);
  border-radius:8px;box-shadow:0 10px 26px rgba(20,32,27,.18)}
.sugs .opt b{margin-right:6px}
.sugs .opt .sub{display:block;margin-top:2px}
td.mname{font-size:13px}

/* ---- purchase pages ---- */
.pages{display:flex;flex-wrap:wrap;gap:12px;margin-top:10px}
.pages .page{margin:0;width:150px}
.pages .page img{width:100%;height:150px;object-fit:cover;border:1px solid var(--line);
  border-radius:8px;background:#fafcfb}
.pages figcaption{font-size:12px;color:var(--muted);margin-top:4px;
  display:flex;align-items:center;gap:6px}

/* ---- the partner shop's phone page ----
   Sticky, because on a phone the search box and the cart have to stay put
   while a long shelf list scrolls under them. */
.reqbar{position:sticky;top:0;z-index:25;display:flex;gap:8px;align-items:center;
  padding:10px 16px;background:var(--card);border-bottom:1px solid var(--line)}
.reqbar input{flex:1;min-width:0;padding:10px 12px;font-size:16px;
  border:1px solid var(--line);border-radius:8px}
.cartbtn{flex:none;background:var(--brand-shop);color:#fff;border:none;border-radius:8px;
  padding:10px 14px;font-size:14px;font-weight:600;cursor:pointer}
.cartbtn b{margin-left:5px;background:rgba(255,255,255,.25);border-radius:10px;
  padding:1px 7px}
.shelf{display:flex;flex-direction:column;gap:2px}
.srow{display:grid;grid-template-columns:1fr auto;gap:4px 10px;align-items:center;
  padding:9px 2px;border-bottom:1px solid var(--line)}
.srow.picked{background:#fbf6f1}
.sname{grid-column:1;min-width:0}
.sname b{display:block;font-size:14.5px}
.sname .sub{font-size:12px}
.sfacts{grid-column:1;display:flex;flex-wrap:wrap;gap:4px 12px;font-size:12px;
  color:var(--muted)}
.sfacts .left{color:var(--brand)}
.step{grid-row:1 / span 2;grid-column:2;display:flex;align-items:center;gap:4px}
.step button{width:38px;height:38px;font-size:19px;line-height:1;padding:0;
  border:1px solid var(--line);background:#fff;border-radius:8px;cursor:pointer}
.step .qty{width:52px;text-align:center;font-size:16px;padding:8px 4px}
@media(min-width:760px){
  .srow{grid-template-columns:minmax(220px,2fr) 3fr auto}
  .sfacts{grid-column:2;grid-row:1}
  .step{grid-row:1;grid-column:3}
}

/* ---- the demand board ---- */
.porder{display:flex;flex-wrap:wrap;align-items:center;gap:10px 16px;
  padding:11px 0;border-bottom:1px solid var(--line)}
.porder > div:first-child{flex:1 1 240px}
.porder .sub{display:block}
.place{margin-bottom:14px}
table.picklist{min-width:0}

/* ---- the printable receipt ----
   Hidden on screen. On paper it is two copies of the same bill side by side on
   one A4 sheet -- customer and shop -- to be cut down the middle. Bills here
   are rare, so the sheet is worth using properly rather than printing a
   three-line sale on a whole page twice. */
.receipt-sheet{display:none}
@media print{
  body > *{display:none !important}
  body > .receipt-sheet{display:flex !important;gap:0;align-items:flex-start}
  .receipt-sheet .rc{width:50%;padding:10mm 8mm;font-size:11px;
    border-right:1px dashed #999;box-sizing:border-box}
  .receipt-sheet .rc:last-child{border-right:none}
  .rc-head{text-align:center;margin-bottom:8px;line-height:1.35}
  .rc-head b{font-size:14px;display:block}
  .rc-meta{display:flex;justify-content:space-between;gap:8px;margin:3px 0;
    border-top:1px solid #ddd;padding-top:3px}
  .rc-copy{font-weight:700;text-transform:uppercase;letter-spacing:.06em;font-size:9px}
  table.rc-lines{width:100%;border-collapse:collapse;margin-top:8px}
  table.rc-lines th{text-align:left;border-bottom:1px solid #333;padding:3px 2px;font-size:10px}
  table.rc-lines td{padding:3px 2px;vertical-align:top;border-bottom:1px solid #eee}
  table.rc-lines .num, .rc-lines td.num{text-align:right}
  .rc-sub{color:#666;font-size:9px}
  .rc-total{display:flex;justify-content:space-between;border-top:2px solid #333;
    margin-top:6px;padding-top:5px;font-size:13px}
  .rc-foot{margin-top:10px;color:#666;font-size:9px;line-height:1.4}
  .picklist{width:100%;border-collapse:collapse}
  .picklist th, .picklist td{border-bottom:1px solid #ddd;padding:3px;font-size:10px}
  @page{size:A4;margin:0}
}

/* ---- the dashboard ----
   Four series, fixed to their meaning and never reassigned by rank: whoever
   learns that medicine is blue keeps that. They were checked for colour-blind
   separation with the palette validator rather than chosen by eye. Aqua and
   yellow fall under 3:1 against white, so the payment bar carries its numbers
   on its face -- the fill is never the whole message.
   One theme, because this app has one. */
.viz{
  --surface-1:#fff;
  --vgrid:#e7ece8;
  --s1:#2a78d6;   /* medicine */
  --s2:#eb6834;   /* consultations */
  --s3:#1baf7a;   /* cash */
  --s4:#eda100;   /* UPI */
}
.kpis{display:flex;flex-wrap:wrap;gap:10px 34px;align-items:flex-end}
.kpis.tight{gap:8px 22px}
.kpi{display:flex;flex-direction:column;gap:2px;min-width:130px}
.klabel{font-size:12px;color:var(--muted)}
.kvalue{font-size:24px;font-weight:600;line-height:1.1;
  font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.kpi.hero .kvalue{font-size:48px}
.ksub{font-size:12px;color:var(--muted)}
.vwrap{position:relative;margin:6px 0 2px}
.vwrap svg{display:block;width:100%;height:auto}
.vwrap.short svg{height:92px}
.vlegend{display:flex;flex-wrap:wrap;gap:6px 18px;font-size:12.5px;color:var(--muted);
  margin:2px 0 6px}
.vlegend span{display:inline-flex;align-items:center;gap:7px}
.vlegend i{width:11px;height:11px;border-radius:3px;display:inline-block}
.dashkey{width:16px;height:0;border-top:2px dashed var(--muted);border-radius:0}
/* Marks: thin, and the grid one step off the surface, solid, recessive. */
.vgrid{stroke:var(--vgrid);stroke-width:1}
.vaxis{stroke:#cfd8d2;stroke-width:1}
.vcross{stroke:#c4d0c9;stroke-width:1}
.vtick{font-size:11px;fill:var(--muted)}
.vlabel{font-size:12px;font-weight:600;fill:var(--ink)}
.viz .s1 path,.viz .s1 rect{fill:var(--s1)}
.viz .s2 path,.viz .s2 rect{fill:var(--s2)}
.viz .s3 path,.viz .s3 rect{fill:var(--s3)}
.viz .s4 path,.viz .s4 rect{fill:var(--s4)}
.vexp{fill:none;stroke:var(--muted);stroke-width:2;stroke-linecap:round;
  stroke-linejoin:round;stroke-dasharray:5 4}
.vexp-dot{fill:var(--muted);stroke:var(--surface-1);stroke-width:2}
.vhit{fill:transparent}
/* display:flex outranks the [hidden] default, the same trap the switcher menu
   fell into -- without this the tooltip sits empty over the chart from the
   moment the page loads. */
.vtip[hidden]{display:none}
.vtip{position:absolute;top:8px;z-index:20;pointer-events:none;min-width:190px;
  background:var(--card);border:1px solid var(--line);border-radius:9px;padding:8px 10px;
  box-shadow:0 10px 26px rgba(20,32,27,.18);font-size:12.5px;
  display:flex;flex-direction:column;gap:3px}
.vtip span{display:flex;align-items:center;gap:7px;justify-content:space-between}
.vtip span i{width:9px;height:9px;border-radius:2px;flex:none;margin-right:auto}
.vtip .dashkey{height:0;width:14px;margin-right:auto}
.vtip .tot{border-top:1px solid var(--line);padding-top:3px;margin-top:2px}


/* ---- the Shop's screens, given the same shape as its dashboard ----
   The dashboard reads well because it leads with a few figures, groups things
   into cards of different weights, and keeps the long stuff out of the way.
   The other screens were a flat form sitting on top of an unbounded table --
   the Sales page came to seven thousand pixels, nearly all of it history
   nobody had asked for. Everything below is scoped to main.shop: the RGHS
   side is in daily use and did not ask to be restyled. */

/* A page leads with its numbers, the way the dashboard does. */
main.shop .lead{display:flex;flex-wrap:wrap;gap:12px 34px;align-items:flex-end;
  padding:2px 0 2px}
main.shop .lead .kpi{min-width:120px}
main.shop .lead .kvalue{font-size:22px}
main.shop .lead .kpi.hero .kvalue{font-size:34px}

/* Cards get a heading that means something and room around it. */
main.shop .card{padding:18px 20px}
main.shop .card > h2{font-size:15.5px;letter-spacing:-.01em;margin:0 0 3px}
main.shop .card > h2 .sub{font-weight:400}
main.shop .card > p.sub{max-width:78ch;margin:-1px 0 14px}

/* The card a screen exists for. One per page, and it should look like it. */
main.shop .card.work{border-color:#cfe0d8;box-shadow:0 1px 0 rgba(20,32,27,.03),
  0 8px 22px -18px rgba(20,32,27,.5)}
main.shop .card.work > h2::before{content:"";display:inline-block;width:4px;height:14px;
  border-radius:2px;background:var(--brand-shop);margin-right:9px;vertical-align:-2px}

/* Forms that are not the point of the page fold away. Adding a medicine is a
   thing you do once a week; looking at the shelf is a thing you do all day. */
main.shop details.fold{border:1px solid var(--line);border-radius:10px;background:var(--card)}
main.shop details.fold > summary{cursor:pointer;padding:13px 18px;font-size:14.5px;
  font-weight:600;list-style:none;display:flex;align-items:center;gap:9px}
main.shop details.fold > summary::-webkit-details-marker{display:none}
main.shop details.fold > summary::before{content:"+";font-size:17px;line-height:1;
  color:var(--brand-shop);font-weight:700;width:14px}
main.shop details.fold[open] > summary::before{content:"\2212"}
main.shop details.fold > summary .sub{font-weight:400;margin:0}
main.shop details.fold .inner{padding:0 18px 16px}

/* Long lists: a heading that stays put, alternating rows, and money that reads
   as money. A hundred rows of identical grey is the thing that was hard to
   read. */
main.shop .list{max-height:min(56vh,520px);overflow:auto;border:1px solid var(--line);
  border-radius:9px}
main.shop .list table{margin:0}
main.shop .list thead th{position:sticky;top:0;z-index:2;background:#f3f6f4;
  box-shadow:inset 0 -1px 0 var(--line)}
main.shop table tbody tr:nth-child(even) > td{background:#fafcfb}
main.shop table tbody tr:hover > td{background:#f2f8f5}
main.shop td, main.shop th{padding:7px 10px}
main.shop td.money{text-align:right;font-variant-numeric:tabular-nums;font-weight:600}
main.shop .empty{padding:22px 12px;text-align:center;color:var(--muted);font-size:13.5px}

/* What a list is showing, and how to see more of it. */
main.shop .listfoot{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;
  margin-top:9px;font-size:12.5px;color:var(--muted)}
main.shop .when{display:flex;gap:4px}
main.shop .when button{padding:5px 11px;font-size:12.5px;border-radius:20px;
  border:1px solid var(--line);background:#fff;color:var(--muted);cursor:pointer}
main.shop .when button.on{background:var(--brand-shop);border-color:var(--brand-shop);
  color:#fff;font-weight:600}

/* A field should be as wide as what goes in it. Every box the same width is
   what made the forms read as a wall. */
main.shop .row{display:flex;flex-wrap:wrap;gap:12px 14px;align-items:flex-end}
main.shop .row .field{flex:1 1 180px;min-width:0}
main.shop .row .field.wide{flex:2 1 280px}
main.shop .row .field.tight{flex:0 0 110px}
main.shop .row .field.mid{flex:0 0 160px}
main.shop .row .field input, main.shop .row .field select{width:100%}

/* A filter is not a form field: it should be the width of what you type into
   it, not the width of the card. Left to grow, a lone Supplier box stretched
   across a thousand pixels and read as the most important thing on the page. */
main.shop .row.find .field{flex:0 1 240px}
main.shop .row.find .field.wide{flex:0 1 320px}
main.shop .chkrow{display:flex;flex-wrap:wrap;gap:8px 18px;align-items:center}
main.shop .chkrow .chk{white-space:nowrap}
/* Codes, batches, dates and money are read as shapes; breaking one over two
   lines is the one thing that stops that working. */
main.shop td.reg, main.shop td.money{white-space:nowrap}
main.shop .actions button, main.shop .actions .dlbtn{white-space:nowrap}
/* Line-entry cells. Without a ceiling the browser hands the widest column to
   whichever input has the least to hold -- Disc % came out twice the width of
   the quantity beside it. */
main.shop #lines td input, main.shop #items td input{width:100%;min-width:0}
main.shop #lines td input.num, main.shop #items td input.num{max-width:86px}
main.shop #lines td:first-child input, main.shop #items td:first-child input{min-width:110px}
main.shop #lines th, main.shop #items th{white-space:nowrap}

/* The bar that says which bill is being corrected. It sits above everything
   because a form that looks exactly like the new-bill form, but is not one, is
   the one thing here that must never be in doubt. */
.editbar{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 10px;
  background:#e6f4ef;border:1px solid #cce5de;border-left:4px solid var(--brand);
  border-radius:8px;padding:10px 14px;font-size:13.5px;color:var(--ink)}
/* .hidden is a single class and so is this, so the later rule wins on equal
   specificity -- display:flex beat display:none and a fresh bill showed an
   empty tinted box. Same fix as .pager.hidden above. */
.editbar.hidden{display:none}
.editbar.warn{background:#fdf6e3;border-color:#e8d9a8;border-left-color:#e0b34d}
.editbar .warnbit{color:#7a5a10;font-weight:600}
.editbar a{color:var(--brand);font-weight:600}

/* ---------------------------------------------------------------- Invoice
   Status: what RGHS has done with each claim.

   The band at the top is the one deliberate piece of design on this screen.
   A claim really does pass along a line -- submitted, assessed by the TPA,
   released by the CU, paid -- so the tiles are numbered and pointed, which is
   a device that would be decoration on any screen where the order did not
   carry information. Everything below it is the ordinary table.

   The money is the large type and the claim count is the small type, because
   the question being asked is almost always "how much is stuck", not "how
   many". */
.stagebar{display:flex;flex-wrap:wrap;gap:0;align-items:stretch}
.stage{flex:1 1 150px;min-width:0;padding:11px 14px;
  background:#f4f8f6;border:1px solid var(--line);border-radius:9px}
/* The arrow between two tiles, never before the first. It is the whole of
   what makes this read as one line rather than four unrelated boxes. */
.stage + .stage{margin-left:26px;position:relative}
.stage + .stage::before{content:"\203A";position:absolute;left:-20px;top:50%;
  transform:translateY(-50%);font-size:19px;color:var(--muted);opacity:.55}
.stagestep{display:inline-block;min-width:16px;font-size:10.5px;font-weight:700;
  color:var(--muted);letter-spacing:.06em}
.stagename{font-size:11.5px;text-transform:uppercase;letter-spacing:.05em;
  color:var(--muted);font-weight:700}
.stageamt{display:block;font-size:19px;font-weight:700;margin-top:5px;
  color:var(--ink);font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
.stagen{display:block;font-size:12px;color:var(--muted);margin-top:1px}
/* Settled is the only stage that is finished, and the only one tinted. Spend
   the colour where it says something: the rest are all "still waiting". */
.stage-settled{background:#e6f4ef;border-color:#cce5de}
.stage-settled .stageamt{color:var(--brand)}
.stage-dropped{background:#f4f5f6}
.stage-dropped .stageamt{color:var(--muted);font-weight:600}
.stagewait{color:var(--muted);font-size:13.5px;margin:2px 0}

.fetchline{font-size:12.5px;color:var(--muted);margin:12px 0 0;line-height:1.5}
/* A date this system recorded, as against one RGHS gave. The distinction is
   the whole reason the page can be trusted, so it is drawn, not just worded. */
.ours{color:var(--muted);font-style:italic}

.statusfilter{display:flex;flex-wrap:wrap;gap:7px}
.statusfilter button{font-size:12.5px;padding:5px 11px;border:1px solid var(--line);
  border-radius:20px;cursor:pointer;font-weight:600}
.statusfilter button.on{background:var(--brand);color:#fff;border-color:var(--brand)}
.statusfilter .cnt{opacity:.65;font-weight:400;margin-left:3px}

/* The status verbatim, coloured by which desk it is on. An unrecognised one
   is drawn plainly rather than guessed at. */
.claimst{display:inline-block;font-size:11px;font-weight:600;padding:2px 9px;
  border-radius:20px;white-space:nowrap}
.claimst.settled{background:#e6f4ef;color:var(--brand)}
.claimst.waiting{background:#fdf6e3;color:#7a5a10}
.claimst.query{background:#fdecea;color:var(--bad)}
.claimst.dropped{background:#f0f2f4;color:var(--muted)}
.claimst.unknown{background:#eef2f4;color:var(--ink)}
/* On the row it may wrap; on the dialog's own bar it may not.
   "PHARMACY CLAIM APPROVED" held on one line puts a 218px floor under the
   Status column, and with the Notes column added that is what pushed the
   whole table past the edge of its card -- and the page into scrolling
   sideways on a 1024-wide screen. Two lines in a pill costs nothing here;
   the bar up in the dialog has a whole line to itself and keeps the line. */
#list td .claimst{white-space:normal}

/* One click opens a row, so the rows have to look clickable. */
#list tbody tr{cursor:pointer}
#list tbody tr:hover{background:#f7faf9}
#list tbody tr.picked{background:#e6f4ef}

/* ---- one claim, over the list ------------------------------------------
   The panel this replaces sat at the foot of the page, so clicking a row in a
   list of tens of thousands scrolled you away from the row you had just
   clicked and left you to scroll back and find your place. It opens over the
   list instead, in a real <dialog>, which brings Escape, the focus trap and
   the backdrop with it. Narrower than the invoice one: this is two small
   tables side by side, not an eleven-column bill. */
#claimBox{border:none;border-radius:12px;padding:14px 20px 16px;
  max-width:min(1000px,96vw);width:1000px;max-height:92vh;
  box-shadow:0 18px 48px rgba(20,32,27,.22);color:var(--ink)}
/* Only while it is open. A <dialog> is display:none until then, and a plain
   display rule overrides that -- which left the box on the page after it had
   been closed, still showing its contents. */
#claimBox[open]{display:flex;flex-direction:column}
#claimBox::backdrop{background:rgba(20,32,27,.42)}
#claimBox #detail{overflow-y:auto;overflow-x:auto;flex:1;min-height:0;
  overscroll-behavior:contain}
/* The heading bar stays put while the claim scrolls under it, so the cross is
   always where it was. */
#claimBox .dlghead{position:sticky;top:0;background:var(--card,#fff);z-index:2;
  padding-bottom:8px;border-bottom:1px solid var(--line);margin-bottom:10px}
/* An invoice number reads as a number, so it is set like one. */
#claimTitle,#pairTitle{font-family:ui-monospace,SFMono-Regular,Consolas,monospace}
/* Nothing to show until the claim has come back; an empty badge is a grey box
   sitting where a status will be. */
#claimStatus:empty,#pairStatus:empty{display:none}
.detailgrid{display:flex;gap:34px;flex-wrap:wrap}
.detailgrid .statetbl{font-size:12.5px}
.detailgrid .statetbl th{padding-right:14px;white-space:nowrap}
/* The note is a sentence in a table of short values. Left to size itself it
   sets the width of the whole value column and flings the three money figures
   to the far side of the box, so it is capped and wraps instead. */
.detailgrid .statetbl td.notetext{max-width:260px;white-space:normal}
.rawmore{margin-top:12px;font-size:12.5px}
.rawmore summary{cursor:pointer;color:var(--muted)}

@media(max-width:820px){
  /* Stacked, the arrows point across a line break and read as noise. */
  .stagebar{flex-direction:column;gap:8px}
  .stage + .stage{margin-left:0}
  .stage + .stage::before{content:none}
  .detailgrid{gap:14px}
}

/* ---- the month-by-month dialog -----------------------------------------
   A real <dialog>, so the focus trap, Escape and the backdrop come from the
   browser rather than from a worse reimplementation of them here. */
#chartBox{border:none;border-radius:12px;padding:18px 20px 14px;max-width:min(940px,94vw);
  width:940px;max-height:92vh;overflow:auto;overscroll-behavior:contain;
  box-shadow:0 18px 48px rgba(20,32,27,.22);color:var(--ink)}
#chartBox::backdrop{background:rgba(20,32,27,.42)}
.dlghead{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:4px}
.dlghead h2{font-size:16px;margin:0;font-weight:700}
.dlghead .viewseg{margin-left:auto;display:flex;border:1px solid var(--line);
  border-radius:7px;overflow:hidden}
.dlghead .viewseg button{background:#fff;color:var(--muted);border:none;
  padding:5px 12px;font-size:12.5px;cursor:pointer;font-weight:600}
.dlghead .viewseg button.on{background:var(--brand);color:#fff}
.note-undated{font-size:11.5px;color:#7a5a10;background:#fdf6e3;
  border:1px solid #e8d9a8;border-radius:20px;padding:2px 9px;font-weight:600}

/* Identity never rests on colour alone: the legend is always present for
   three series, and the values are labelled on the chart as well. */
.chartlegend{display:flex;gap:16px;flex-wrap:wrap;margin:6px 0 2px;
  font-size:12.5px;color:var(--muted);font-weight:600}
.chartlegend i, .chartdata i.key{display:inline-block;width:10px;height:10px;
  border-radius:3px;margin-right:6px;vertical-align:-1px}
.chartwrap{position:relative;margin-top:2px}
.claimchart{display:block;width:100%;height:auto}
/* Hairline, solid, one step off the surface. Never dashed, never assertive. */
.claimchart .grid{stroke:var(--line);stroke-width:1}
/* Columns: capped in width, never filling the band -- the leftover is the air
   between them. The 2px gaps between stacked segments are cut in the geometry
   rather than stroked, so the surface itself does the separating. */
.claimchart .colseg{stroke:none}
.claimchart .colhover{fill:var(--ink);opacity:.05}
/* Text wears text tokens, never a series colour -- aqua is illegible as type
   on white, and identity comes from the coloured mark beside it. */
.claimchart .tick{fill:var(--muted);font-size:11px;
  font-family:system-ui,Segoe UI,Roboto,sans-serif}
.claimchart .tick-y{text-anchor:end}
.claimchart .tick-x{text-anchor:middle}
.claimchart .hit{cursor:crosshair}
.charttip{position:absolute;background:#fff;border:1px solid var(--line);
  border-radius:8px;box-shadow:0 6px 18px rgba(20,32,27,.14);padding:8px 10px;
  font-size:12px;pointer-events:none;min-width:150px;z-index:2}
.charttip b{display:block;font-size:12.5px}
.charttip .tipn{display:block;color:var(--muted);font-size:11px;margin-bottom:4px}
.charttip .tiprow{display:flex;align-items:center;gap:6px;line-height:1.7}
.charttip .tiprow i{width:9px;height:9px;border-radius:2px;flex:none}
.charttip .tiprow b{margin-left:auto;display:inline;font-variant-numeric:tabular-nums}
/* RGHS's own three figures, under the split this page drew from them. The rule
   above them says which is which, so the arithmetic is never mistaken for the
   source. */
.charttip .tipsep{display:block;margin:6px 0 2px;padding-top:5px;
  border-top:1px solid var(--line);color:var(--muted);font-size:10.5px;
  text-transform:uppercase;letter-spacing:.04em}
.charttip .tiprow.raw{color:var(--muted);padding-left:15px}
.oddnote{color:#7a5a10;font-weight:600}
.oddnote.hidden{display:none}
.tablescroll{overflow-x:auto;max-height:260px;overflow-y:auto;
  overscroll-behavior:contain}
table.chartdata{width:100%;font-size:12px}
table.chartdata th{position:sticky;top:0;background:var(--card)}

@media(max-width:820px){
  #chartBox{width:auto;padding:14px 14px 10px}
  .dlghead .viewseg{margin-left:0}
}
@media(prefers-reduced-motion:reduce){
  #chartBox{animation:none}
}

/* What RGHS took off a claim, item by item. The cut lines are the point of
   the table, so they are the ones that carry weight; the rest are context and
   stay quiet. */
table.deducted td{vertical-align:top}
table.deducted tr.wascut td{font-weight:600}
table.deducted tr.wascut td:last-child{font-weight:400;color:#7a5a10}
table.deducted td:last-child{max-width:280px}

/* ---- Rates: what RGHS will pay ----------------------------------------
   One question is asked of this screen, at a counter, with somebody waiting:
   what will they pay for this. So the search is the page rather than a control
   above it, and the rate is the largest thing on the row. */
.ratehead{padding-bottom:12px}
.ratesearch{display:block}
.ratesearch input{font-size:17px;padding:12px 14px}
.ratesearch input::placeholder{color:var(--muted);opacity:.7;font-size:15px}
#ratesLine{margin-top:10px}
/* The answer. Tabular figures so a column of them lines up on the decimal --
   these are compared down the column far more than read one at a time. */
#list b.rate{font-size:15px;font-variant-numeric:tabular-nums;color:var(--ink)}
#list td .sub{font-size:12px}
/* Whose card the bill went on, and the doctor, under the patient's name. Its
   own line rather than two more columns on a table already nine wide -- and
   quieter than the name, because it is how you recognise the claim, not who
   the claim is for. */
#list td .sub.whose{display:block;line-height:1.3;color:var(--muted)}
/* A remark on Invoices, a note on Invoice Status: the same thing on two
   screens -- a line the operator types straight into the row -- so the two
   look and behave alike rather than being two half-remembered versions of one
   idea. It has to look like somewhere you can type before anybody tries; an
   ordinary cell with a cursor in it reads as text somebody else wrote. */
td.remark,td.notes{min-width:120px;cursor:text}
td.remark:empty::before,td.notes:empty::before{content:"—";color:var(--line)}
td.remark:focus,td.notes:focus{outline:2px solid var(--brand);
  outline-offset:-2px;background:#fff}
td.remark.saving,td.notes.saving{opacity:.55}
td.remark.saved,td.notes.saved{background:#e6f4ef}
td.remark.failed,td.notes.failed{background:#fdecea;color:#c0392b}
/* A claim the tracker returned with no invoice number. There is nothing to
   file a note under, so the cell does not offer to be typed in. */
td.notes.nokey{cursor:default}

/* ---- Cards: one RGHS card, and everything ever put on it ----------------
   Same shape as Rates and for the same reason: one question, asked at a
   counter with somebody waiting, so the search is the page. */
.matches{margin-top:10px;display:flex;flex-direction:column;gap:6px}
/* Shut, once a card has been picked out of it. Two classes on purpose: the
   utility .hidden is a single class and is declared far higher up the file, so
   against a single-class display:flex declared here it loses on order alone --
   the list stayed on screen with .hidden faithfully applied to it. */
.matches.hidden{display:none}
.matches .match{border:1px solid var(--line);border-radius:8px;padding:8px 10px;
  cursor:pointer;display:flex;flex-wrap:wrap;gap:4px 10px;align-items:baseline}
.matches .match:hover{background:#eef7f4;border-color:var(--brand)}
.matches .match.picked{border-color:var(--brand);background:#e6f4ef}
.matches .match b{font-size:15px}
.matches .match .reg{font-family:var(--register);color:var(--muted);font-size:12.5px}
.matches .match .sub{margin:0;font-size:12.5px}
/* The household, on its own line: it is what tells one card from another. */
.matches .match .who{flex-basis:100%;color:var(--muted)}
.cardhead h2{margin:0 0 2px}
.cardhead .sub{margin:0 0 12px}
#txns td.num{font-variant-numeric:tabular-nums}
#txns td .sub{display:block;font-size:12px;margin:0}
/* Charged more than RGHS allowed is the ordinary direction, so it is not an
   alarm -- it is the figure the screen exists to show. Green the other way,
   because being paid more than billed is worth a second look. */
#txns .under, #cardTotals .under{color:#a35a12}
#txns .over, #cardTotals .over{color:var(--brand)}
#txns .same, #cardTotals .same{color:var(--muted);font-weight:400}
/* A sale nobody ever claimed for. Quietly marked rather than shouted at: it
   may be deliberate. */
#txns tr.unclaimed td{background:#fdf6e3}
#txns .claimst.none{background:#fdf6e3;color:#7a5a10;border:1px solid #e8d9a8}
#cardTotals td{border-top:2px solid var(--line);font-size:14px;padding-top:10px}
#cardTotals .sub{font-weight:400;margin:3px 0 0}
/* The two records of the card, each under its own heading: what RGHS's own
   portals returned, and what this shop's books say it billed. The heading and
   its line of explanation belong to the table below them, so they sit closer
   to that than to the table above. */
#cardBox .accthist h3{margin-bottom:2px}
#cardBox .accthist > p.sub{margin:0 0 8px}
/* The note against a claim and the remark against our own bill: both are a
   line of prose in a table of figures, so they wrap and are held to a width
   rather than stretching the money columns being read against each other. */
#txns td.notes,#ours td.remark{white-space:normal;max-width:220px;min-width:110px}
/* Our own book, under RGHS's, in the same tabular figures -- the two Billed
   columns are compared down the page and have to line up on the decimal. */
#ours td.num{font-variant-numeric:tabular-nums}
#ours td.reg{white-space:nowrap}
/* The date a transaction happened, on one line. RGHS's own invoice numbers are
   long enough to need two, and once the Notes column joined the table the date
   started breaking after the month -- which reads as two dates at a glance. */
#txns td:first-child{white-space:nowrap}
/* Still loading, or nothing to load. Said in the row: an empty table looks
   like an answer, and on this screen the answer "none" matters. */
#cardBox td.empty{color:var(--muted);text-align:center;padding:14px 8px}
#cardBox td.empty.bad{color:var(--bad,#b0413e)}
/* What the shop charged, beside what RGHS pays. The same weight as the rate --
   the point of the row is that the two are read against each other, so neither
   may look like the footnote of the other -- with the spread and the number of
   lines under it, where there is a spread to show. */
#list td.sold b{font-size:15px;font-variant-numeric:tabular-nums;color:var(--ink)}
#list td.sold .sub{display:block;margin:0;line-height:1.3}
#list td.sold.none{color:var(--muted)}
/* The gap. Coloured, because "we are charging above what they will pay" and
   "we are charging below it" are different news and the sign alone is easy to
   read past in a column of figures. Never a warning: a difference is a fact
   about two prices, and what to do about it is the operator's call. */
#list td.diff{font-variant-numeric:tabular-nums;font-weight:600}
#list td.diff.over{color:#a35a12}
#list td.diff.under{color:var(--brand)}
#list td.diff.same{color:var(--muted);font-weight:400}

/* The account-history panel at the foot of an invoice. */
.accthist{margin-top:18px}
.accthist h3{font-size:14px;margin:0 0 8px;color:var(--ink)}
.accttbl .here{background:#fff8e1}
.accttbl .off td{opacity:.55}

/* ---- the medicine dialog -------------------------------------------------
   Same bargain as the month-by-month one above: a real <dialog>, so Escape,
   the focus trap and the backdrop are the browser's rather than a worse
   reimplementation here. The cross is in the corner because that is where
   people reach for it; Escape still works and is not advertised. */
#medBox{border:none;border-radius:12px;padding:16px 20px 14px;
  max-width:min(1040px,95vw);width:1040px;
  max-height:92vh;overflow:auto;overscroll-behavior:contain;
  box-shadow:0 18px 48px rgba(20,32,27,.22);color:var(--ink)}
#medBox::backdrop{background:rgba(20,32,27,.42)}
/* The cross that shuts a floating box, on all four of them.
   It is drawn rather than typed. It used to be the character U+2715, and that
   glyph's ink sits 1.1px above the middle of its own line box -- measured off
   the rendered pixels, not guessed -- so on a 30px square it read as high no
   matter how the box was centred. Centring the box differently changes nothing
   at all; the offset is inside the letter. U+00D7 is better and still off by
   0.35px, and neither is a promise any other font would keep.
   Two lines about the centre of a square viewBox cannot be off centre, and
   they look the same on every machine. The flex box is what centres the
   drawing in the button, and the zeroed padding stops the browser's own
   button padding nudging it back off. */
.dlgx{margin-left:auto;background:none;border:1px solid var(--line);
  border-radius:8px;width:30px;height:30px;cursor:pointer;
  color:var(--muted);flex:none;
  display:flex;align-items:center;justify-content:center;padding:0}
.dlgx svg{width:14px;height:14px;display:block;fill:none;
  stroke:currentColor;stroke-width:1.6;stroke-linecap:round}
.dlgx:hover{background:var(--line);color:var(--ink)}
.dlgx:focus-visible{outline:2px solid var(--brand);outline-offset:2px}

/* A row that opens something says so before it is clicked. Single click, and
   the whole row is the target -- not a link buried in one cell. */
table.clickrows tbody tr{cursor:pointer}
table.clickrows tbody tr:hover{background:var(--hover,#f3f6f4)}

/* The codes a medicine has gone by. Many on a busy medicine, so they wrap and
   stay small rather than pushing every other column off the screen. */
.codelist{display:flex;flex-wrap:wrap;gap:3px;max-width:280px}
.codelist .cd{font-size:11px;background:var(--line);border-radius:4px;
  padding:1px 5px;font-variant-numeric:tabular-nums;white-space:nowrap}
.codelist .more{font-size:11px;color:var(--muted);padding:1px 2px}

/* The three price columns on the medicines list: what the shop charges, the
   RGHS discount it charges under, and what RGHS's own sheets pay for a unit.
   Tabular figures and no wrapping -- these are read down the column against
   each other, and a price broken over two lines reads as two prices. The
   codes column beside them is allowed to wrap and they are not, so a narrow
   window squeezes the chips rather than the money. */
#recentMed td.disc,#recentMed td.mrp,#recentMed td.rghs{
  font-variant-numeric:tabular-nums;white-space:nowrap}
/* What RGHS pays is the figure the other two are read against, so it is the
   one with weight on it. Never coloured: a price is a fact about a price, and
   whether it is good news is the operator's call. */
#recentMed td.rghs .rghsrate{font-weight:600;color:var(--ink)}
/* Two spellings of one medicine, priced differently by RGHS. Marked quietly
   rather than warned about -- it is reported, not corrected. */
#recentMed td.rghs .rghsrate.spread{font-weight:500;border-bottom:1px dotted var(--line)}
/* A count after a range, so "three MRPs" is not mistaken for a fourth figure. */
#recentMed td.disc .sub,#recentMed td.mrp .sub{font-size:11px}
/* The Edit column. A medicine is a family of codes and there is no screen on
   which they are separate things to correct, so this row is where the whole
   family is corrected -- which is also why the button says Edit rather than
   sitting silently as a pencil: what it reaches is worth naming. */
#recentMed td.medact{white-space:nowrap}
#recentMed td.medact button{font-size:12px;padding:3px 10px;border-radius:6px}
#recentMed tr.editing td{background:#fff8e1}
#recentMed tr.editing input{padding:5px 7px;font-size:13px}
#recentMed tr.editing input.num{text-align:right;font-variant-numeric:tabular-nums}
/* A row being edited is a form, so it must not also look like a way into the
   medicine behind it. */
#recentMed tr.editing{cursor:default}

/* The dialog's own table: dense, because it is a ledger and the whole point is
   seeing every batch at once. */
.medtable{width:100%;border-collapse:collapse;margin-top:10px}
.medtable th,.medtable td{padding:6px 8px;border-bottom:1px solid var(--line);
  font-size:12.5px;text-align:left;white-space:nowrap}
.medtable th{color:var(--muted);font-weight:600;font-size:11px;
  text-transform:uppercase;letter-spacing:.04em}
.medtable td.num,.medtable th.num{text-align:right;
  font-variant-numeric:tabular-nums}
.medtable tfoot td{font-weight:700;border-top:2px solid var(--line);
  border-bottom:none}
.medtable tr.gone td{color:var(--muted)}
.medtable .expired{color:#b0413e;font-weight:600}
.medsum{display:flex;flex-wrap:wrap;gap:18px;margin:12px 0 2px}
.medsum div{font-size:12px;color:var(--muted)}
.medsum b{display:block;font-size:18px;color:var(--ink);
  font-variant-numeric:tabular-nums}
.medempty{color:var(--muted);font-size:13px;padding:10px 0}

/* The medicine's month-by-month columns. One series, so the colour carries no
   identity and is the page's own; the peak is a shade stronger because "when
   was the most of this sold" is the question the chart is opened for. */
.medchart .colseg{fill:var(--brand);opacity:.75}
.medchart .colseg.peak{opacity:1}
.medchart .colseg:hover{opacity:1}

/* Deductions: the share column carries its own bar, drawn behind the figure
   rather than in a column beside it. The table is thirty-odd rows on one
   screen and ranking them by eye is the whole use of it; a separate bar
   column would take width from the reason text, which is the part that has
   to stay readable. */
.shareCell{position:relative;isolation:isolate}
.shareCell::before{content:"";position:absolute;inset:2px auto 2px 0;
  width:var(--share,0);background:var(--brand);opacity:.16;border-radius:2px;
  z-index:-1}
/* RGHS writes these in whatever case and punctuation the assessor used, and
   they are shown that way. Left alone deliberately: no capitalising, no
   trimming of the full stops. */
td.reason{max-width:38ch}


/* ---- Bills & Claims -------------------------------------------------------
   The band is a row of buttons: each stage opens the whole list at that stage,
   so the figure and the rows behind it are one gesture apart. They are the
   same tiles Invoice Status draws, with a button's reset on top. */
.stagebar button.stage{font:inherit;text-align:left;cursor:pointer;
  border:1px solid transparent;border-radius:9px;background:none;color:inherit}
.stagebar button.stage:hover{background:#f3f8f6}
.stagebar button.stage.on{background:#e6f4ef;border-color:#cce5de}
.stagebar button.stage:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
/* Ours, not RGHS's: bills RGHS has never reported. Amber, because it is the
   tile that means something has not happened yet. */
.stage-ours .stageamt{color:#7a5a10}
.stage-queried .stageamt{color:var(--bad)}
.stage-tpa .stageamt,.stage-cu .stageamt{color:#7a5a10}
.stage-approved .stageamt{color:var(--brand)}
.stage-dropped .stageamt,.stage-other .stageamt{color:var(--muted);font-weight:600}

/* Which list is showing. The same control as the month-by-month dialog's, out
   here on the page rather than in a dialog's heading. */
.filters .viewseg{display:flex;border:1px solid var(--line);border-radius:8px;
  overflow:hidden}
.filters .viewseg button{background:#fff;color:var(--muted);border:none;
  font-size:12.5px;font-weight:600;padding:6px 13px;cursor:pointer}
.filters .viewseg button + button{border-left:1px solid var(--line)}
.filters .viewseg button.on{background:var(--brand);color:#fff}

/* What the list has been narrowed to, and the way back out. */
.narrowed{margin:0;font-size:12.5px;color:var(--muted);display:flex;gap:8px;
  align-items:center}
.narrowed button{font-size:12px;padding:3px 9px}

/* The mark on a row: that a pairing rests on no identifier, or that there is
   something about it to read. The whole of it is in the dialog. */
.pairmark{display:inline-block;font-size:10.5px;font-weight:700;padding:1px 6px;
  border-radius:20px;background:#f0f2f4;color:var(--muted);vertical-align:1px}
.pairmark.warn{background:#fdf6e3;color:#7a5a10}
.paircell{min-width:170px}
.pairflag{display:inline-block;font-size:11px;font-weight:600;padding:2px 9px;
  border-radius:20px;background:#fdf6e3;color:#7a5a10;margin:1px 0}
.pairwhy{margin:0 0 8px;font-size:13.5px;line-height:1.5;max-width:90ch}
.pairlines{margin-top:14px}
.pairlines caption{text-align:left;font-weight:600;font-size:12.5px;padding-bottom:4px;color:var(--ink)}
.pairlines .statetbl{font-size:12.5px}
.pairlines .statetbl td{padding-right:14px}
/* A day where fewer bills reached RGHS than were written. */
#daily td.short{color:var(--bad);font-weight:600}
#attention tbody tr,#daily tbody tr{cursor:pointer}
#attention tbody tr:hover,#daily tbody tr:hover{background:#f7faf9}

/* ---- scanning a receipt, and reviewing what was read ---------------------
   Built for a phone held in one hand at the counter: one column, targets big
   enough for a thumb, and no horizontal scrolling except the table itself,
   which is genuinely wider than a phone and says so by scrolling. */
.scan-box{display:flex;flex-direction:column;gap:12px}
.sc-shoot{font-size:16px;padding:12px 18px;border-radius:10px}
.sc-pages{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.sc-page{display:inline-flex;align-items:center;justify-content:center;
  min-width:34px;height:34px;border-radius:8px;background:#eef2f7;
  border:1px solid var(--line);font-size:13px;font-weight:600}
.sc-page.done{background:#e6f4ef;border-color:#9ed2be}
.sc-page.failed{background:#fdecec;border-color:#e6b0b0}
.scan-note.bad{color:#a3242b}

/* the bill's own particulars: label, value, and the button that takes it */
.sc-fields{display:flex;flex-direction:column;gap:8px}
.sc-field{display:grid;grid-template-columns:minmax(90px,28%) 1fr auto auto;
  gap:8px;align-items:center}
.sc-field label{font-size:12px;color:var(--muted)}
.sc-field .sc-val{width:100%;box-sizing:border-box;padding:8px;font-size:15px;
  border:1px solid var(--line);border-radius:8px}
.sc-field.used .sc-val{background:#f2fbf7;border-color:#9ed2be}
.sc-flag{font-size:11px;padding:2px 6px;border-radius:999px}
.sc-flag.check{background:#fff4e0;color:#8a5a12}
.sc-flag.unsure{background:#fdecec;color:#a3242b}

/* the medicines. A bill is wider than a phone; the table scrolls on its own
   rather than pushing the page sideways. */
.sc-tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.sc-table{width:100%;border-collapse:collapse;font-size:13px}
.sc-table th{text-align:left;font-size:11px;color:var(--muted);font-weight:600;
  padding:6px 4px;border-bottom:1px solid var(--line);white-space:nowrap}
.sc-table td{padding:3px 4px;border-bottom:1px solid #f0f2f4;vertical-align:middle}
.sc-table .sc-val{width:100%;min-width:64px;box-sizing:border-box;padding:6px;
  font-size:13px;border:1px solid transparent;border-radius:6px;background:#fbfcfd}
.sc-table .sc-val:focus{border-color:var(--brand);background:#fff;outline:none}
.sc-cell.unsure .sc-val{background:#fdf4f4}
.sc-table td:first-child .sc-val{min-width:160px}
.sc-row.used .sc-val{background:#f2fbf7}
.sc-row.done .sc-val{background:#f6f8f7;color:var(--muted)}
.sc-act{white-space:nowrap;text-align:right}
.sc-act .sc-use{padding:6px 12px;border-radius:8px;font-size:13px}
/* already in the system: a tick, and nothing to press */
.sc-tick{color:#1b7f5a;font-size:18px;font-weight:700}
.sc-actions{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.sc-actions .primary,.sc-actions .ghost{padding:10px 16px;border-radius:10px;font-size:15px}
.sc-sum{display:flex;flex-direction:column;gap:4px;margin:0 0 10px}
.sc-sum div{display:flex;gap:10px}
.sc-sum dt{min-width:120px;color:var(--muted);font-size:12px}
.sc-sum dd{margin:0;font-weight:600}
@media (max-width:520px){
  .sc-field{grid-template-columns:1fr auto auto}
  .sc-field label{grid-column:1/-1;margin-bottom:-4px}
}
/* a line the reading doubts: said under the row, in the operator's words */
.sc-row.doubted .sc-val{background:#fffaf0}
.sc-doubt td{padding:2px 6px 8px;font-size:12px;color:#8a5a12;border-bottom:1px solid #f0f2f4}
.sc-doubt.done td{color:var(--muted)}
