/* Tinna Medical Centre — design system
   Grounded in the clinic's own materials: ledger paper, carbon receipts,
   a surgical green. Figures are monospaced so money lines up like a slip. */
:root{
  --paper:#F6F7F4; --surface:#FFFFFF; --surface-2:#FBFCFA;
  --ink:#16201C; --ink-2:#4A554F; --ink-3:#65716A;
  --rule:#DDE2DC; --rule-2:#EAEEE8;
  --accent:#0E6B57; --accent-ink:#FFFFFF; --accent-soft:#E3F0EB;
  --amber:#8A5200; --amber-soft:#FAEEDA;
  --red:#A32020; --red-soft:#F8E4E4;
  --blue:#1D4E89; --blue-soft:#E4EDF7;
  --shadow:0 1px 0 rgba(22,32,28,.03);
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
  --sans:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --r:6px;
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --paper:#0F1513; --surface:#18211E; --surface-2:#141C19;
    --ink:#E8EDE9; --ink-2:#A9B5AE; --ink-3:#8D9992;
    --rule:#2A3531; --rule-2:#212B27;
    --accent:#3FBF9F; --accent-ink:#06231C; --accent-soft:#16332C;
    --amber:#E0A458; --amber-soft:#2E2210;
    --red:#EE8A8A; --red-soft:#331717;
    --blue:#8FB6E3; --blue-soft:#16233A;
    --shadow:0 1px 0 rgba(0,0,0,.25);
  }
}
:root[data-theme="dark"]{
  --paper:#0F1513; --surface:#18211E; --surface-2:#141C19;
  --ink:#E8EDE9; --ink-2:#A9B5AE; --ink-3:#8D9992;
  --rule:#2A3531; --rule-2:#212B27;
  --accent:#3FBF9F; --accent-ink:#06231C; --accent-soft:#16332C;
  --amber:#E0A458; --amber-soft:#2E2210;
  --red:#EE8A8A; --red-soft:#331717;
  --blue:#8FB6E3; --blue-soft:#16233A;
  --shadow:0 1px 0 rgba(0,0,0,.25);
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--sans);
     font-size:13.5px;line-height:1.45;-webkit-font-smoothing:antialiased}
a{color:var(--accent)}
button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:5px}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
.num{font-family:var(--mono);font-variant-numeric:tabular-nums}
.lbl{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);font-weight:600}
.muted{color:var(--ink-3)}
.r{text-align:right}
.money{font-family:var(--mono);font-variant-numeric:tabular-nums;white-space:nowrap}
.money.big{font-size:15px;font-weight:700}
.dim{opacity:.45}
.stack{display:flex;flex-direction:column;gap:16px}
.row-between{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}
.seg{display:inline-flex;background:var(--surface-2);border:1px solid var(--rule);border-radius:9px;padding:3px;gap:2px}
.seg a{padding:6px 12px;border-radius:7px;font-size:12.5px;text-decoration:none;color:var(--ink-2)}
.seg a.on{background:var(--accent);color:var(--accent-ink);font-weight:600}
.results{margin-top:6px}
.result{display:flex;align-items:center;gap:11px;padding:11px 4px;border-bottom:1px solid var(--rule-2);
  text-decoration:none;color:inherit;border-radius:7px}
.result:hover,.result.active{background:var(--accent-soft);padding-left:8px;padding-right:8px}
/* The arrow-key highlight has to be visible without a mouse anywhere near it. */
.result.active{outline:2px solid var(--accent);outline-offset:-2px;border-radius:8px}
.result:last-child{border-bottom:0}
.av-sm{width:34px;height:34px;border-radius:50%;background:var(--accent-soft);color:var(--accent);
  display:grid;place-items:center;font-size:12px;font-weight:700;flex:0 0 auto}

/* shell */
.app{display:grid;grid-template-columns:216px 1fr;min-height:100vh}
/* Grid items refuse to shrink below their content unless told to. Without
   this the nav's own width props the whole page open and `overflow-x:auto`
   never gets a chance to scroll anything — which is why the collapsed rail
   was still forcing 500px onto a 375px screen. */
