/* RemindCare — THPS palette.
   Carried over from the approved prototype so the Laravel build looks
   identical to what was signed off. Navy #283372 is sampled from the
   THPS logo; the surface is a faint blue.
   Status colours (green / red / grey / purple) are functional, not
   decorative - they carry the meaning staff already know from the
   paper register, so they are not restyled. */
:root{
  /* THIPS brand navy + faint blue as the dominant surface colour */
  --navy:#283372; --navy-d:#1a2250; --navy-l:#e9edf8;
  --sky:#c3d6f0; --sky-2:#dbe7f8; --faint:#eef4fc; --faint-2:#e2ecf9;
  --green:#1f6f43; --green-d:#0d3b23; --green-l:#e6f4ea;
  --red:#b3261e; --red-l:#fdecea;
  --grey:#5f6368; --grey-l:#eceff1;
  --lock:#6a4c93; --lock-l:#f0eaf8;
  --amber:#a8631d; --amber-l:#fbf0e4;
  --blue:#3a56a8; --blue-l:#e4ebfa;
  --ink:#1b2033; --muted:#5c6785; --line:#c9d8ee; --bg:#eef4fc; --card:#ffffff;

  /* Navy is used two ways: as a filled background carrying white text, and as
     text sitting on a card. Those need to move in opposite directions in a
     dark theme, so they are separate tokens even though they match here. */
  --accent-ink:#283372;
  --on-accent:#ffffff;
  --shadow:rgba(40,51,114,.16);
}

/* --------------------------------------------------------------- dark ---
   Every token above is redefined below -- none is left to fall through to a
   light value, which is how a dark theme ends up with white text on white.

   Two selectors, deliberately. The media query serves whoever has never
   touched the toggle and whose system asks for dark; it is guarded so that
   choosing light explicitly still wins over a dark operating system. The
   attribute selector serves the toggle itself, in both directions. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --navy:#5468c4; --navy-d:#43549f; --navy-l:#232b47;
    --sky:#33406b; --sky-2:#2a3559; --faint:#1c2236; --faint-2:#232b42;
    --green:#4caf7d; --green-d:#8fd6ae; --green-l:#17301f;
    --red:#ef6b62; --red-l:#331a19;
    --grey:#9aa3b8; --grey-l:#262b38;
    --lock:#a98ad6; --lock-l:#241f33;
    --amber:#d99a4e; --amber-l:#31261a;
    --blue:#8ea6f0; --blue-l:#1e2740;
    --ink:#e6eaf5; --muted:#9aa5c4; --line:#2e3956; --bg:#10141f; --card:#171d2e;
    --accent-ink:#9fb0f5;
    --on-accent:#ffffff;
    --shadow:rgba(0,0,0,.45);
  }
}

:root[data-theme="dark"] {
  --navy:#5468c4; --navy-d:#43549f; --navy-l:#232b47;
  --sky:#33406b; --sky-2:#2a3559; --faint:#1c2236; --faint-2:#232b42;
  --green:#4caf7d; --green-d:#8fd6ae; --green-l:#17301f;
  --red:#ef6b62; --red-l:#331a19;
  --grey:#9aa3b8; --grey-l:#262b38;
  --lock:#a98ad6; --lock-l:#241f33;
  --amber:#d99a4e; --amber-l:#31261a;
  --blue:#8ea6f0; --blue-l:#1e2740;
  --ink:#e6eaf5; --muted:#9aa5c4; --line:#2e3956; --bg:#10141f; --card:#171d2e;
  --accent-ink:#9fb0f5;
  --on-accent:#ffffff;
  --shadow:rgba(0,0,0,.45);
}
*{box-sizing:border-box}
body{margin:0;font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;color:var(--ink);background:var(--bg)}
button{font:inherit;cursor:pointer}
input,select,textarea{font:inherit}
a{color:var(--blue)}

/* ---------- Logo ---------- */
.logo{display:block;height:auto}
.logo-login{width:190px;margin-bottom:18px}
.logo-bar{height:26px;width:auto}

/* ---------- Login ---------- */
#login{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;
  background:linear-gradient(135deg,var(--sky-2) 0%,var(--sky) 45%,var(--faint-2) 100%);z-index:100}
#login:before{content:"";position:absolute;inset:0;
  background:radial-gradient(circle at 18% 22%,rgba(255,255,255,.85),transparent 42%),
             radial-gradient(circle at 82% 78%,rgba(40,51,114,.10),transparent 46%)}
.loginbox{position:relative;background:var(--card);border-radius:16px;padding:34px;width:410px;
  box-shadow:0 22px 60px rgba(26,34,80,.25);border:1px solid var(--sky)}
