/* "Night Ward" day palette, pinned always-on (Bret's final call; app.js
   stamps data-theme="light" at boot, which outranks the OS preference). The
   dark tokens below are retained but dormant. */
:root{
  color-scheme: light;
  --surface-1:#ffffff; --page:#f2f5f9;
  --ink-1:#101b2b; --ink-2:#4c5c72; --ink-3:#68788e;
  --grid:#d9e1ec; --baseline:#b7c3d3;
  --border:rgba(16,27,43,0.12);
  --series-1:#0f8ba1; --series-2:#eb6834; --series-3:#1baf7a;
  --good:#0ca30c; --warn:#fab219; --serious:#ec835a; --critical:#d03b3b;
  --good-text:#006300;
  --chip-ok:#e3f1ea; --chip-warn:#fdf3dc; --chip-late:#fbe4e4;
  --accent:#0f8ba1; --accent-deep:#0b6c7e; --on-accent:#ffffff;
  --radius:14px;
}
@media (prefers-color-scheme: dark){
  :root:where(:not([data-theme="light"])){
    color-scheme: dark;
    --surface-1:#16202f; --page:#0e1420;
    --ink-1:#eaf1fa; --ink-2:#a7b4c8; --ink-3:#7d8ca1;
    --grid:#22304a; --baseline:#33455f;
    --border:rgba(150,190,255,0.14);
    --series-1:#4cc3d9; --series-2:#d95926; --series-3:#199e70;
    --good-text:#31d158;
    --chip-ok:#0f2418; --chip-warn:#2a2410; --chip-late:#331414;
    --accent:#4cc3d9; --accent-deep:#7ad6e6; --on-accent:#04121a;
  }
}
/* the clock's stamp always wins, both directions */
:root[data-theme="dark"]{
  color-scheme: dark;
  --surface-1:#16202f; --page:#0e1420;
  --ink-1:#eaf1fa; --ink-2:#a7b4c8; --ink-3:#7d8ca1;
  --grid:#22304a; --baseline:#33455f;
  --border:rgba(150,190,255,0.14);
  --series-1:#4cc3d9; --series-2:#d95926; --series-3:#199e70;
  --good-text:#31d158;
  --chip-ok:#0f2418; --chip-warn:#2a2410; --chip-late:#331414;
  --accent:#4cc3d9; --accent-deep:#7ad6e6; --on-accent:#04121a;
}
:root[data-theme="light"]{
  color-scheme: light;
  --surface-1:#ffffff; --page:#f2f5f9;
  --ink-1:#101b2b; --ink-2:#4c5c72; --ink-3:#68788e;
  --grid:#d9e1ec; --baseline:#b7c3d3;
  --border:rgba(16,27,43,0.12);
  --series-1:#0f8ba1; --series-2:#eb6834; --series-3:#1baf7a;
  --good-text:#006300;
  --chip-ok:#e3f1ea; --chip-warn:#fdf3dc; --chip-late:#fbe4e4;
  --accent:#0f8ba1; --accent-deep:#0b6c7e; --on-accent:#ffffff;
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
button,select,input,.code,.loc,.pinpad button{touch-action:manipulation}
.pinpad{user-select:none;-webkit-user-select:none}
html,body{height:100%}
body{
  font-family:system-ui,-apple-system,"Segoe UI",sans-serif;
  background:var(--page); color:var(--ink-1);
  overscroll-behavior:none;
}
button{font-family:inherit;border:none;background:none;color:inherit;cursor:pointer}
.app{max-width:480px;margin:0 auto;min-height:100dvh;display:flex;flex-direction:column;background:var(--page)}
.app.wide{max-width:980px}

/* ---------- shared components ---------- */
.card{background:var(--surface-1);border:1px solid var(--border);border-radius:var(--radius);padding:14px}
.pill{display:inline-flex;align-items:center;gap:5px;border-radius:999px;padding:3px 10px;font-size:12px;font-weight:600}
.hairline{height:1px;background:var(--grid);border:none;margin:10px 0}
.muted{color:var(--ink-3)} .sec{color:var(--ink-2)}
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  border-radius:12px;padding:13px 18px;font-size:15px;font-weight:650;
  background:var(--accent);color:var(--on-accent);width:100%;
}
.btn:active{transform:scale(.985)}
.btn.ghost{background:transparent;color:var(--accent);border:1.5px solid var(--accent)}
.btn.subtle{background:var(--surface-1);color:var(--ink-1);border:1px solid var(--border)}
.btn.danger{background:var(--critical)}
.btn[disabled]{opacity:.45;pointer-events:none}

/* ---------- top bar ---------- */
.topbar{
  position:sticky;top:0;z-index:30;background:var(--page);
  padding:calc(env(safe-area-inset-top) + 10px) 16px 10px;
  display:flex;align-items:center;gap:10px;border-bottom:1px solid var(--grid);
}
/* Inside the installed iOS app (html.native-ios, set from the user agent) the
   webview underlaps the Dynamic Island and there is no Safari chrome to save
   us. max() holds a floor tall enough to clear the island even if
   env(safe-area-inset-top) reports 0, which it has been seen to do in
   WKWebView. On non-island devices env() wins and nothing changes. */
html.native-ios .topbar{padding-top:max(calc(env(safe-area-inset-top) + 10px), 62px)}
html.native-ios .login{padding-top:max(calc(env(safe-area-inset-top) + 28px), 70px)}

.topbar .brand{font-weight:800;font-size:17px;letter-spacing:-.2px}
.topbar .brand small{display:block;font-size:11px;font-weight:600;color:var(--ink-3);letter-spacing:.2px}
.topbar .spacer{flex:1}
.iconbtn{width:38px;height:38px;border-radius:11px;background:var(--surface-1);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;font-size:17px}
.net{display:flex;align-items:center;gap:6px;font-size:11.5px;font-weight:700;color:var(--good-text)}
.net .dot{width:8px;height:8px;border-radius:50%;background:var(--good)}
.net.off{color:var(--serious)} .net.off .dot{background:var(--serious)}

/* ---------- demo bar ---------- */
.demobar{
  margin:10px 16px 0;border-radius:12px;border:1px dashed var(--baseline);
  padding:9px 12px;display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  font-size:12px;color:var(--ink-2);background:var(--surface-1);
}
.demobar b{font-size:11px;letter-spacing:.6px;color:var(--ink-3)}
.demobar select{
  font:inherit;font-weight:650;color:var(--ink-1);background:var(--page);
  border:1px solid var(--border);border-radius:8px;padding:4px 8px;
}
.demobar .ff{margin-left:auto;font-weight:700;color:var(--accent);font-size:12px;padding:4px 8px;border-radius:8px;border:1px solid var(--accent)}

/* ---------- login ---------- */
/* `safe center` matters here. Plain `center` centres the roster, but once the
   list is taller than the screen — which it is at eight staff — the overflow
   goes off BOTH ends and the top names become unreachable. `safe` falls back
   to flex-start in exactly that case. The inset padding keeps the heading out
   from under the notch in the installed app, where there is no browser chrome
   to push it down. */