.app>*{min-width:0}
.rail{background:var(--surface-2);border-right:1px solid var(--rule);padding:16px 12px;
      display:flex;flex-direction:column;gap:20px;position:sticky;top:0;height:100vh;overflow-y:auto}
.brand{display:flex;gap:10px;align-items:center;padding:0 6px;text-decoration:none;color:inherit}
.mark{width:31px;height:31px;border-radius:9px;background:var(--accent);color:var(--accent-ink);
      display:grid;place-items:center;font-weight:700;font-size:14px;flex:0 0 auto}
.brand b{font-size:14.5px;display:block;line-height:1.2;letter-spacing:-.01em}
.brand span{font-size:11px;color:var(--ink-3)}
/* `.brand span` (0,1,1) outranks `.mark` (0,1,0), so the letter in the logo
   square has been rendering in muted grey on the accent green — 1.29:1, which
   is very close to invisible. It needs the specificity back. */
.brand .mark{color:var(--accent-ink)}
.rail nav{display:flex;flex-direction:column;gap:2px}
.rail nav a{display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:7px 9px;border-radius:5px;font-size:13px;color:var(--ink-2);text-decoration:none}
.rail nav a:hover{background:var(--rule-2);color:var(--ink)}
.rail nav a.on{background:var(--accent-soft);color:var(--accent);font-weight:600}
.rail nav .c{font-family:var(--mono);font-size:11px;color:var(--ink-3)}
.rail-foot{margin-top:auto;display:flex;flex-direction:column;gap:9px;padding:0 6px}
.who{display:flex;gap:9px;align-items:center}
.who .av{width:30px;height:30px;border-radius:50%;background:var(--accent-soft);color:var(--accent);
  display:grid;place-items:center;font-size:11.5px;font-weight:700;flex:0 0 auto}
.who b{font-size:12.5px;display:block;line-height:1.2}
.who span{font-size:11px;color:var(--ink-3)}
main{padding:22px 26px 64px;max-width:1240px;width:100%}

/* pieces */
.head{display:flex;justify-content:space-between;align-items:flex-end;gap:16px;flex-wrap:wrap;margin-bottom:20px}
h1{font-size:18px;margin:0 0 2px;letter-spacing:-.01em;text-wrap:balance}
h2{font-size:16px;margin:0 0 8px;letter-spacing:-.01em}
.sub{color:var(--ink-2);font-size:13.5px;margin:0;max-width:64ch}
.card{background:var(--surface);border:1px solid var(--rule);border-radius:var(--r);box-shadow:var(--shadow)}
.card>h2{font-size:11.5px;margin:0;padding:10px 13px;border-bottom:1px solid var(--rule-2);
  display:flex;justify-content:space-between;align-items:center;gap:8px}
.card>h2 em{font-style:normal;color:var(--ink-3);font-weight:400;font-size:11.5px}
.pad{padding:15px}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;margin-bottom:20px}
/* Four tiles of identical weight means the one reading K0.00 gets the same
   share of the eye as the one saying there is money uncollected in the
   building. A tile that wants something done says so. */
.stat.needs{border-color:var(--red);background:var(--red-soft)}
.stat.needs .v{color:var(--red)}
.stat.quiet .v{color:var(--ink-2);font-weight:600}

/* The two-column page layouts.
   These lived as inline `style="grid-template-columns:1fr 340px"` with a class
   attached that was never written, so no breakpoint could reach them and every
   one of these screens overflowed a phone by around 300px. Inline styles also
   beat a media query, so the columns had to move here to be collapsible at
   all. */
.deskgrid,.billgrid,.clingrid,.ptgrid,.showgrid,.setupgrid{
  display:grid;gap:20px;align-items:start}