.login-head{text-align:center;margin-bottom:22px}
.login-head .logo-login{margin:0 auto 14px;display:block}
.loginbox h1{margin:0 0 4px;font-size:26px;color:var(--navy);text-align:center;letter-spacing:.02em}
.loginbox .sub{color:var(--muted);font-size:12.5px;text-align:center;line-height:1.5}
.login-ctx{background:var(--faint);border:1px solid var(--sky);border-radius:8px;padding:10px 12px;
  font-size:12.5px;color:var(--navy-d);text-align:center;margin-bottom:4px}
.login-ctx b{display:block;font-size:13.5px}
.login-err{background:var(--red-l);border:1px solid var(--red);color:var(--red);border-radius:7px;
  padding:9px 11px;font-size:12.5px;margin-top:14px}
.login-info{background:var(--amber-l);border:1px solid var(--amber);color:var(--amber);border-radius:7px;
  padding:9px 11px;font-size:12.5px;margin-bottom:4px}

/* ---------- Idle warning ---------- */
.idle-scrim{position:fixed;inset:0;background:rgba(26,34,80,.55);z-index:300;display:none;
  align-items:center;justify-content:center;padding:16px}
.idle-scrim.on{display:flex}
.idle-box{background:var(--card);border-radius:14px;padding:26px;max-width:420px;width:100%;
  box-shadow:0 20px 60px rgba(26,34,80,.35);border:1px solid var(--sky);text-align:center}
.idle-box h3{margin:0 0 8px;color:var(--navy-d);font-size:18px}
.idle-box p{margin:0 0 6px;font-size:13.5px;color:var(--ink)}
.idle-count{font-size:40px;font-weight:700;color:var(--red);margin:10px 0;line-height:1}
.idle-box .btns{display:flex;gap:10px;justify-content:center;margin-top:16px;flex-wrap:wrap}

/* ---------- Confirm dialog ----------
   Replaces window.confirm(): once the user ticks the browser's
   "don't let this page prompt you again" box, confirm() returns false for
   ever and the button it guarded stops submitting with nothing on screen to
   say why. This one is ours and cannot be suppressed. */
.rc-confirm-scrim{position:fixed;inset:0;background:rgba(26,34,80,.55);z-index:320;display:none;
  align-items:center;justify-content:center;padding:16px}
.rc-confirm-scrim.on{display:flex}
.rc-confirm-box{background:var(--card);border-radius:14px;padding:24px;max-width:420px;width:100%;
  box-shadow:0 20px 60px rgba(26,34,80,.35);border:1px solid var(--sky)}
.rc-confirm-box p{margin:0 0 18px;font-size:14px;color:var(--ink);line-height:1.5}
.rc-confirm-box .btns{display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap}
.loginbox label{display:block;font-size:12px;font-weight:600;color:var(--muted);margin:14px 0 5px;text-transform:uppercase;letter-spacing:.04em}
.loginbox select,.loginbox input{width:100%;padding:10px;border:1px solid var(--line);border-radius:7px;background:var(--card);color:var(--ink)}
.loginbox select:focus,.loginbox input:focus{outline:2px solid var(--sky);border-color:var(--navy)}
/* Anything drawn as a control must not be underlined. Most of these are
   <a>, which underlines its label by default, so the same control looked
   different depending only on which element a view happened to use. */
.btn,.tab,.pill,.chip,.pg,.tile{text-decoration:none}
.btn:hover,.tab:hover,.pill:hover,.pg:hover{text-decoration:none}

.btn{background:var(--navy);color:var(--on-accent);border:0;border-radius:7px;padding:10px 16px;font-weight:600;
  text-decoration:none;display:inline-block;text-align:center}
.btn:hover{background:var(--navy-d)}
.btn.full{width:100%;margin-top:20px;padding:12px}
.btn.ghost{background:var(--card);color:var(--accent-ink);border:1px solid var(--line);font-weight:500}
.btn.ghost:hover{background:var(--faint-2);border-color:var(--navy)}
.btn.sm{padding:6px 11px;font-size:13px}
/* A quick range that IS the current range. Filled rather than outlined, so the
   row of them reads as "you are here" and not as seven equal offers. */
.btn.ghost.on,.btn.ghost.on:hover{background:var(--navy);color:var(--on-accent);border-color:var(--navy);font-weight:600}
/* A role that may not record sees the action greyed in place, not a 403 after the click. */
.btn.disabled,.btn.disabled:hover{background:var(--faint-2);color:var(--muted);border:1px solid var(--line);
  font-weight:500;cursor:not-allowed;display:inline-block}