.login{flex:1;display:flex;flex-direction:column;justify-content:safe center;overflow-y:auto;
  padding:calc(env(safe-area-inset-top) + 28px) 28px calc(env(safe-area-inset-bottom) + 28px);gap:20px}
.login h1{font-size:26px;letter-spacing:-.4px}
.login h1 span{color:var(--accent)}
.login p{color:var(--ink-2);font-size:14.5px;line-height:1.5}
.stafflist{display:flex;flex-direction:column;gap:10px}
.staffrow{
  display:flex;align-items:center;gap:12px;background:var(--surface-1);
  border:1px solid var(--border);border-radius:var(--radius);padding:13px 14px;text-align:left;
}
.staffrow:active{transform:scale(.99)}
.avatar{
  width:42px;height:42px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-weight:800;font-size:15px;color:#fff;flex-shrink:0;
}
.staffrow .who{flex:1}
.staffrow .who b{font-size:15.5px;display:block}
.staffrow .who span{font-size:12.5px;color:var(--ink-3)}
.staffrow .arr{color:var(--ink-3);font-size:18px}

/* ---------- staff board ---------- */
.board{padding:12px 16px 110px;display:flex;flex-direction:column;gap:10px}
.boardhead{display:flex;align-items:baseline;gap:8px;margin:6px 2px 0}
.boardhead h2{font-size:18px;letter-spacing:-.3px}
.boardhead .count{font-size:12.5px;color:var(--ink-3);font-weight:600}
.clientcard{
  background:var(--surface-1);border:1px solid var(--border);border-radius:var(--radius);
  padding:12px 14px;display:flex;align-items:center;gap:12px;text-align:left;width:100%;
  position:relative;overflow:hidden;
}
.clientcard:active{transform:scale(.99)}
.clientcard .edge{position:absolute;left:0;top:0;bottom:0;width:4px;border-radius:4px 0 0 4px}
.clientcard.ok .edge{background:var(--good)}
.clientcard.due .edge{background:var(--warn)}
.clientcard.late .edge{background:var(--critical)}
.clientcard .cinfo{flex:1;min-width:0}
.clientcard .cname{font-weight:750;font-size:15.5px;display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.clientcard .cmeta{font-size:12.5px;color:var(--ink-3);margin-top:2px;display:flex;gap:8px;flex-wrap:wrap}
.lvl{font-size:10.5px;font-weight:800;letter-spacing:.4px;padding:2px 7px;border-radius:6px;background:var(--page);border:1px solid var(--border);color:var(--ink-2)}
.lvl.hot{background:var(--chip-late);border-color:transparent;color:var(--critical)}
.flag{font-size:10.5px;font-weight:700;padding:2px 7px;border-radius:6px;background:var(--chip-warn);color:#7a5200}
:root[data-theme="dark"] .flag{color:#fab219}
@media (prefers-color-scheme: dark){ :root:where(:not([data-theme="light"])) .flag{color:#fab219} }
.timerbox{text-align:right;flex-shrink:0}
.timerbox .t{font-variant-numeric:tabular-nums;font-weight:800;font-size:17px}
.timerbox .lab{font-size:10.5px;font-weight:700;letter-spacing:.5px;color:var(--ink-3)}
.clientcard.late .timerbox .t{color:var(--critical)}
.clientcard.due .timerbox .t{color:#a36f00}
:root[data-theme="dark"] .clientcard.due .timerbox .t{color:var(--warn)}
@media (prefers-color-scheme: dark){ :root:where(:not([data-theme="light"])) .clientcard.due .timerbox .t{color:var(--warn)} }
.prox{display:flex;align-items:center;gap:4px;font-size:11px;font-weight:700}
.prox .bars{display:inline-flex;align-items:flex-end;gap:1.5px;height:11px}
.prox .bars i{width:3px;border-radius:1px;background:var(--baseline)}
.prox .bars i:nth-child(1){height:4px}.prox .bars i:nth-child(2){height:7px}.prox .bars i:nth-child(3){height:11px}
.prox.p2 .bars i:nth-child(-n+2){background:var(--good)}
.prox.p3 .bars i{background:var(--good)}
.prox.p1 .bars i:nth-child(1){background:var(--warn)}
.prox .plab{color:var(--ink-3)}
.prox.p3 .plab,.prox.p2 .plab{color:var(--good-text)}

/* sticky action */
.stickyact{
  position:fixed;bottom:0;left:0;right:0;z-index:40;
  padding:10px 16px calc(env(safe-area-inset-bottom) + 12px);
  background:linear-gradient(to top,var(--page) 70%,transparent);
  display:flex;gap:10px;max-width:480px;margin:0 auto;
}
.badge{
  position:absolute;top:-6px;right:-6px;background:var(--critical);color:#fff;
  font-size:11px;font-weight:800;min-width:20px;height:20px;border-radius:10px;
  display:flex;align-items:center;justify-content:center;padding:0 5px;
}

/* ---------- record sheet ---------- */
.sheet-scrim{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:50;opacity:0;pointer-events:none;transition:opacity .18s}
.sheet-scrim.open{opacity:1;pointer-events:auto}
.sheet{
  position:fixed;left:0;right:0;bottom:0;z-index:60;max-width:480px;margin:0 auto;
  background:var(--surface-1);border-radius:0;border:1px solid var(--border);border-bottom:none;
  transform:translateY(105%);transition:transform .22s cubic-bezier(.32,.72,.35,1);
  /* Full takeover — Bret: "should go all the way to the top". Recording a
     round is the app's main act; give it the whole screen. */
  height:100dvh;max-height:100dvh;display:flex;flex-direction:column;
  padding-top:env(safe-area-inset-top);
}
html.native-ios .sheet{padding-top:max(env(safe-area-inset-top), 59px)}
.sheet.open{transform:translateY(0)}
.sheet .grip{width:38px;height:4px;border-radius:2px;background:var(--baseline);margin:9px auto 2px}
.sheet .body{overflow-y:auto;padding:10px 18px calc(env(safe-area-inset-bottom) + 16px)}
.sheethead{display:flex;align-items:center;gap:12px;padding:6px 0 12px;border-bottom:1px solid var(--grid)}
.sheethead .who b{font-size:17px;display:block}
.sheethead .who span{font-size:12.5px;color:var(--ink-3)}
.verify{
  margin:12px 0;border-radius:12px;padding:11px 13px;display:flex;gap:10px;align-items:center;
  font-size:13px;font-weight:650;border:1px solid transparent;
}
.verify .vico{font-size:19px}
.verify.v-ok{background:var(--chip-ok);color:var(--good-text)}
.verify.v-weak{background:var(--chip-warn);color:#7a5200}
.verify.v-none{background:var(--chip-late);color:var(--critical)}
.verify.v-na{background:var(--page);border-color:var(--border);color:var(--ink-2)}
.prox.pna .plab{color:var(--ink-3);font-style:italic}
:root[data-theme="dark"] .verify.v-weak{color:var(--warn)}
@media (prefers-color-scheme: dark){ :root:where(:not([data-theme="light"])) .verify.v-weak{color:var(--warn)} }
.verify small{display:block;font-weight:500;font-size:11.5px;opacity:.85}
.groupt{font-size:11px;font-weight:800;letter-spacing:.8px;color:var(--ink-3);margin:14px 0 8px}
.codegrid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.code{
  border:1px solid var(--border);border-radius:11px;padding:10px 6px;text-align:center;
  background:var(--page);display:flex;flex-direction:column;gap:3px;align-items:center;
}
.code .ico{font-size:20px}
.code .cl{font-size:11.5px;font-weight:650;line-height:1.15}
.code.sel{background:var(--accent);border-color:var(--accent)}
.code.sel .cl{color:#fff}
.code.sel .ico{filter:grayscale(1) brightness(3)}
.locrow{display:flex;gap:7px;flex-wrap:wrap}
.loc{border:1px solid var(--border);border-radius:999px;padding:7px 13px;font-size:12.5px;font-weight:650;background:var(--page)}
.loc.sel{background:var(--accent);color:#fff;border-color:var(--accent)}
.notefield{
  width:100%;font:inherit;font-size:14px;border:1px solid var(--border);border-radius:11px;
  background:var(--page);color:var(--ink-1);padding:10px 12px;resize:none;min-height:44px;
}
.overridebox{margin-top:10px}
.sheetfoot{display:flex;gap:10px;margin-top:16px}

/* ---------- toast ---------- */
.toast{
  position:fixed;bottom:calc(env(safe-area-inset-bottom) + 90px);left:50%;transform:translateX(-50%) translateY(20px);
  background:var(--ink-1);color:var(--page);padding:11px 18px;border-radius:999px;font-size:13.5px;font-weight:650;
  opacity:0;transition:all .25s;z-index:80;pointer-events:none;white-space:nowrap;
}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}

/* ---------- supervisor ---------- */
.dash{padding:12px 16px 40px;display:flex;flex-direction:column;gap:14px}
.tilerow{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
@media(min-width:760px){.tilerow{grid-template-columns:repeat(4,1fr)}}
.tile{background:var(--surface-1);border:1px solid var(--border);border-radius:var(--radius);padding:13px 15px}
.tile .tv{font-size:26px;font-weight:800;letter-spacing:-.5px;margin-top:2px}
.tile .tl{font-size:11.5px;font-weight:700;letter-spacing:.4px;color:var(--ink-3)}
.tile .ts{font-size:11.5px;color:var(--ink-2);margin-top:2px}
.tile.alert .tv{color:var(--critical)}
.tile.goodv .tv{color:var(--good-text)}
.alertfeed{display:flex;flex-direction:column;gap:8px}
.alertrow{display:flex;gap:10px;align-items:flex-start;padding:10px 12px;border-radius:11px;background:var(--chip-late);font-size:13px}
.alertrow.warn{background:var(--chip-warn)}
.alertrow .at{font-variant-numeric:tabular-nums;font-size:11.5px;color:var(--ink-2);flex-shrink:0;font-weight:700;margin-top:1px}
.alertrow b{font-weight:750}
.livegrid{display:flex;flex-direction:column;gap:8px}
.liverow{
  display:grid;grid-template-columns:12px 1fr auto;gap:3px 10px;align-items:center;
  padding:10px 12px;border-radius:11px;
  background:var(--page);border:1px solid var(--border);font-size:13px;
}
.liverow .lname{font-weight:700;min-width:0;display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.liverow .lstat{color:var(--ink-2);font-size:12.5px;grid-column:2/4}
.liverow .ltime{font-variant-numeric:tabular-nums;font-weight:750;font-size:12.5px}
.liverow.late .ltime{color:var(--critical)} .liverow.due .ltime{color:#a36f00}
:root[data-theme="dark"] .liverow.due .ltime{color:var(--warn)}
@media (prefers-color-scheme: dark){ :root:where(:not([data-theme="light"])) .liverow.due .ltime{color:var(--warn)} }
.statusdot{width:9px;height:9px;border-radius:50%;flex-shrink:0}
.liverow.ok .statusdot{background:var(--good)} .liverow.due .statusdot{background:var(--warn)} .liverow.late .statusdot{background:var(--critical)}
table.aud{width:100%;border-collapse:collapse;font-size:12.5px}
table.aud th{font-size:10.5px;letter-spacing:.6px;color:var(--ink-3);text-align:left;padding:7px 8px;border-bottom:1px solid var(--grid);font-weight:800}
table.aud td{padding:8px;border-bottom:1px solid var(--grid);vertical-align:top}
table.aud td.tnum{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:650}
.vtag{font-size:10.5px;font-weight:750;padding:2px 7px;border-radius:6px;display:inline-block}
.vtag.beacon{background:var(--chip-ok);color:var(--good-text)}
.vtag.manual{background:var(--chip-warn);color:#7a5200}
.vtag.late{background:var(--chip-late);color:var(--critical)}
.vtag.na{background:var(--page);border:1px solid var(--border);color:var(--ink-2)}
.vtag.nfc{background:#e0f2f6;color:var(--accent-deep)}
:root[data-theme="dark"] .vtag.nfc{background:#152741;color:#86b6ef}
@media (prefers-color-scheme: dark){ :root:where(:not([data-theme="light"])) .vtag.nfc{background:#152741;color:#86b6ef} }
:root[data-theme="dark"] .vtag.manual{color:var(--warn)}
@media (prefers-color-scheme: dark){ :root:where(:not([data-theme="light"])) .vtag.manual{color:var(--warn)} }
.sechead{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.sechead h3{font-size:15px;letter-spacing:-.2px;flex:1;min-width:120px}
.linkbtn{font-size:12.5px;font-weight:700;color:var(--accent)}
.stafftab{width:100%;border-collapse:collapse;font-size:13px}
.stafftab td,.stafftab th{padding:8px;border-bottom:1px solid var(--grid);text-align:left}
.stafftab th{font-size:10.5px;letter-spacing:.6px;color:var(--ink-3);font-weight:800}
.stafftab td.num{font-variant-numeric:tabular-nums;text-align:right;font-weight:650}
.meter{height:6px;border-radius:3px;background:var(--grid);overflow:hidden;min-width:70px}
.meter i{display:block;height:100%;border-radius:3px;background:var(--series-1)}
.filterrow{display:flex;gap:8px;flex-wrap:wrap}
.fchip{border:1px solid var(--border);background:var(--surface-1);border-radius:999px;padding:6px 13px;font-size:12.5px;font-weight:650}
.fchip.sel{background:var(--ink-1);color:var(--page);border-color:var(--ink-1)}

/* forms & staff admin */
.formgrid{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.formgrid .full{grid-column:1/3}
label.flab{font-size:11px;font-weight:800;letter-spacing:.6px;color:var(--ink-3);display:block;margin-bottom:5px}
.input{width:100%;font:inherit;font-size:14px;border:1px solid var(--border);border-radius:10px;background:var(--page);color:var(--ink-1);padding:10px 12px}
select.input{appearance:auto}
.staffadmin{display:flex;flex-direction:column;gap:8px}
.sarow{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:11px;background:var(--page);border:1px solid var(--border);flex-wrap:wrap}
.sarow .who{flex:1;min-width:150px}
.sarow .who span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
.sarow .who b{font-size:14px;display:block}
.sarow .who span{font-size:12px;color:var(--ink-3)}
.sarow.inactive{opacity:.5}
.rolechip{font-size:10.5px;font-weight:800;letter-spacing:.4px;padding:3px 8px;border-radius:6px;background:var(--chip-ok);color:var(--good-text)}
.rolechip.admin{background:#ece9fb;color:#4a3aa7}
:root[data-theme="dark"] .rolechip.admin{background:#262148;color:#9085e9}
@media (prefers-color-scheme: dark){ :root:where(:not([data-theme="light"])) .rolechip.admin{background:#262148;color:#9085e9} }
.iconbtn.on{background:var(--accent);color:#fff;border-color:var(--accent)}
/* Wide report tables scroll INSIDE their card. Without this the widest one
   (By client, 7 columns) is wider than a phone screen, so the whole page
   slides sideways under your thumb — reported on an iPhone 16 Pro Max, where
   that table measures 431px against a 430px viewport. Same posture as .tlwrap
   above: never clip a compliance figure to stop the slide, let it scroll. */
.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.reptbl{width:100%;border-collapse:collapse;font-size:12.5px}
.reptbl th{font-size:10.5px;letter-spacing:.6px;color:var(--ink-3);text-align:left;padding:7px 8px;border-bottom:1px solid var(--grid);font-weight:800}
.reptbl td{padding:8px;border-bottom:1px solid var(--grid)}
.reptbl td.num{font-variant-numeric:tabular-nums;text-align:right;font-weight:650}

/* timeline view */
.tlwrap{position:relative;overflow-x:auto}
.tlhead{display:flex;align-items:flex-end;gap:8px;margin-bottom:2px}
.tlrow{display:flex;align-items:center;gap:8px;min-height:38px;border-bottom:1px solid var(--grid)}
.tlrow:last-child{border-bottom:none}
.tlname{width:132px;flex-shrink:0;font-size:12.5px;font-weight:750;line-height:1.2;padding:4px 0}
.tlmeta{display:flex;gap:5px;align-items:center;margin-top:2px;flex-wrap:wrap}
.tlmeta .lvl{font-size:9.5px;padding:1px 5px}
.gapb{font-size:10px;font-weight:800;font-variant-numeric:tabular-nums;padding:1px 6px;border-radius:5px;background:var(--chip-ok);color:var(--good-text)}
.gapb.due{background:var(--chip-warn);color:#7a5200}
.gapb.late{background:var(--chip-late);color:var(--critical)}
.bstat{font-size:9.5px;color:var(--ink-3);font-style:italic}
.tltrack{flex:1;position:relative;height:34px;min-width:340px}
.tlhr{position:absolute;top:0;bottom:0;width:1px;background:var(--grid)}
.tlhlab{position:absolute;bottom:0;transform:translateX(-50%);font-size:10px;color:var(--ink-3)}
.tlnow{position:absolute;top:0;bottom:0;width:2px;background:var(--series-1);opacity:.55;border-radius:1px}
.tldot{position:absolute;top:50%;transform:translate(-50%,-50%);width:11px;height:11px;border-radius:50%;cursor:pointer}
.tldot.ok{background:var(--baseline)}
.tldot.noprox{background:var(--surface-1);border:2.5px solid var(--series-1)}
.tldot.late{background:var(--warn)}
.tldot.missed{background:var(--critical);width:12px;height:12px}
.tldot:hover{outline:2px solid var(--ink-1);outline-offset:1px}
.syncbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.kipulogo{font-weight:800;font-size:12px;letter-spacing:.4px;background:#0e4c68;color:#fff;border-radius:7px;padding:4px 9px}
.synclog{font-size:12px;color:var(--ink-2);display:flex;flex-direction:column;gap:5px}
.synclog b{font-weight:700}
.crow{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:11px;background:var(--page);border:1px solid var(--border);flex-wrap:wrap}
.crow .who{flex:1;min-width:150px}
.crow .who b{font-size:14px;display:block}
.crow .who span{font-size:11.5px;color:var(--ink-3)}
.bchip{font-size:11px;font-weight:750;padding:4px 9px;border-radius:7px;background:var(--chip-ok);color:var(--good-text)}
.bchip.none{background:var(--page);border:1px dashed var(--baseline);color:var(--ink-3)}
.bchip.ref{background:var(--chip-late);color:var(--critical)}
.assignrow{display:flex;gap:7px;align-items:center;width:100%;margin-top:8px}
.assignrow .input{max-width:170px;padding:8px 10px;font-size:13px}
.photodot{position:absolute;right:-2px;bottom:-2px;width:15px;height:15px;border-radius:50%;background:var(--surface-1);display:flex;align-items:center;justify-content:center;font-size:9px;border:1px solid var(--border)}

/* chart */
.chartwrap{position:relative}
.legend{display:flex;gap:16px;font-size:12px;color:var(--ink-2);margin:2px 0 8px}
.legend .li{display:flex;align-items:center;gap:6px;font-weight:600}
.legend .sw{width:10px;height:10px;border-radius:3px}
.ttip{
  position:absolute;pointer-events:none;background:var(--ink-1);color:var(--page);
  border-radius:9px;padding:7px 10px;font-size:12px;font-weight:600;opacity:0;transition:opacity .12s;
  white-space:nowrap;z-index:5;transform:translate(-50%,-110%);
}
.ttip .tt2{font-weight:500;opacity:.8}
.datatable{display:none}
.datatable.show{display:block}

.viewtabs{display:flex;background:var(--surface-1);border:1px solid var(--border);border-radius:12px;padding:4px;gap:4px;margin:0 16px}
.viewtabs button{flex:1;padding:8px;border-radius:9px;font-size:13px;font-weight:700;color:var(--ink-3)}
.viewtabs button.sel{background:var(--accent);color:#fff}
.hide{display:none !important}

/* ---------- production additions ---------- */
.loginform{display:flex;flex-direction:column;gap:10px}
.loginform .input{font-size:16px;padding:13px 14px} /* 16px stops iOS zoom-on-focus */
.err{background:var(--chip-late);color:var(--critical);border-radius:10px;padding:10px 13px;font-size:13px;font-weight:650}
.pinpad{display:grid;grid-template-columns:repeat(3,1fr);gap:9px;margin-top:4px}
.pinpad button{background:var(--surface-1);border:1px solid var(--border);border-radius:12px;padding:15px 0;font-size:19px;font-weight:700}
.pinpad button:active{background:var(--accent);color:#fff}
.pindots{display:flex;gap:9px;justify-content:center;margin:10px 0 4px}
.pindots i{width:12px;height:12px;border-radius:50%;background:var(--grid);display:block}
.pindots i.on{background:var(--accent)}
.codegrid.multi .code.sel::after{content:"✓";position:absolute;top:4px;right:6px;font-size:11px;font-weight:800;color:#fff}
/* A code required by another (respiration attestation under Sleeping) — shown
   as locked on, so it is clear it is part of what is being attested to. */
.codegrid.multi .code.sel.locked::after{content:"🔒"}
.code.sel.locked{opacity:.92}
.code{position:relative}
.groupt .hint{font-weight:600;letter-spacing:0;color:var(--ink-3);text-transform:none;font-size:11px}
.queuepill{display:flex;align-items:center;gap:6px;font-size:11.5px;font-weight:700;color:var(--serious)}
.syncing{animation:spin 1s linear infinite;display:inline-block}
@keyframes spin{to{transform:rotate(360deg)}}
.scanbox{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:11px;background:var(--page);border:1px dashed var(--baseline);font-size:12.5px;color:var(--ink-2);margin-bottom:10px}
.testbadge{background:var(--chip-warn);color:#7a5200;font-size:10px;font-weight:800;letter-spacing:.5px;padding:2px 7px;border-radius:5px}
.emptystate{text-align:center;padding:40px 20px;color:var(--ink-3)}
.emptystate .big{font-size:34px;margin-bottom:10px}
.emptystate p{font-size:13.5px;line-height:1.5;margin-top:6px}
.daterow{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:12.5px}
.daterow input{font:inherit;font-size:13px;padding:7px 10px;border:1px solid var(--border);border-radius:9px;background:var(--page);color:var(--ink-1)}

/* install-to-home-screen bar */
.installbar{
  position:fixed;left:0;right:0;bottom:0;z-index:90;
  max-width:480px;margin:0 auto;
  background:var(--ink-1);color:var(--page);
  padding:12px 14px calc(env(safe-area-inset-bottom) + 12px);
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  font-size:12.5px;font-weight:600;line-height:1.4;
  border-radius:14px 14px 0 0;
}
.installbar span{flex:1;min-width:170px}
.installbar .fchip{background:transparent;border-color:rgba(255,255,255,.35);color:var(--page);padding:6px 12px}
.installbar .fchip.sel{background:var(--page);color:var(--ink-1);border-color:var(--page)}

/* ---------- vitals reminder card ----------
   Deliberately NOT styled like the round cards: vitals are a Kipu reminder,
   not part of the rounding record, and the box says so at a glance. */
.vitalscard{border:1.5px solid var(--warn);border-radius:var(--radius);
  background:var(--chip-warn);padding:12px 14px;margin-top:16px}
.vitalscard .vhead{display:flex;align-items:center;gap:8px;font-weight:800;font-size:13px;
  letter-spacing:.4px;color:#7a5200;margin-bottom:8px}
:root[data-theme="dark"] .vitalscard .vhead{color:var(--warn)}
@media (prefers-color-scheme: dark){ :root:where(:not([data-theme="light"])) .vitalscard .vhead{color:var(--warn)} }
.vitalscard .sarow{background:var(--surface-1);border:1px solid var(--border);
  border-radius:10px;padding:9px 11px;margin-bottom:6px}

/* =========================================================================
   SKY — Bret's pick (2026-08-12), replacing Slate Glass.
   documentation/UI-SPEC-SKY.md is the source of truth: Vertical Wash card
   fill, Clear Blue borders (he rejected white/pale borders twice — do not
   lighten), segmented tabs with the gradient blue chip (option B).
   Appended last so equal-specificity rules here win by order. The dormant
   dark tokens above are untouched — Sky has no designed dark variant yet
   and app.js pins data-theme="light"; design it before ever unpinning.
   Contrast: the spec's muted #5c7a90 measures 2.7:1 on the card wash, so
   muted/secondary ink are darkened to AA here (the spec's own instruction).
   Late/due figures likewise get deepened inks (--late-ink/--due-ink); the
   bright #e0415c stays on the non-text edge stripes and dots.
   ========================================================================= */
:root, :root[data-theme="light"]{
  --page:#ddeefb;                     /* base under the sky gradient */
  --ink-1:#12283d; --ink-2:#2e4d68; --ink-3:#365570;
  --accent:#0b8fd6; --accent-deep:#076ba3; --on-accent:#ffffff;
  --late:#e0415c;                     /* edge stripes, status dots */
  --late-ink:#c11f47; --due-ink:#7a5200;  /* AA-safe figures on the wash */
  --border:rgba(63,124,180,.42);
  --grid:#c9dff0; --baseline:#a6c6de;
  --series-1:#0b8fd6;
  --radius:15px;
  --card-wash:linear-gradient(180deg,rgba(150,196,232,.8),rgba(238,248,254,.42));
  --card-border:rgba(63,124,180,.75); /* "Clear Blue" — border 2 */
  --card-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 4px 13px -6px rgba(18,64,104,.42);
}
body{background:linear-gradient(160deg,#d9ecfb,#eaf6fd 50%,#dbeefb)}
.app{background:transparent}

.card,.tile,.staffrow,.clientcard,.demobar{
  background:var(--card-wash);
  border:1px solid var(--card-border);
  box-shadow:var(--card-shadow);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
}
/* Tall section containers (reports, live board): the wash settles to
   near-white after the header band so tables and charts stay readable.
   Compact cards above keep the exact approved percent gradient. */
.card{background:linear-gradient(180deg,rgba(150,196,232,.8),rgba(238,248,254,.42) 220px,rgba(244,250,254,.5))}
.iconbtn,.btn.subtle{background:rgba(255,255,255,.6);border-color:var(--border);box-shadow:0 1px 6px rgba(18,64,104,.12)}
.fchip{background:rgba(255,255,255,.55);border-color:var(--border)}
.lvl{background:rgba(11,143,214,.16);border-color:transparent;color:#054a70;border-radius:7px}
.lvl.hot{background:var(--chip-late);color:var(--critical)}
.linkbtn{color:#05537d}
.demobar .ff{color:var(--accent-deep);border-color:var(--accent-deep)}

.topbar{
  background:rgba(234,246,253,.72);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  border-bottom:none;box-shadow:0 1px 0 rgba(18,64,104,.08);
}

/* Segmented tabs — gradient blue chip on a white-to-blue track (option B) */
.viewtabs{border:1px solid rgba(63,124,180,.42);background:linear-gradient(180deg,#f4fafe,#b9dcf4);border-radius:14px;box-shadow:none}
.viewtabs button{color:#33607f;border-radius:11px}
.viewtabs button.sel{
  color:#fff;background:linear-gradient(180deg,#2ba3e3,#0678bd);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.45),0 3px 10px -3px rgba(11,143,214,.7);
}

.btn{border-radius:15px;box-shadow:0 6px 18px -6px rgba(11,143,214,.75)}
.btn.ghost{box-shadow:none}
.btn.danger{box-shadow:0 2px 8px rgba(208,59,59,.30)} /* keeps #d03b3b: white on it is 4.8:1 */

/* Urgency: bright stripe + dot stay #e0415c (non-text); figures use the
   deepened inks so a 3am hallway can still read how late a check is. */
.clientcard.late .edge{background:var(--late)}
.liverow.late .statusdot{background:var(--late)}
.tldot.missed{background:var(--late)}
.clientcard.late .timerbox .t{color:var(--late-ink)}
.clientcard.due .timerbox .t{color:var(--due-ink)}
.liverow.late .ltime{color:var(--late-ink)}
.liverow.due .ltime{color:var(--due-ink)}
.vitalscard{background:var(--surface-1)}

/* Phone privilege chip, beside the level chip on a client card (Bret,
   2026-08-14). Colours are deliberately NOT Kipu's tag colours: the tag ships
   #1bd603, which fails AA on this wash. Same decision as the Sky ink
   corrections — match the meaning, not the hex. Every chip carries words as
   well as colour, because this decides whether somebody gets their phone and a
   colour-blind reader must not be guessing. */
.phchip{
  display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-weight:800;
  padding:2px 7px;border-radius:999px;white-space:nowrap;vertical-align:middle;
  letter-spacing:.1px;
}
.phchip.ok{color:#0f6b32;background:#e2f6e9}
.phchip.land{color:var(--due-ink);background:#fdf1d6}
.phchip.no{color:var(--late-ink);background:#fde7ec}
/* Untagged is the loudest thing on the row on purpose — it is an instruction
   ("go ask"), not a status, and it should look unfinished until charted. */
.phchip.unset{color:#4a3a86;background:#ebe7fa;border:1px dashed #b9aeea}

/* Vitals: how overdue, sitting beside the name (Bret, 2026-08-14).
   The name is display:block, so the two need their own flex line to share a
   row. .voverdue has to out-specify `.sarow .who span{display:block}` (0-2-1),
   which is why it is written as a descendant chain and not a bare class.
   Colour is --late-ink, the Sky palette's measured AA-safe red — the same ink
   the late round timers already use. Never hardcode a red here. */
.vitalscard .vtop{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap}
/* Claim enough width for "Marcus Whitfield  45m overdue" to stay on ONE line.
   The row already wraps, so on a phone this pushes the "Logged in Kipu" button
   onto its own line instead — the right trade: the lateness is what gets read
   at 3am, the button is what gets pressed afterwards. On a wider supervisor
   screen there is room for both and nothing moves. (Kipu-synced facilities
   have no button at all, so this only bites where one exists.) */
.vitalscard .sarow .who{min-width:min(100%, 15rem)}
.vitalscard .vtop b{display:inline;font-size:14px}
.vitalscard .sarow .who .voverdue{
  display:inline;font-size:12px;font-weight:800;color:var(--late-ink);
  white-space:nowrap;letter-spacing:.1px;
}
/* One badge, one colour, on every row — overdue or due-soon (Bret's call,
   2026-08-14). An earlier version rendered inside-the-grace rows in the softer
   due ink; he asked for red throughout, so there is deliberately no second
   variant here. The badge text carries the meaning, not the colour. */

/* Record sheet stays a calm white surface; scrim deepened to a sky navy so
   the sheet separates from the washed board behind it. */
.sheet{border-color:transparent;box-shadow:0 -6px 24px rgba(18,64,104,.2)}
.sheet-scrim{background:rgba(13,36,58,.45)}

/* ------------- Individual client audit (DHCS / Joint Commission) -------------
   A survey document, so it deliberately looks like PAPER — white in every
   theme, black type, no app chrome. Overlay on screen; @media print strips
   everything else so window.print() emits just the report (works in the
   native shell via AirPrint too — no popups anywhere). */
.audwrap{position:fixed;inset:0;z-index:300;background:#fff;overflow-y:auto;
  /* safe-area: without this the toolbar (with Close) hides under the iPhone
     notch/status bar — reported live: "no way to return to the home screen" */
  padding:calc(26px + env(safe-area-inset-top, 0px)) 34px calc(60px + env(safe-area-inset-bottom, 0px));
  -webkit-overflow-scrolling:touch}
.audbar{position:sticky;top:0;background:#fff;padding:6px 0;z-index:2}
.audbar{display:flex;gap:10px;margin-bottom:20px}
.audoc{font:13px/1.5 -apple-system,'Segoe UI',Roboto,sans-serif;color:#111;max-width:880px}
.audoc h1{font-size:19px;margin:0;color:#111}
.audoc h2{font-size:13px;font-weight:600;color:#555;margin:2px 0 0}
.audoc .head{display:flex;justify-content:space-between;align-items:flex-start;
  border-bottom:3px solid #111;padding-bottom:10px}
.audoc .brand{text-align:right;font-size:12px;color:#555}
.audoc .grid{display:grid;grid-template-columns:repeat(4,1fr);gap:6px 18px;margin:14px 0;font-size:12.5px}
.audoc .grid b{display:block;font-size:10.5px;text-transform:uppercase;letter-spacing:.04em;color:#666}
.audoc .sumline{margin:6px 0 14px;padding:9px 12px;background:#f2f2f2;border-radius:6px;font-size:12.5px}
.audoc table{width:100%;border-collapse:collapse;font-size:12px}
.audoc th{text-align:left;font-size:10.5px;text-transform:uppercase;letter-spacing:.04em;color:#555;
  border-bottom:2px solid #111;padding:5px 7px}
.audoc td{border-bottom:1px solid #ddd;padding:5px 7px;vertical-align:top;color:#111}
.audoc td.num{color:#888;width:26px}
.audoc .ok{color:#0a7a33;font-weight:600}
.audoc .warn{color:#a15c00;font-weight:600}
.audoc .bad{color:#b3121f;font-weight:700}
.audoc tr.miss td{background:#fbeaea}
.audoc .foot{margin-top:16px;font-size:11px;color:#555}
.audoc .sig{display:flex;gap:40px;margin-top:34px}
.audoc .sig div{flex:1;border-top:1px solid #111;padding-top:4px;font-size:11px;color:#444}
@media print{
  body.audit-open>*:not(.audwrap){display:none !important}
  body.audit-open .audwrap{position:static;overflow:visible;padding:0}
  body.audit-open{background:#fff}
  .audwrap .noprint{display:none !important}
}

/* ---- board split: due above, caught-up below, unmistakable boundary ---- */
.boarddivider{display:flex;align-items:center;gap:12px;margin:18px 2px 10px;
  color:var(--good,#2e8b57);font-size:12px;font-weight:700;letter-spacing:.04em;
  text-transform:uppercase}
.boarddivider::before,.boarddivider::after{content:'';flex:1;height:2px;
  background:var(--border,#d7dee8);border-radius:1px}
.clientcard.inert{cursor:default;opacity:.62;pointer-events:none}
.clientcard.inert .edge{background:var(--border,#d7dee8)}

/* ---- admin messages to staff (banners + client notes) ---- */
.msgbanner{display:flex;gap:9px;align-items:flex-start;margin:0 2px 10px;
  border-radius:12px;padding:10px 12px;font-size:13px;font-weight:600;line-height:1.45}
.msgbanner.note{background:#fff7e0;border:1.5px solid #e0bd58;color:#6b5410}
.msgbanner.urgent{background:#fdeceb;border:1.5px solid #de7367;color:#8c2b22}
.msgbanner .mbody small{display:block;font-weight:500;opacity:.75;font-size:11px;margin-top:2px}
.msgbanner .mdismiss{margin-left:auto;background:none;border:none;color:inherit;
  opacity:.55;font-weight:800;font-size:14px;padding:2px 6px;cursor:pointer}
.clientnote{background:#eef4fb;border-left:3px solid var(--accent,#3d8a9a);color:#2d4257;
  font-size:13px;line-height:1.5;padding:9px 11px;border-radius:8px;margin:10px 0 4px}

/* ---- client face photos on the board and round sheet ---- */
.clientcard { align-items:center; }
.cface { width:44px; height:44px; border-radius:11px; flex:0 0 auto; margin-right:10px;
  display:flex; align-items:center; justify-content:center; font-weight:800; font-size:15px;
  color:#fff; background:linear-gradient(140deg,#4fb6ec,#0b8fd6); background-size:cover; background-position:center center;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.08); }
.cface.hasface { color:transparent; }
.sheethead .avatar.cface { width:52px; height:52px; border-radius:13px; }

/* =========================================================================
   PHONES — the daily hand-out / collection screen (Bret, 2026-08-14).

   Reuses .card / .sarow / .fchip so the screen is visibly the same app as the
   rounding board. Only three things are new: the progress header, the red
   COLLECT badge, and the muted "already back" state.
   ========================================================================= */
.phhead .phtitle{display:flex;align-items:baseline;gap:9px}
.phhead .phtitle h2{font-size:20px;letter-spacing:-.3px;flex:1}
.phhead .phday{font-size:11.5px;font-weight:800;color:var(--ink-3);white-space:nowrap;letter-spacing:.2px}
.phprog{height:8px;border-radius:999px;background:rgba(63,124,180,.2);overflow:hidden;margin-top:10px}
.phprog i{display:block;height:100%;border-radius:999px;
  background:linear-gradient(90deg,#2ba3e3,#0678bd);transition:width .35s ease}
/* Something is still out: the whole header changes colour, not just a digit.
   A supervisor glancing at a phone across the med room reads the block, not
   the number inside it. */
.phhead.short{border-color:var(--late)}
.phhead.short .phprog i{background:linear-gradient(90deg,#ef6a80,var(--late-ink))}

.phlist{margin-top:8px;display:flex;flex-direction:column;gap:7px}
.phrow{background:var(--page)}
/* The meta line WRAPS here rather than ellipsing. .sarow's default clips at
   one line, which on a phone cut "Room 10 Bed 1 · 2 out 4:58 PM · Dana Staff"
   down to "· Da…" — and who handed the device out is the first thing anyone
   asks at 10pm when one has not come back. Two lines is the right trade on a
   checklist. */
.phrow .who > span{white-space:normal;overflow:visible;text-overflow:clip;line-height:1.45}
/* Handed out and fully returned — deliberately quiet. Done work should
   recede so the two rows that still need a hand stand out at arm's length. */
.phrow.done{opacity:.62}
.phrow.short{border-color:var(--late);background:#fdf3f5}
.phacts{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-left:auto}
.phacts .fchip{padding:8px 14px}          /* thumb target, not a mouse target */
.phacts .ghostchip{padding:8px 10px;opacity:.6;font-size:14px;line-height:1}
.pdone{font-size:12px;font-weight:800;color:#0f6b32;white-space:nowrap}

/* The COLLECT badge. --late-ink (#c11f47) rather than --late (#e0415c): this
   one carries white TEXT, and the palette's note is explicit that #e0415c is
   for stripes and dots, not for type. White on #c11f47 measures ~6.5:1. */
/* Written as a descendant chain, NOT a bare .pbadge, for exactly the reason
   .voverdue is: `.sarow .who span{display:block}` (0-2-1) out-specifies a lone
   class and turns this pill into a full-width red bar on its own line — caught
   in the browser at 280px wide. Do not "simplify" this selector. */
.phrow .who b .pbadge{
  display:inline-flex;align-items:center;font-size:10.5px;font-weight:900;
  letter-spacing:.45px;padding:2px 8px;border-radius:999px;margin-left:7px;
  color:#fff;background:var(--late-ink);vertical-align:middle;
  white-space:nowrap;overflow:visible;width:auto;
}

/* Devices held in the safe (Bret confirmed 2026-08-14 the facility keeps
   blackout clients' phones). A held item is somebody else's property, so it
   reads as a distinct object on the row, not as another status chip. */
.safeclient{flex-wrap:wrap;align-items:flex-start}
.safelist{flex:1 0 100%;display:flex;flex-direction:column;gap:6px;margin-top:8px}
.safeitem{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:8px 11px;border-radius:10px;background:var(--surface-1);
  border:1px solid var(--border)}
.safeitem .who{flex:1;min-width:140px}
.safeitem .who b{display:block;font-size:13px}
.safeitem .who span{display:block;font-size:11.5px;color:var(--ink-3);white-space:normal}
.safeitem .fchip{padding:7px 13px}
/* Unclaimed property: discharged and the facility still has it. This section
   should be empty; when it is not, it is the loudest thing on the screen. */
.sarow.safeclient.short{border-color:var(--late);background:#fdf3f5}

/* A top-bar icon that is the CURRENT screen. Admins reach Phones from here
   rather than from the tab strip (Bret, 2026-08-14), so the icon has to be
   able to show that it is selected the way a tab would. */
.iconbtn.sel{
  background:linear-gradient(180deg,#2ba3e3,#0678bd);border-color:#0678bd;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4),0 3px 10px -3px rgba(11,143,214,.7);
}

/* Collect-a-phone, inside the round sheet (Bret, 2026-08-15). Sits between the
   proximity banner and the location step: visible the moment the sheet opens,
   but never in the way of recording the check, which is what the sheet is for. */
.phcollect{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:10px 0 2px;
  padding:11px 13px;border-radius:12px;
  background:#eef6fd;border:1px solid rgba(63,124,180,.35);
}
.phcollect .who{flex:1;min-width:150px}
.phcollect .who b{display:block;font-size:13.5px}
.phcollect .who span{display:block;font-size:11.5px;color:var(--ink-3);line-height:1.4}
.phcollect .fchip{padding:9px 15px}

/* =========================================================================
   SETTINGS — rebuilt 2026-08-15.

   Bret: "they are very boring and look janky. some words are cut off."

   THE CUT-OFF WORDS were a real bug, not a taste problem. Settings rows were
   borrowing `.sarow`, whose meta line is deliberately one-line-with-ellipsis
   (line ~323) because a client row shows "MR# · Room · admitted". Settings
   help is a SENTENCE, and ellipsing it hid the half that explains what the
   switch actually does — the only part that matters when you are deciding
   whether to touch it.

   Same fix the phones screen already needed: a descendant chain at equal
   specificity, appended later so it wins by order. `.sarow .who span` is
   (0,2,1); `.setrow .who > span` is also (0,2,1) and comes after. Do NOT
   "simplify" these to a bare class — a lone `.setrow span` (0,1,1) loses and
   the ellipsis silently comes back.
   ========================================================================= */

/* ---- group header: gives each card an identity at a glance ---- */
.setgrp{display:flex;align-items:center;gap:11px;margin-bottom:2px}
.setgrp-ico{
  width:34px;height:34px;flex-shrink:0;border-radius:10px;
  display:grid;place-items:center;font-size:16px;line-height:1;
  background:rgba(11,143,214,.14);border:1px solid rgba(63,124,180,.34);
}
.setgrp h3{margin:0}
.setgrp .n{
  margin-left:auto;font-size:11px;font-weight:700;color:var(--ink-3);
  background:rgba(255,255,255,.6);border:1px solid var(--border);
  padding:3px 9px;border-radius:999px;white-space:nowrap;
}

/* ---- one setting ---- */
.setrow{
  display:flex;align-items:flex-start;gap:14px;
  padding:13px 14px;margin-top:9px;
  border-radius:12px;
  background:rgba(255,255,255,.52);
  border:1px solid var(--border);
  transition:border-color .16s,background .16s;
}
.setrow:hover{background:rgba(255,255,255,.72)}
.setrow .who{flex:1;min-width:0}          /* min-width:0 lets long words wrap */
.setrow .who b{
  display:block;font-size:14.5px;line-height:1.35;color:var(--ink-1);
  margin-bottom:3px;
}
/* THE FIX — wrap instead of ellipse. See the header note before editing. */
.setrow .who > span{
  display:block;white-space:normal;overflow:visible;text-overflow:clip;
  font-size:12.5px;line-height:1.5;color:var(--ink-2);
}
.setctl{display:flex;align-items:center;gap:7px;flex-shrink:0;padding-top:1px}

/* Unsaved: the row itself says so, rather than a word buried under the help. */
.setrow.dirty{border-color:var(--accent);background:rgba(11,143,214,.09)}
/* These pills live inside .setmeta, NOT as direct children of .who — which is
   what keeps them clear of `.setrow .who > span` (0,2,1) above. When they were
   direct children that rule won and stretched each pill into a full-width bar;
   measured at 313px before the fix. Same trap the phones badge hit (see
   `.phrow .who b .pbadge`); the codebase has now paid for it twice. If you ever
   move a .tag back up to be a direct child of .who, it needs `> span.tag`
   (0,3,1) to survive. */
.setmeta .tag{
  display:inline-block;width:auto;font-size:10.5px;font-weight:800;
  letter-spacing:.4px;text-transform:uppercase;padding:3px 9px;border-radius:999px;
}
.setmeta .tag.unsaved{background:var(--accent);color:var(--on-accent)}
.setmeta .tag.over{background:rgba(255,255,255,.75);color:var(--ink-3);border:1px solid var(--border)}
/* Tag + Reset on one line, wrapping together rather than the button dropping
   onto a lonely row of its own. */
.setmeta{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-top:7px}
.setmeta .fchip{padding:4px 11px;font-size:12px}
.setwarn{
  display:block;margin-top:7px;padding:7px 9px;border-radius:9px;
  font-size:12px;line-height:1.45;
  background:var(--chip-late,#fbe4e4);color:var(--late-ink,#c11f47);
  border:1px solid rgba(224,65,92,.3);
}

/* ---- a switch that reads as a switch ---- */
.sw{
  width:52px;height:30px;flex-shrink:0;border-radius:999px;cursor:pointer;
  position:relative;border:1px solid var(--border);
  background:rgba(255,255,255,.75);
  transition:background .18s,border-color .18s;
}
.sw::after{
  content:"";position:absolute;top:3px;left:3px;width:22px;height:22px;
  border-radius:50%;background:#fff;
  box-shadow:0 1px 4px rgba(18,64,104,.45);
  transition:transform .18s;
}
.sw.on{background:var(--accent);border-color:var(--accent-deep)}
.sw.on::after{transform:translateX(22px)}
.sw:focus-visible{outline:2px solid var(--accent-deep);outline-offset:2px}

.setnum{max-width:96px;text-align:right}
.setunit{font-size:12px;color:var(--ink-3);white-space:nowrap}

/* ---- save bar: pinned, so a change made at the top of a long page is not
   saved by scrolling to the bottom and hoping ---- */
/* Only PINNED when there is something to lose. Sticky-always floated over the
   card behind it and covered the help text of whatever setting you were
   reading — janky in exactly the way this rebuild was meant to fix. With
   nothing unsaved it sits quietly at the end of the page instead. */
.setsave.float{position:sticky;bottom:10px;z-index:5}
.setsave{
  margin-top:14px;
  display:flex;align-items:center;gap:11px;flex-wrap:wrap;
  padding:12px 14px;border-radius:13px;
  background:linear-gradient(180deg,rgba(238,248,254,.96),rgba(214,235,250,.96));
  border:1px solid var(--card-border);
  box-shadow:0 6px 20px -8px rgba(18,64,104,.5);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
}
.setsave .cnt{font-size:12.5px;color:var(--ink-2);flex:1;min-width:120px}

@media (max-width:430px){
  .setrow{gap:10px;padding:12px}
  .setgrp-ico{width:30px;height:30px;font-size:14px}
}

/* Facility-configurable round sheet (2026-08-16) —
   a place the facility marked as its default leads the list; an activity
   that requires a written note carries a pencil and turns the note field
   red when selected. Small marks, because the round must stay three taps. */
.loc.pref { border-color: var(--good); box-shadow: inset 0 0 0 1px var(--good); }
.groupt.sub { opacity: .72; font-size: 11px; margin-top: 6px; }
.code .reqmark { opacity: .65; font-size: 11px; }
.notefield.req { border-color: var(--critical); }

/* Support access banner — visible the entire time Support Scan holds
   authorized access to a facility. Deliberately unmissable and not
   dismissible; it clears itself when the session ends. */
.supportbanner { position: sticky; top: 0; z-index: 60; padding: 9px 14px;
  background: #7a4a00; color: #fff; font-size: 12.5px; line-height: 1.45; }
.supportbanner b { font-weight: 800; }