.deskgrid{grid-template-columns:1fr 340px}
.billgrid{grid-template-columns:1fr 350px}
.clingrid,.ptgrid,.setupgrid{grid-template-columns:1fr 330px}
.showgrid{grid-template-columns:1fr 320px}
.stat{background:var(--surface);border:1px solid var(--rule);border-radius:var(--r);padding:11px 13px;box-shadow:var(--shadow)}
.stat .v{font-family:var(--mono);font-size:18px;font-weight:600;letter-spacing:-.02em;margin:3px 0 1px}
.stat .d{font-size:11.5px;color:var(--ink-3)}
.bar{height:5px;border-radius:3px;background:var(--rule-2);overflow:hidden;margin-top:7px}
.bar i{display:block;height:100%;background:var(--accent)}

.btn{display:inline-flex;align-items:center;gap:7px;background:var(--accent);color:var(--accent-ink);
  border:0;border-radius:5px;padding:7px 13px;font-size:13px;font-weight:600;text-decoration:none}
.btn:hover{filter:brightness(1.08)}
.btn:disabled{background:var(--rule);color:var(--ink-2);cursor:not-allowed;filter:none}
.btn.ghost{background:var(--surface);border:1px solid var(--rule);color:var(--ink);font-weight:500}
.btn.ghost:hover{border-color:var(--accent);color:var(--accent);filter:none}
.btn.danger{background:var(--red)}
.btn.sm{padding:6px 11px;font-size:12.5px}
.btn.block{width:100%;justify-content:center;padding:11px}

label{display:block}
.f{display:flex;flex-direction:column;gap:5px;margin-bottom:13px}
.f>span{font-size:12px;font-weight:600;color:var(--ink-2)}
input[type=text],input[type=email],input[type=password],input[type=date],input[type=month],
input[type=number],input[type=tel],input[type=search],select,textarea{
  width:100%;background:var(--surface-2);border:1px solid var(--rule);border-radius:9px;
  padding:10px 12px;font-size:14px;min-height:44px;transition:border-color .12s,box-shadow .12s,background .12s}
input::placeholder,textarea::placeholder{color:var(--ink-3)}
input:hover,select:hover,textarea:hover{border-color:var(--ink-3)}
input:focus,select:focus,textarea:focus{border-color:var(--accent);background:var(--surface);outline:none;
  box-shadow:0 0 0 3px var(--accent-soft)}
input:disabled,select:disabled{opacity:.55;cursor:not-allowed}

/* A checkbox deciding whether a service is billable was 13px square. WCAG 2.2
   asks for 24, and a 13px target on a phone is a coin toss. */
input[type=checkbox],input[type=radio]{
  /* 20px of box inside 4px of margin gives 28px of exclusive space, which
     clears WCAG 2.2's spacing exception rather than sitting exactly on it.
     It was 13px square, deciding whether a service is billable. */
  width:20px;height:20px;min-height:20px;accent-color:var(--accent);
  margin:4px;cursor:pointer;flex:0 0 auto}

/* Pagination, in this application's own idiom rather than Tailwind's. */
.pager{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.pager-step{display:inline-flex;align-items:center;min-height:34px;padding:6px 13px;
  border:1px solid var(--rule);border-radius:9px;background:var(--surface);
  color:var(--ink);text-decoration:none;font-size:13px}
.pager-step:hover{border-color:var(--accent);color:var(--accent)}
.pager-step[aria-disabled=true]{opacity:.45;pointer-events:none}
.pager-where{color:var(--ink-3);font-size:12.5px}
select{appearance:none;background-image:linear-gradient(45deg,transparent 50%,var(--ink-3) 50%),
  linear-gradient(135deg,var(--ink-3) 50%,transparent 50%);
  background-position:calc(100% - 17px) calc(50% + 1px),calc(100% - 12px) calc(50% + 1px);
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:34px}
textarea{min-height:88px;resize:vertical;line-height:1.55}
/* search field with a magnifier drawn in CSS, no icon font to load */
.search{position:relative}
.search input{padding-left:36px}
.search::before{content:"";position:absolute;left:13px;top:50%;width:11px;height:11px;
  margin-top:-7px;border:1.8px solid var(--ink-3);border-radius:50%;pointer-events:none}
.search::after{content:"";position:absolute;left:22px;top:50%;width:6px;height:1.8px;
  margin-top:3px;background:var(--ink-3);transform:rotate(45deg);pointer-events:none}
.search.busy::before{border-color:var(--accent);border-right-color:transparent;animation:spin .7s linear infinite}
.search.busy::after{opacity:0}
@keyframes spin{to{transform:rotate(360deg)}}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:0 13px}
.err{color:var(--red);font-size:12px;margin:-8px 0 11px}