.demo-note{margin-top:16px;font-size:11.5px;color:var(--navy-d);background:var(--faint);border:1px solid var(--sky);padding:10px 12px;border-radius:8px}

/* ---------- Shell ---------- */
#app{display:none;min-height:100vh}
.topbar{background:linear-gradient(180deg,var(--sky-2),var(--sky));color:var(--accent-ink);padding:0 18px;height:60px;
  display:flex;align-items:center;gap:14px;position:sticky;top:0;z-index:40;border-bottom:1px solid var(--sky)}
.brand{font-weight:700;letter-spacing:.02em;display:flex;align-items:center;gap:12px}
.brand .sys{font-size:14px;color:var(--navy);border-left:1px solid rgba(40,51,114,.28);padding-left:12px}
.brand small{font-weight:400;opacity:.8;margin-left:8px;font-size:11.5px}
.topbar .spacer{flex:1}
.pill{background:rgba(255,255,255,.72);border:1px solid rgba(40,51,114,.20);color:var(--navy-d);border-radius:20px;padding:5px 12px;font-size:12.5px}
.pill.act{cursor:pointer;text-decoration:none}
.pill.act:hover{background:var(--card);border-color:var(--navy)}
.pill.green{background:var(--green-l);border-color:var(--green);color:var(--green)}
.pill.green:hover{background:var(--green-l);border-color:var(--green-d)}
.pill.warn{background:var(--amber-l);border-color:var(--amber);color:var(--amber)}
.pill.warn:hover{background:var(--amber-l);border-color:var(--amber)}
.pill.red{background:var(--red-l);border-color:var(--red);color:var(--red)}
.pill.red:hover{background:var(--red-l);border-color:var(--red)}
.layout{display:flex;align-items:flex-start}
.side{width:216px;background:var(--card);border-right:1px solid var(--line);height:calc(100vh - 60px);overflow-y:auto;padding:12px 0;position:sticky;top:60px;flex:none}
.side a{display:flex;align-items:center;gap:10px;padding:10px 18px;color:var(--ink);text-decoration:none;font-size:13.5px;border-left:3px solid transparent}
.side a:hover{background:var(--faint)}
.side a.on{background:var(--faint-2);border-left-color:var(--navy);font-weight:600;color:var(--navy)}
.side a .ico{width:20px;text-align:center;flex:none;font-size:15px}

/* ---------- Collapsible rail ---------- */
.side{transition:width .18s ease}
.side.collapsed{width:60px}
.side.collapsed a{justify-content:center;padding:13px 0;gap:0;border-left-width:0;border-right:3px solid transparent}
.side.collapsed a.on{border-right-color:var(--navy)}
.side.collapsed a .lbl{display:none}
.side.collapsed .grp{font-size:0;height:0;padding:0;margin:8px 12px;border-top:1px solid var(--sky)}
.navcollapse{display:flex;align-items:center;gap:10px;width:100%;background:none;border:0;
  border-top:1px solid var(--line);margin-top:10px;padding:12px 18px;color:var(--muted);
  font-size:12.5px;text-align:left}
.navcollapse:hover{background:var(--faint);color:var(--navy)}
.side.collapsed .navcollapse{justify-content:center;padding:12px 0}
.side.collapsed .navcollapse .lbl{display:none}

/* Release badge, pinned under the collapse button. Quiet on purpose: it is
   reference information somebody looks FOR, not something to read every day. */
.navversion{padding:10px 18px 14px;color:var(--muted);font-size:11.5px;line-height:1.45;
  border-top:1px solid var(--line);margin-top:2px}
.navversion .lbl{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 7px}
.navversion-kind{text-transform:uppercase;letter-spacing:.07em;font-weight:700;font-size:10px}
.navversion-num{font-size:11.5px;color:var(--navy)}
/* A version gap is the explanation for a whole class of "central is missing my
   figures" reports, so it is tinted rather than left as more grey text. */
.navversion-gap{font-size:10.5px;color:var(--amber)}
.navversion-short{display:none}
.side.collapsed .navversion{text-align:center;padding:10px 0 12px}
.side.collapsed .navversion .lbl{display:none}
.side.collapsed .navversion-short{display:block;font-size:10px}
@media(max-width:860px){
  /* off-canvas on small screens — collapsing is a desktop idea, so neutralise it */
  .side.collapsed{width:250px}
  .side.collapsed a{justify-content:flex-start;padding:14px 20px;gap:10px;border-left-width:3px;border-right:0}
  .side.collapsed a .lbl{display:inline}
  .side.collapsed .grp{font-size:10.5px;height:auto;padding:14px 18px 6px;margin:0;border-top:0}
  .navcollapse{display:none}
}
.side .grp{font-size:10.5px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);padding:14px 18px 6px;font-weight:700}
.main{flex:1;padding:22px 26px;max-width:1500px}
h2.page{margin:0 0 3px;font-size:21px;color:var(--navy-d)}
.page-sub{color:var(--muted);font-size:13px;margin-bottom:18px}

/* ---------- Cards / tiles ---------- */
.card{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:16px 18px;margin-bottom:16px;
  box-shadow:0 1px 3px rgba(40,51,114,.06)}
.card h3{margin:0 0 12px;font-size:15px;color:var(--navy-d)}
.card h3 .hint{font-weight:400;color:var(--muted);font-size:12px;margin-left:8px}
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:14px;margin-bottom:16px}
/* Centred: the figure is the point of these cards, and a number sitting hard
   against the left edge under a label of a different length reads as ragged
   rather than as a set. */
.tile{text-align:center;background:var(--card);border:1px solid var(--line);border-radius:10px;padding:15px 17px;cursor:pointer;transition:.12s;
  box-shadow:0 1px 3px rgba(40,51,114,.06)}
.tile:hover{box-shadow:0 4px 14px var(--shadow);transform:translateY(-1px)}
.tile .k{font-size:11.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:700}
.tile .v{font-size:31px;font-weight:700;line-height:1.15;margin-top:6px}
.tile .n{font-size:11.5px;color:var(--muted)}
/* The tone classes are kept because the views set them, but they no longer
   paint anything: the figure reads as a figure and the card as a card. The
   label already says whether a number is good or bad. */
.tile.g,.tile.r,.tile.y,.tile.b,.tile.l{border-left:1px solid var(--line)}
.tile.g .v,.tile.r .v,.tile.y .v,.tile.b .v,.tile.l .v{color:var(--ink)}

.tile.visit{background:color-mix(in srgb, var(--blue-l) 25%, transparent)}

/* ---------- Compact stat row (.cards > .card.stat) ----------
   The register screens mark up a summary band as `.cards` holding `.card.stat`.
   Neither selector existed, so each one fell through to the plain `.card` rule:
   full width, 16px of padding and a 16px bottom margin, stacking five headline
   figures down the page and pushing the register itself below the fold.

   Deliberately NOT merged into `.tiles`. These sit directly above a table and
   are read as its caption, so they are smaller and quieter than a dashboard
   tile — a summary of what is below, not the point of the page. Same grid
   though, so the two never look like different systems. */
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:10px;margin-bottom:16px}
.cards .card.stat{margin:0;padding:10px 12px;text-align:center}
.card.stat .k{font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);
  font-weight:700;line-height:1.3}
.card.stat .n{font-size:22px;font-weight:700;line-height:1.2;margin-top:3px;color:var(--ink)}
/* Scoped to .card.stat, not to a bare .hint: `.hint` is used all over the
   application at 12px and shrinking it globally would touch every screen. */
.card.stat .hint{font-size:10.5px;color:var(--muted);line-height:1.35;
  overflow-wrap:anywhere}

/* ---------- Tables ---------- */
table{width:100%;border-collapse:collapse;font-size:13px}
th{text-align:left;padding:9px 10px;background:var(--faint);border-bottom:2px solid var(--sky);font-size:11.5px;text-transform:uppercase;letter-spacing:.04em;color:var(--navy);white-space:nowrap}
td{padding:9px 10px;border-bottom:1px solid var(--line);vertical-align:middle}
tr.clickable:hover{background:var(--faint-2);cursor:pointer}
.tbl-wrap{overflow-x:auto}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12.5px;white-space:nowrap}

/* ---------- Status chips ---------- */
.chip{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:20px;font-size:11.5px;font-weight:600;white-space:nowrap}
.chip.green{background:var(--green-l);color:var(--green-d);border:1px solid var(--green)}
.chip.red{background:var(--red-l);color:var(--red);border:1px solid var(--red)}
.chip.grey{background:var(--grey-l);color:var(--grey);border:1px solid var(--grey)}
.chip.blue{background:var(--blue-l);color:var(--blue);border:1px solid var(--blue)}
.chip.amber{background:var(--amber-l);color:var(--amber);border:1px solid var(--amber)}
.chip.lock{background:var(--lock-l);color:var(--lock);border:1px solid var(--lock)}
.chip .ic{font-weight:900;font-size:12px}
.bar.l{background:var(--lock)}
tr.locked-row{background:var(--lock-l)}