table{width:100%;border-collapse:separate;border-spacing:0;font-size:13px}
thead th{position:sticky;top:0;z-index:2;background:var(--surface);
   text-align:left;font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);
   font-weight:600;padding:10px 15px;border-bottom:1px solid var(--rule);white-space:nowrap}
td{padding:8px 13px;border-bottom:1px solid var(--rule-2);vertical-align:middle}
tbody tr:last-child td{border-bottom:0}
tbody tr{transition:background .1s}
tbody tr:hover{background:var(--surface-2)}
tbody tr.row-link{cursor:pointer}
tbody tr.row-link:hover td:first-child{box-shadow:inset 3px 0 0 var(--accent)}
tfoot td{padding:9px 13px;border-top:1.5px solid var(--ink);font-weight:600}
.t-wrap{max-height:none;overflow:auto}
/* two-line cell: the thing, then what qualifies it */
.cell2 b{display:block;font-weight:600}
.cell2 span{display:block;font-size:11.5px;color:var(--ink-3)}
.scroll{overflow-x:auto}
.chip{display:inline-block;padding:2px 8px;border-radius:5px;font-size:11px;font-weight:600;white-space:nowrap}
.chip.ok{background:var(--accent-soft);color:var(--accent)}
.chip.warn{background:var(--amber-soft);color:var(--amber)}
.chip.bad{background:var(--red-soft);color:var(--red)}
.chip.info{background:var(--blue-soft);color:var(--blue)}
.empty{text-align:center;color:var(--ink-3);font-size:13px;padding:34px 16px;line-height:1.55}
.flash{border-radius:9px;padding:11px 14px;font-size:13.5px;margin-bottom:16px;border:1px solid}
.flash.ok{background:var(--accent-soft);border-color:transparent;color:var(--accent)}
.flash.bad{background:var(--red-soft);border-color:transparent;color:var(--red)}

/* Below this width a wide table is unreadable, so each row becomes a card
   with its column name printed beside the value. */