/* ---------- Controls ---------- */
.toolbar{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end;margin-bottom:14px}
.field{display:flex;flex-direction:column;gap:4px}
.field label{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
.field input,.field select{padding:7px 9px;border:1px solid var(--line);border-radius:6px;background:var(--card);color:var(--ink);min-width:150px}

/* ---- outcome entry: the rows the user has to act on --------------------
   The form mixes read-only facts (.locked, dashed) with fields to fill.
   .field--do marks a row that needs an answer: a navy rule down the left
   edge, an ink-coloured label instead of muted grey, and a thicker input
   border with a clear focus ring. A caller scanning the form then sees at
   a glance which rows are theirs. */
.field--do{border-left:3px solid var(--navy);padding-left:12px;margin-left:-15px}
.field--do > label{color:var(--ink);font-size:12px}
.field--do input,.field--do select,.field--do textarea{border-color:var(--blue);border-width:1.5px}
.field--do input:focus,.field--do select:focus,.field--do textarea:focus{
  border-color:var(--navy);outline:2px solid var(--sky);outline-offset:1px}

/* A conditional field that has just appeared because of the chosen method
   or outcome. Tinted and boxed so it reads as "and now this one too",
   with a one-shot flash the moment JS reveals it. */
.field--reveal{background:var(--blue-l);border:1px solid var(--blue);border-left:3px solid var(--navy);
  border-radius:8px;padding:12px 13px;margin-left:0}
.field--reveal.flash{animation:fieldflash 1.2s ease-out}
@keyframes fieldflash{from{background:var(--sky)}to{background:var(--blue-l)}}
.tabs{display:flex;gap:6px;margin-bottom:14px;flex-wrap:wrap}
.tab{padding:8px 14px;border:1px solid var(--line);background:var(--card);border-radius:7px;font-size:13px;position:relative;color:var(--accent-ink)}
.tab:hover{background:var(--faint-2)}
.tab.on{background:var(--navy);color:var(--on-accent);border-color:var(--navy);font-weight:600}
.tab .cnt{display:inline-block;margin-left:7px;background:var(--faint-2);border-radius:10px;padding:0 7px;font-size:11px}
.tab.on .cnt{background:rgba(255,255,255,.26)}

/* ---------- Bars ---------- */
.bar-row{display:grid;grid-template-columns:230px 1fr 62px;gap:10px;align-items:center;margin-bottom:6px;font-size:12.5px}
.bar{height:16px;background:var(--navy);border-radius:3px;min-width:2px}
.bar.g{background:var(--green)} .bar.r{background:var(--red)} .bar.y{background:var(--grey)}
.stack{display:flex;height:22px;border-radius:4px;overflow:hidden;border:1px solid var(--line)}
.stack div{display:flex;align-items:center;justify-content:center;color:var(--on-accent);font-size:11px;font-weight:600}

/* ---------- Drawer ---------- */
.scrim{position:fixed;inset:0;background:rgba(0,0,0,.42);display:none;z-index:60}
.scrim.on{display:block}
.drawer{position:fixed;top:0;right:0;height:100%;width:460px;max-width:94vw;background:var(--card);box-shadow:-6px 0 30px rgba(0,0,0,.22);
  transform:translateX(100%);transition:.22s;z-index:70;display:flex;flex-direction:column}
.drawer.on{transform:translateX(0)}
.drawer header{padding:16px 20px;border-bottom:1px solid var(--sky);display:flex;align-items:center;gap:10px;background:var(--faint)}
.drawer header h3{margin:0;font-size:16px;flex:1;color:var(--navy-d)}
.drawer .body{padding:18px 20px;overflow:auto;flex:1}
.drawer footer{padding:14px 20px;border-top:1px solid var(--sky);display:flex;gap:10px;justify-content:flex-end;background:var(--faint)}
.x{background:none;border:0;font-size:22px;line-height:1;color:var(--muted)}
.kv{display:grid;grid-template-columns:135px 1fr;gap:6px 12px;font-size:13px;margin-bottom:16px}
.kv .k{color:var(--muted)}
.locked{background:var(--faint);border:1px dashed var(--sky);border-radius:6px;padding:8px 10px;font-size:12.5px;color:var(--navy)}
.dropzone{border:2px dashed var(--sky);border-radius:12px;padding:26px;text-align:center;background:linear-gradient(180deg,var(--card),var(--faint));transition:.15s}
.dropzone.hot{border-color:var(--navy);background:var(--faint-2)}
.dropzone input[type=file]{display:none}

/* ---------- Choosing the CTC2 database ----------
   The .mdb sits on this workstation and is read where it lies, so what the
   import offers is a list of the databases found on the machine rather than an
   upload. Each row has to show enough to pick between two copies of the same
   file: where it is, how big, and when it was last written. */
.mdb-list{display:flex;flex-direction:column;gap:6px;margin-bottom:4px}
.mdb-row{display:grid;grid-template-columns:auto 1fr auto;gap:2px 10px;align-items:baseline;
  border:1px solid var(--line);border-radius:8px;padding:9px 11px;background:var(--card);cursor:pointer;transition:.12s}
.mdb-row:hover{border-color:var(--sky);background:var(--faint)}
/* The radio must keep its own size: `.field input` sets a padding and a
   min-width for text boxes, and inherited by a radio it becomes a grey slab. */
.field .mdb-row input[type=radio]{padding:0;min-width:0;margin:0;align-self:center}
.mdb-row:has(input:checked){border-color:var(--navy);background:var(--faint-2)}
.mdb-name{font-weight:700;color:var(--navy);font-size:13px}
.mdb-meta{color:var(--muted);font-size:11.5px;white-space:nowrap}
.mdb-path{grid-column:2/4;color:var(--muted);font-size:11.5px;word-break:break-all}

/* ---------- Import progress ----------
   Named apart from the report .bar so the two cannot drift into each other:
   that one draws a finished measurement, this one draws work still running. */
.imp-prog{margin-top:14px;padding:14px 16px;border:1px solid var(--line);border-radius:10px;background:var(--faint)}
.imp-prog-head{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin-bottom:8px}
.imp-prog-label{font-size:13px;font-weight:700;color:var(--navy)}
.imp-prog-pct{font-size:13px;font-weight:700;color:var(--navy);font-variant-numeric:tabular-nums}
.imp-prog-track{height:10px;border-radius:5px;background:var(--sky-2);overflow:hidden}
.imp-prog-fill{height:100%;width:0;border-radius:5px;background:var(--navy);transition:width .3s ease}
.imp-prog-note{margin-top:7px;font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums;min-height:18px}

/* A phase the server cannot measure — reading a CTC2 Access database gives no
   row count until rows start arriving, which on a full clinic file is minutes
   in. Motion has to say "working" without a percentage claiming to know.

   It used to say it by animating stripes across the FILL, which is invisible:
   during an unmeasurable phase the fill sits at the floor of its band, which
   for the first phase is a width of zero. A striped animation on a zero-width
   element is a blank bar, and a blank bar that never moves for nine minutes
   reads as a frozen page — the exact thing this panel exists to prevent.

   So an unmeasurable phase now runs a segment BACK AND FORTH ACROSS THE TRACK.
   The width is set here and JS leaves the inline width alone while busy, or the
   two fight over the same property and the inline one wins. */
.imp-prog.busy .imp-prog-fill{
  width:38%;
  background-image:linear-gradient(115deg,rgba(255,255,255,.42) 25%,transparent 25%,transparent 50%,
    rgba(255,255,255,.42) 50%,rgba(255,255,255,.42) 75%,transparent 75%);
  background-size:22px 22px;
  transition:none;
  animation:imp-prog-stripe .8s linear infinite, imp-prog-sweep 2.1s ease-in-out infinite}
@keyframes imp-prog-stripe{from{background-position:0 0}to{background-position:22px 0}}
@keyframes imp-prog-sweep{
  0%{transform:translateX(-105%)}
  50%{transform:translateX(268%)}
  100%{transform:translateX(-105%)}}

.imp-prog.done .imp-prog-fill{background:var(--green)}
.imp-prog.done .imp-prog-label,.imp-prog.done .imp-prog-pct{color:var(--green)}
.imp-prog.failed .imp-prog-fill{background:var(--red)}
.imp-prog.failed .imp-prog-label,.imp-prog.failed .imp-prog-pct{color:var(--red)}

@media (prefers-reduced-motion:reduce){
  .imp-prog-fill{transition:none}
  /* No sweep, but the bar must still not be a blank nothing — hold the segment
     still in the middle of the track and let the elapsed clock carry the news
     that something is happening. */
  .imp-prog.busy .imp-prog-fill{animation:none;transform:translateX(80%)}
}
/* ---------- Return to care (inline row disclosure) ---------- */
.rtc{margin-top:5px}
.rtc>summary{list-style:none;cursor:pointer;display:inline-block;white-space:nowrap}
.rtc>summary::-webkit-details-marker{display:none}
.rtc[open]>summary{background:var(--faint-2);border-color:var(--navy)}
.rtc form{margin-top:7px;padding:9px;border:1px solid var(--line);border-radius:8px;background:var(--faint);
  display:flex;flex-direction:column;gap:6px;min-width:172px}
.rtc form label{font-size:10.5px;font-weight:700;text-transform:uppercase;color:var(--muted)}
.rtc form input{padding:6px 8px;font-size:12.5px}

/* ---------- Pager ---------- */
.pager{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.pager-count{font-size:12px;color:var(--muted)}
.pager-links{display:flex;gap:4px;flex-wrap:wrap}
.pager-links .pg{display:inline-flex;align-items:center;justify-content:center;min-width:32px;height:32px;
  padding:0 9px;border:1px solid var(--line);border-radius:7px;background:var(--card);color:var(--accent-ink);
  font-size:12.5px;font-weight:500;text-decoration:none}
.pager-links a.pg:hover{background:var(--faint-2);border-color:var(--navy)}
.pager-links .pg.on{background:var(--navy);border-color:var(--navy);color:var(--on-accent);font-weight:600}
.pager-links .pg.disabled{color:var(--muted);background:var(--faint-2);cursor:not-allowed}
.pager-links .pg.gap{border:0;background:none;min-width:16px;padding:0}

.req{display:inline-block;background:var(--red-l);color:var(--red);border:1px solid var(--red);
  border-radius:4px;font-size:9px;font-weight:800;line-height:1.4;padding:1px 5px;
  letter-spacing:.05em;text-transform:uppercase;vertical-align:1px}
.hist{border-left:3px solid var(--line);padding-left:12px;margin-top:6px}
.hist div{font-size:12px;color:var(--muted);margin-bottom:5px}

/* ---------- Misc ---------- */
.note{background:var(--faint);border:1px solid var(--sky);border-radius:8px;padding:11px 13px;font-size:12.5px;margin-bottom:14px;color:var(--navy-d)}
.note.warn{background:var(--amber-l);border-color:var(--amber);color:var(--amber)}
.note.priv{background:var(--green-l);border-color:var(--green);color:var(--green-d)}
.note b{display:block;margin-bottom:2px}
.empty{text-align:center;color:var(--muted);padding:34px;font-size:13px}
.legend{display:flex;gap:16px;flex-wrap:wrap;font-size:12px;color:var(--muted);margin-top:10px}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
@media(max-width:1080px){.grid2{grid-template-columns:1fr}}

/* ---------- Mobile navigation ---------- */
#navToggle{display:none;background:rgba(255,255,255,.7);border:1px solid rgba(40,51,114,.2);
  color:var(--navy);border-radius:8px;width:40px;height:40px;font-size:19px;line-height:1;flex:none}
.navscrim{position:fixed;inset:0;background:rgba(26,34,80,.45);z-index:44;display:none}
.navscrim.on{display:block}

/* ============ RESPONSIVE ============ */
@media(max-width:1024px){
  .main{padding:18px 16px}
  .tiles{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:11px}
  .bar-row{grid-template-columns:150px 1fr 48px}
  /* Below this the sidebar still takes its 236px and the band has under 800px
     to work with, where six cards wrap to an uneven 4+2. Three across is a
     deliberate choice rather than whatever auto-fit lands on: two even rows
     read as a set, a widow does not. */
  .cards{grid-template-columns:repeat(3,1fr)}
}
@media(max-width:860px){
  #navToggle{display:flex;align-items:center;justify-content:center}
  .side{position:fixed;top:0;left:0;height:100vh;overflow-y:auto;z-index:45;transform:translateX(-100%);
        transition:transform .22s;box-shadow:6px 0 26px rgba(26,34,80,.22);padding-top:16px;width:250px}
  .side.open{transform:translateX(0)}
  .side a{padding:14px 20px;font-size:15px}          /* larger touch targets */
  .main{padding:14px 12px;width:100%}
  .topbar{height:56px;padding:0 10px;gap:8px}
  .brand .sys{display:none}
  .logo-bar{height:22px}
  .pill{padding:6px 10px;font-size:12px}
  .hide-md{display:none!important}
  .tiles{grid-template-columns:1fr 1fr;gap:10px}
  .tile{padding:12px 13px}
  .tile .v{font-size:26px}
  /* Three across is still legible on a phone at this size; auto-fit would give
     one per row and undo the point of the band. */
  .cards{grid-template-columns:repeat(3,1fr);gap:8px}
  .cards .card.stat{padding:8px 6px}
  .card.stat .n{font-size:18px}
  .drawer{width:100%;max-width:100%}
  .toolbar{gap:8px}
  .field input,.field select{min-width:0;width:100%;padding:10px}
  .field{flex:1 1 46%}
  .kv{grid-template-columns:1fr;gap:2px 0}
  .kv .k{margin-top:8px;font-size:11px;text-transform:uppercase;letter-spacing:.04em}
  h2.page{font-size:18px}
  .bar-row{grid-template-columns:120px 1fr 40px;font-size:11.5px}
}
@media(max-width:560px){
  .tiles{grid-template-columns:1fr}
  .hide-sm{display:none!important}
  .tab{padding:10px 12px;font-size:13px;flex:1 1 auto;text-align:center}
  .tabs{gap:5px}
  .card{padding:13px 12px;border-radius:9px}
  table{font-size:12.5px}
  th,td{padding:8px 7px}
  .btn{padding:11px 15px}      /* >=44px touch target */
  .btn.sm{padding:9px 12px}
  .field{flex:1 1 100%}
  .toolbar .field label{font-size:10.5px}
  .loginbox{width:100%;margin:12px;padding:24px}
  .logo-login{width:150px}
  .toast{left:12px;right:12px;transform:translateY(90px);width:auto}
  .toast.on{transform:translateY(0)}
  .drawer footer{flex-direction:column-reverse}
  .drawer footer .btn{width:100%}
}
@media(hover:none){ .tile:hover{transform:none;box-shadow:0 1px 3px rgba(40,51,114,.06)} }
.toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%) translateY(90px);background:var(--navy-d);color:var(--on-accent);
  padding:11px 20px;border-radius:8px;font-size:13.5px;z-index:200;transition:.25s;box-shadow:0 6px 24px rgba(26,34,80,.4)}
.toast.on{transform:translateX(-50%) translateY(0)}
.etr th{background:var(--faint-2);color:var(--navy);border:1px solid var(--sky);font-size:10.5px;text-align:center}
.etr td{border:1px solid var(--line);text-align:center;font-size:12px}
.etr .sw{display:block;font-style:italic;font-weight:400;text-transform:none;letter-spacing:0;opacity:.8}
.redacted{background:repeating-linear-gradient(45deg,var(--grey-l),var(--grey-l) 5px,var(--faint-2) 5px,var(--faint-2) 10px);color:var(--muted);font-size:10.5px;font-style:italic}
@media print{.side,.topbar,.toolbar,.tabs,.no-print{display:none!important}.main{padding:0}.card{border:0;padding:0}}

/* ---------- Theme toggle ---------- */
.pill.theme{min-width:34px;text-align:center;font-size:14px;line-height:1}
:root[data-theme="dark"] .pill.theme .sun,
.pill.theme .moon{display:inline}
:root[data-theme="dark"] .pill.theme .moon,
.pill.theme .sun{display:none}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pill.theme .sun{display:inline}
  :root:not([data-theme="light"]) .pill.theme .moon{display:none}
}

/* ── Charts ────────────────────────────────────────────────────────────────
   Series colours live here rather than in the SVG so that one definition
   serves both themes and a chart follows the light/dark switch with no
   re-render. The three steps were chosen by running the palette validator,
   not by eye: worst adjacent separation is dE 21.1 under protanopia in light
   mode and 22.9 in dark, against a target of 8.

   The dark steps are NOT the app's dark --blue/--amber/--lock. Those are tuned
   to carry text and small UI on a dark surface and sit above the lightness band
   a chart mark needs, which made every series read as pastel. Chart marks get
   their own three. */