@media(max-width:760px){
  table.cards thead{display:none}
  table.cards,table.cards tbody,table.cards tr,table.cards td{display:block;width:100%}
  table.cards tr{border:1px solid var(--rule);border-radius:10px;margin-bottom:10px;
    padding:4px 2px;background:var(--surface)}
  table.cards td{border:0;padding:7px 13px;display:flex;justify-content:space-between;gap:12px;text-align:right}
  table.cards td::before{content:attr(data-l);font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;
    color:var(--ink-3);font-weight:600;text-align:left;flex:0 0 auto;padding-top:2px}
  table.cards td:first-child{border-bottom:1px solid var(--rule-2);margin-bottom:3px}
  table.cards tfoot td{border-top:2px solid var(--ink)}
}
@media(max-width:900px){
  .app{grid-template-columns:1fr}
  /* The rail used to lie down and become a horizontal scrolling strip. With
     fourteen destinations that showed about three of them, gave no sign the
     rest existed, and put "Sign out" in the same swipe as "Front desk". It is
     a drawer now: closed by default, over the page rather than above it, the
     way Horizon does it. */
  .rail{position:fixed;top:0;left:0;bottom:0;width:270px;height:100dvh;z-index:60;
        transform:translateX(-100%);border-right:1px solid var(--rule);
        overflow-y:auto;overscroll-behavior:contain;
        /* `visibility` is here for the keyboard, not the eye: a drawer moved
           off-screen with `transform` alone keeps all fourteen links in the
           tab order, so tabbing walks through a menu nobody can see. It is
           delayed on close so the slide-out is still watchable. */
        visibility:hidden;
        transition:transform .22s cubic-bezier(.2,.7,.3,1),visibility 0s .22s}
  body.navopen .rail{transform:none;visibility:visible;transition-delay:0s}
  .navscrim{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:50;
            opacity:0;pointer-events:none;transition:opacity .22s}
  body.navopen .navscrim{opacity:1;pointer-events:auto}
  body.navopen{overflow:hidden}
  /* Room for the fixed bar, which the grid no longer accounts for. */
  .app{padding-top:52px}
  /* Full-width rows with generous targets: this is a list to be tapped, not a
     sidebar to be glanced at. */
  .rail nav a{padding:11px 12px;font-size:14px;border-radius:7px}
  .rail-foot{padding-bottom:8px}
  main{padding:16px 14px 60px}
  .grid2{grid-template-columns:1fr}
  /* One column, and the rail that was beside the work goes underneath it —
     on a phone the slip matters more than the catalogue next to it. */
  .deskgrid,.billgrid,.clingrid,.ptgrid,.showgrid,.setupgrid{grid-template-columns:1fr}

  /* Cards and the rows inside them have to be allowed to shrink. A patient
     row is a name, two chips and a button on one line, and none of those can
     narrow, so the row props its card open and the card props the page open.
     On a phone it wraps onto a second line instead. */
  .card,.stat{min-width:0}

  /* A patient row is a name, its file number, two chips and a button — five
     things that cannot narrow, on one line. Rather than letting them squeeze
     until "Njavwa Sakala" breaks across two lines, the row becomes two
     deliberate ones: who it is, then what to do about them. */
  .result{flex-wrap:wrap;row-gap:8px;align-items:flex-start}
  .result>*{min-width:0}
  .result>:nth-child(2){flex:1 1 calc(100% - 46px)}
  .result>:nth-child(n+3){margin-left:46px}
  .result>:nth-child(n+4){margin-left:0}
  /* Only the file number must not break mid-token. Pinning the whole
     sub-line also pinned the department list, which grows as a patient
     collects charges across books — so the stage at the end of it ran off the
     card and "Gone home" was the part that got cut. */
  .result .num{white-space:normal}
  .result .num .mrn{white-space:nowrap}
  .head{flex-wrap:wrap;row-gap:10px}
  /* Anything with its own scroll keeps it rather than pushing the page. */
  .scroll{max-width:100%}
}

/* ---- micro-interactions -------------------------------------------------
   Every one of these answers a question she would otherwise have to guess
   at: did that register, is it still going, what just changed. The global
   prefers-reduced-motion rule above switches all of it off. */

/* A button that has been pressed says so, and cannot be pressed again. Money
   is the reason: a double-tapped "Take payment" is a double payment. */
.btn[disabled],.btn.busy{opacity:.72;cursor:progress;pointer-events:none}
.btn.busy::before{content:"";width:12px;height:12px;border-radius:50%;
  border:2px solid currentColor;border-top-color:transparent;
  animation:spin .6s linear infinite;flex:none}
@keyframes spin{to{transform:rotate(360deg)}}

/* The flash message is the system answering back, so it arrives rather than
   appearing — enough to catch the eye at 26 receipts a day, no more. */
.flash{animation:drop .22s cubic-bezier(.2,.7,.3,1)}
@keyframes drop{from{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:none}}

/* A line added to the slip should be visibly the thing she just tapped. */
.line{animation:linein .16s ease-out}
@keyframes linein{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}

/* Tapping a service acknowledges the tap in the hand, not on the next paint. */
.svc:active{transform:translateY(1px)}
.svc{transition:border-color .12s,background .12s,transform .06s}

/* Search that is working looks like it is working. */
.search.busy input{background-image:linear-gradient(90deg,transparent,var(--accent-soft),transparent);
  background-size:180% 100%;animation:sweep 1.1s linear infinite}