:root{ --c1:#3a56a8; --c2:#a8631d; --c3:#6a4c93; }
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){ --c1:#6a83dd; --c2:#bd8235; --c3:#8e6ec4; }
}
:root[data-theme="dark"]{ --c1:#6a83dd; --c2:#bd8235; --c3:#8e6ec4; }

.chart{width:100%;height:auto;display:block;overflow:visible}
/* Recessive: the grid is a reading aid, not data. */
.chart-grid line{stroke:var(--line);stroke-width:1;opacity:.55}
.chart-axis line{stroke:var(--line);stroke-width:1}
.chart-tick{fill:var(--muted);font-size:10.5px}
.chart-name{fill:var(--ink);font-size:11px}
/* Values and labels wear text tokens, never the series colour: the mark beside
   them already carries identity, and coloured text on a card reads as a link. */
.chart-value{fill:var(--muted);font-size:10.5px;font-weight:600}
.chart-label{fill:var(--ink);font-size:11px;font-weight:700}
.chart-line{fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
/* A 2px surface ring, so overlapping markers stay countable. */
.chart-dot{stroke:var(--card);stroke-width:2}
.chart-bar{stroke:var(--card);stroke-width:1}
.chart-bar:hover{opacity:.82}
.chart-marker{stroke:var(--ink);stroke-width:1.5;stroke-dasharray:4 3;opacity:.5}

.chart-legend{display:flex;flex-wrap:wrap;gap:14px;margin:2px 0 10px}
.chart-key{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--muted)}
.chart-key i{width:11px;height:11px;border-radius:3px;display:inline-block;flex:0 0 auto}

.chart-grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:14px}
@media print{ .chart-bar,.chart-dot{stroke:none} }