@keyframes sweep{from{background-position:180% 0}to{background-position:-80% 0}}

/* Rows that arrive from a search settle in rather than snapping. */
.results .result{animation:linein .14s ease-out}

/* A book is shut until she wants it. The summary row stays a target the
   width of the card so it is hard to miss with a fast hand. */
.book{border-bottom:1px solid var(--rule-2)}
.book>summary{list-style:none;cursor:pointer;padding:11px 13px;display:flex;
  justify-content:space-between;align-items:baseline;gap:10px}
.book>summary::-webkit-details-marker{display:none}
.book>summary:hover{background:var(--surface-2)}
.book>summary::after{content:"▸";color:var(--ink-3);font-size:11px;transition:transform .15s}
.book[open]>summary::after{transform:rotate(90deg)}
.svchits{display:flex;flex-wrap:wrap;gap:6px;margin-top:9px}
.svchits .svc{animation:linein .12s ease-out}
/* `.btn.danger` paints the background red and `.btn.ghost.danger` paints the
   text red, so a button carrying both classes came out red on red — exactly
   1:1, an invisible label on the control that removes a service. The ghost
   variant takes its background back. */
.btn.ghost.danger{color:var(--red);background:var(--surface);border-color:var(--rule)}
.btn.ghost.danger:hover{border-color:var(--red);background:var(--red-soft)}

/* A line taken off a slip: small, quiet, and never mistaken for the row
   itself. Styled through the tokens so it follows light and dark like
   everything else. */
.linkish{
  /* 24x24 is the WCAG 2.2 minimum (2.5.8) and this one removes a billing
     line, so it was the worst thing in the app to have at 12px square. */
  background:none;border:0;cursor:pointer;
  color:var(--ink-3);font:inherit;font-size:12px;line-height:1;
  min-width:24px;min-height:24px;padding:4px 6px;border-radius:6px;
}
.linkish:hover,.linkish:focus-visible{ color:var(--red); background:var(--surface-2); }

/* Corrections sit under a receipt and should read as an aside, not an
   invitation. */
.corrections{ background:var(--surface-2); }
.corrections .f span{ font-size:10.5px; }

/* ---- the filter card ----------------------------------------------------
   Two dates and an Apply on one strip, five one-tap ranges on another below
   it, divided because they are different acts: one is typing, the other is
   pointing. Borrowed from Horizon Shop Tracker, where the same question is
   asked of the same kind of person at the end of a day. */
/* ---- toasts -------------------------------------------------------------
   The flash used to sit at the top of the content and push the page down as
   it arrived. Bottom-right instead, over the page: it never moves the thing
   she was about to tap, and it leaves on its own. */
.toasts{position:fixed;right:16px;bottom:16px;z-index:80;display:flex;flex-direction:column-reverse;
  gap:9px;pointer-events:none;max-width:min(360px,calc(100vw - 32px))}
.toast{display:flex;align-items:flex-start;gap:10px;pointer-events:auto;
  padding:11px 13px;border-radius:9px;font-size:13.5px;line-height:1.45;
  background:var(--surface);border:1px solid var(--rule);box-shadow:0 6px 22px rgba(0,0,0,.16);
  transform:translateY(6px);opacity:0;transition:transform .2s,opacity .2s}
.toast.in{transform:none;opacity:1}
/* A coloured edge rather than a coloured fill: the text stays on the surface
   colour, so it keeps its contrast in both themes without a second palette. */
.toast.ok{border-left:3px solid var(--accent)}
.toast.bad{border-left:3px solid var(--red)}
.toast b{display:block;font-size:11px;letter-spacing:.08em;text-transform:uppercase;margin-bottom:2px}
.toast.ok b{color:var(--accent)}
.toast.bad b{color:var(--red)}
.toast .x{flex:0 0 auto;background:none;border:0;color:var(--ink-3);cursor:pointer;
  font-size:15px;line-height:1;padding:2px 4px;border-radius:5px;min-width:24px;min-height:24px}
.toast .x:hover{color:var(--ink);background:var(--surface-2)}
@media(max-width:760px){
  /* Above the thumb, not under it, and full width so it is readable at arm's
     length while she is holding a phone in one hand. */
  .toasts{left:12px;right:12px;bottom:12px;max-width:none}
}

/* ---- empty states that do something ------------------------------------
   A message saying there is nothing here is a dead end. The thing that would
   fix it belongs in the same box. */
.empty .btn{margin-top:13px}
.empty p{margin:0 0 2px}

/* ---- a figure against the one before it ---------------------------------
   A number on its own is not information. K963 is good or bad depending
   entirely on what last month was. */
.stat .delta{display:inline-flex;align-items:center;gap:4px;font-size:11.5px;font-weight:600;
  margin-top:3px;font-family:var(--mono)}
.stat .delta.up{color:var(--accent)}
.stat .delta.down{color:var(--red)}
.stat .delta.flat{color:var(--ink-3)}
.stat .delta span{font-weight:400;color:var(--ink-3);font-family:var(--sans)}

/* ---- skeletons ----------------------------------------------------------
   Shown while results are on their way. The point is that the page keeps its
   shape: rows appear where rows were, so nothing jumps when they land. */
.skel{background:linear-gradient(90deg,var(--rule-2) 25%,var(--rule) 50%,var(--rule-2) 75%);
  background-size:200% 100%;animation:shimmer 1.3s linear infinite;border-radius:6px}
@keyframes shimmer{from{background-position:200% 0}to{background-position:-200% 0}}
.skelrow{display:flex;align-items:center;gap:11px;padding:11px 4px;border-bottom:1px solid var(--rule-2)}
.skelrow .skel.av{width:34px;height:34px;border-radius:50%;flex:0 0 auto}
.skelrow .skel.l1{height:11px;width:44%}
.skelrow .skel.l2{height:9px;width:26%;margin-top:5px}

/* ---- confirming a destructive act in place ------------------------------
   `confirm()` is a dialog the browser draws over the page, it cannot say
   which row it means, and it is the same shape as a cookie banner. This asks
   in the place the thing lives: the button becomes the question. */
.confirmwrap{display:inline-flex;align-items:center;gap:7px;flex-wrap:wrap}
.confirmwrap .ask{font-size:12.5px;color:var(--ink-2)}
.confirmwrap .ask b{color:var(--ink);font-weight:600}

/* ---- the mobile top bar -------------------------------------------------
   Hidden entirely on a desk, where the rail is always there. */
.topbar{display:none;position:fixed;top:0;left:0;right:0;height:52px;z-index:40;
  align-items:center;gap:10px;padding:0 12px;
  background:var(--surface);border-bottom:1px solid var(--rule)}
.topbar .burger{display:grid;place-items:center;width:40px;height:40px;margin-left:-6px;
  background:none;border:0;border-radius:8px;color:var(--ink);cursor:pointer}
.topbar .burger:hover{background:var(--rule-2)}
/* Three rules drawn in CSS rather than an icon font, so the bar costs no
   request and cannot render as a missing glyph on a slow connection. */
.topbar .burger i{position:relative;display:block;width:17px;height:1.8px;
  background:currentColor;border-radius:2px}
.topbar .burger i::before,.topbar .burger i::after{content:"";position:absolute;left:0;
  width:17px;height:1.8px;background:currentColor;border-radius:2px}
.topbar .burger i::before{top:-5.5px}
.topbar .burger i::after{top:5.5px}
.topbar .tbrand{display:flex;align-items:center;gap:8px;text-decoration:none;color:inherit;font-size:14px;font-weight:600}
.topbar .tbrand .mark{width:26px;height:26px;border-radius:7px;font-size:12px}
/* The section a nav list is divided into. Same micro-label as everywhere. */
.navgroup{padding:12px 9px 4px}
/* This has to sit after the `display:none` above rather than up in the main
   phone block: same specificity, and the later rule wins. */
@media(max-width:900px){ .topbar{display:flex} }

/* The month picker in the page header keeps its natural width instead of
   stretching to whatever the header has spare. */
.monthpick{width:170px;flex:0 0 auto}
.monthpick .f{margin-bottom:0}

.filters{margin-bottom:20px}
.filters>h2 .filters-clear{font-size:11.5px;font-weight:500;color:var(--ink-3);text-decoration:none}
.filters>h2 .filters-clear:hover{color:var(--red);text-decoration:underline}
.filters .pad{padding-bottom:4px}

/* From, To, then the buttons. */
.filterrow{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr) auto;
  gap:0 13px;align-items:end}
.filterrow .f{margin-bottom:11px}
.filteract{display:flex;gap:7px;margin-bottom:11px}
.filteract .btn{min-height:44px}

/* The quick strip. `.lbl` is the same uppercase micro-label used on every
   stat tile, so this reads as part of the system rather than a control panel
   bolted onto it. */
.quickbar{display:flex;flex-wrap:wrap;align-items:center;gap:7px;
  padding:10px 15px;background:var(--surface-2);border-top:1px solid var(--rule-2);
  border-radius:0 0 var(--r) var(--r)}
.quickbar .lbl{margin-right:2px}
.quick{display:inline-flex;align-items:center;min-height:32px;padding:5px 11px;
  border:1px solid var(--rule);border-radius:7px;background:var(--surface);
  color:var(--ink-2);text-decoration:none;font-size:12.5px;white-space:nowrap}
.quick:hover{border-color:var(--accent);color:var(--accent)}
/* The applied range is filled rather than outlined: at a glance she should be
   able to tell which question the figures below are answering. */
.quick.on{background:var(--accent);border-color:var(--accent);color:var(--accent-ink);font-weight:600}
.quick.on:hover{color:var(--accent-ink)}

@media(max-width:760px){
  /* Buttons go full width under the dates rather than squeezing beside them. */
  .filterrow{grid-template-columns:1fr 1fr}
  .filteract{grid-column:1 / -1}
  .filteract .btn{flex:1;justify-content:center}
  /* The quick strip scrolls on its own instead of wrapping into three ragged
     lines and pushing the figures off the first screen. */
  .quickbar{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch}
}


/* The one dialog in the app. Native `<dialog>`, so focus trapping, Escape and
   the backdrop are the browser's job rather than ours.

   Capped at 85dvh with the body scrolling inside: a dialog taller than the
   visible viewport is how a form becomes unsubmittable on a phone once the
   keyboard is up. */
dialog{
  border:1px solid var(--rule); border-radius:var(--r); background:var(--surface);
  color:var(--ink); padding:0; width:min(420px,calc(100vw - 32px));
  max-height:85dvh; overflow:auto; box-shadow:var(--shadow);
}
dialog::backdrop{ background:rgb(0 0 0 / .45); }
dialog h2{ font-size:16px; }


/* Where a patient stands with the desk, on the clinical record. A line, not a
   card: the clinician needs it in view and must not read it as a gate. */
.paystate{display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  padding:9px 13px;background:var(--surface-2);border:1px solid var(--rule);border-radius:var(--r)}
.paystate .muted{font-size:12.5px}


/* The number a patient is called by. Big enough to read across a waiting room
   from a printed slip, and monospaced so 6 and 8 are never argued about. */
.qno{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:30px;height:30px;padding:0 7px;border-radius:8px;
  background:var(--accent-soft);color:var(--accent);
  font-family:var(--mono);font-size:14px;font-weight:700;font-variant-numeric:tabular-nums;
}


/* The claim-sheet preview: a spreadsheet, shown as one. Monospaced and tight,
   because it is being read against a printed form held next to the screen. */
.sheet{font-family:var(--mono);font-size:11.5px;border-collapse:collapse;width:auto;min-width:100%}
.sheet td{border:1px solid var(--rule-2);padding:3px 7px;white-space:nowrap}
.sheet tr:first-child td,.sheet tr td:only-child{font-weight:600}
