/* app.css — component styles for the bookings UI. Tokens + base live in theme.css.
   Tailwind utility classes (loaded via CDN) are available everywhere for ad-hoc layout;
   these classes cover the repeated widgets so the JS stays readable. */

.muted { color: var(--muted); }
.error { color: var(--danger); font-size: 0.9rem; }
.hidden, [hidden] { display: none !important; }

/* Icons (sprite symbols inherit size + colour from here) */
.icon { width: 22px; height: 22px; display: inline-block; vertical-align: middle; flex-shrink: 0;
  fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.icon-sm { width: 18px; height: 18px; }
.icon-dots { fill: currentColor; stroke: none; }
.icon-btn { display: inline-flex; align-items: center; justify-content: center; }
button .icon { margin-right: 0; }

/* Layout */
.screen { min-height: 100dvh; }
.center { display: grid; place-items: center; padding: 1.5rem; }
.app-wrap { max-width: 720px; margin: 0 auto; padding-bottom: 76px; }
.topbar { position: sticky; top: 0; z-index: 5; display: flex; align-items: center; gap: 0.6rem;
  padding: 4px 1rem; background: var(--surface); border-bottom: 1px solid var(--border); box-shadow: var(--shadow-sm); }
.topbar .brand { display: flex; align-items: center; gap: 8px; }
/* Brand lockup (light/dark swap) + compact mark badge for the collapsed sidebar.
   The lockup carries vertical whitespace, so it's sized generously; topbar padding is trimmed
   to keep the bar ~52px so the desktop sidebar stays aligned. */
.topbar .logo-lockup { height: 44px; width: auto; display: block; }
.topbar .logo-badge { width: 38px; height: 38px; display: none; }
.topbar .logo-dark { display: none; }
[data-theme="dark"] .topbar .logo-light { display: none; }
[data-theme="dark"] .topbar .logo-dark { display: block; }
#app.nav-collapsed .topbar .logo-lockup { display: none; }
#app.nav-collapsed .topbar .logo-badge { display: block; }
.spacer { flex: 1; }
#view { padding: 0.9rem; display: flex; flex-direction: column; gap: 0.8rem; }

/* Generic */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem 1.1rem; box-shadow: var(--shadow-sm); }
.row { display: flex; align-items: center; gap: 0.6rem; }
.between { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; }
.section-head { display: flex; align-items: center; justify-content: space-between; margin: 0.2rem 0; }
.section-head h2 { margin: 0; font-size: 1.05rem; }
.sh-title { display: flex; align-items: baseline; gap: 8px; }   /* keep "Queue" + the count together */

/* Button modifiers (base button styled in theme.css) */
button.ghost { background: transparent; color: var(--text); border-color: var(--border); }
button.ghost:hover { background: var(--surface-2); border-color: var(--border); }
button.small { padding: 0.35rem 0.65rem; font-size: 0.85rem; font-weight: 400; }
button.danger { background: transparent; color: var(--danger); border-color: var(--border); }
button.danger:hover { background: var(--danger-bg); border-color: var(--border); }

/* Forms */
label.field { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.82rem; color: var(--muted); }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0.6rem; }

/* Auth */
.auth { width: min(360px, 100%); display: flex; flex-direction: column; gap: 0.7rem; }
.auth .login-logo { width: min(240px, 72%); height: auto; display: block; margin: 0.2rem auto 0.4rem; }
.auth .login-dark { display: none; }
[data-theme="dark"] .auth .login-light { display: none; }
[data-theme="dark"] .auth .login-dark { display: block; }

/* Chips / tags */
.chip { font-size: 0.8rem; border-radius: 14px; padding: 2px 10px; border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text); cursor: pointer; }
.chip.on { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.chip.all-chip { font-weight: 500; padding: 3px 16px; border: 2px solid var(--accent); color: var(--accent); background: var(--surface); }
.chip.all-chip.on { background: var(--accent); color: var(--on-accent); }
.chip.colored { background: var(--tag-bg); color: var(--tag-fg); border-color: transparent; }
.chip.sel { border-width: 2px; border-color: var(--tag-fg); }
/* Per-nurse chip: subtle neutral pill = visibility checkbox + small colour dot + clickable name
   (checkbox toggles the column; name/heading click focuses that diary). */
.nurse-chip { display: inline-flex; align-items: center; gap: 6px; padding-left: 8px;
  background: var(--surface-2); color: var(--text); border: 1px solid var(--border); }
.nurse-chip.sel { border-width: 2px; border-color: var(--accent); padding-left: 7px; }
.chip-cb { width: 13px; height: 13px; margin: 0; cursor: pointer; flex: none; accent-color: var(--muted); opacity: 0.65; }
.ndot { width: 9px; height: 9px; border-radius: 50%; flex: none; background: var(--tag-fg, var(--muted)); }
.chip-label { cursor: pointer; }
/* Bulk show/hide controls at the end of the nurse-tag row. */
.tag-bulk { align-self: center; margin-left: 4px; padding: 2px 6px; font-size: 0.72rem; color: var(--muted);
  background: none; border: none; cursor: pointer; text-decoration: underline; }
.tag-bulk:hover { color: var(--accent); }
.tag { font-size: 0.78rem; border-radius: 12px; padding: 2px 9px; white-space: nowrap;
  background: var(--tag-bg, var(--surface-2)); color: var(--tag-fg, var(--text)); }
.tag.unassigned { background: transparent; border: 1px dashed var(--border); color: var(--muted); }
/* Fasting indicator */
.fasting-tag { background: var(--warning-bg, #f3e6cf); color: var(--warning, #8a5a1a); border-color: transparent; }
.name .fasting-tag { margin-left: 6px; }
.fast-flag { color: var(--warning, #8a5a1a); font-weight: 500; }
.qmini-tags { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; margin-top: 4px; }
.qmini-tags .tag { margin-top: 0; }
.tags { display: flex; flex-wrap: wrap; gap: 5px; align-items: flex-start; }
/* Nurse chips: fixed 6 per row so the second row aligns under the first (All sits to the left). */
.nurse-chips { display: grid; grid-template-columns: repeat(6, minmax(0, max-content)); gap: 5px; }
@media (max-width: 899px) { .nurse-chips { grid-template-columns: repeat(3, minmax(0, max-content)); } }
.tag-bulk-col { display: flex; flex-direction: column; gap: 2px; align-items: flex-start; }

/* nurse colour palette — index assigned in db.js (nurseColorIndex) */
.c0{--tag-bg:#f2e5ec;--tag-fg:#803d5e} .c1{--tag-bg:#e6efec;--tag-fg:#2f5e57}
.c2{--tag-bg:#efeae1;--tag-fg:#76582f} .c3{--tag-bg:#f0e8ea;--tag-fg:#7a3f49}
.c4{--tag-bg:#e9ecdf;--tag-fg:#4f5e32} .c5{--tag-bg:#e9e7ef;--tag-fg:#4c4470}
.c6{--tag-bg:#f1e9e3;--tag-fg:#7c4f36} .c7{--tag-bg:#e7ecef;--tag-fg:#44525a}

/* Bottom nav */
.bottomnav { position: fixed; bottom: 0; left: 0; right: 0; z-index: 6; display: flex; justify-content: space-around;
  align-items: center; background: var(--surface); border-top: 1px solid var(--border); padding: 6px 4px;
  padding-bottom: calc(6px + env(safe-area-inset-bottom)); box-shadow: 0 -2px 12px rgba(20, 18, 13, 0.06); }
.bottomnav button { background: none; border: none; color: var(--muted); display: flex; flex-direction: column;
  align-items: center; gap: 2px; font-size: 0.7rem; padding: 5px 14px; border-radius: 10px; font-weight: 400;
  transition: color 0.15s, background 0.15s; }
.bottomnav button:hover { background: var(--surface-2); }
.bottomnav button.on { color: var(--accent); background: var(--accent-bg); }
.bottomnav .fab { background: var(--accent); color: var(--on-accent); width: 50px; height: 50px; border-radius: 50%;
  margin-top: -16px; box-shadow: var(--shadow); display: flex; align-items: center; justify-content: center; gap: 8px; }
.bottomnav .fab .icon { width: 24px; height: 24px; }
/* Mobile "More" overflow: the everyday tabs stay in the bar; Follow-ups / Reports / Admin live in a
   popup above the More button, so the bar never over-fills. On desktop (side nav) this is undone. */
.nav-more-group { display: none; position: fixed; right: 8px; bottom: 66px; z-index: 7;
  flex-direction: column; gap: 2px; min-width: 168px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow-lg); }
.bottomnav.more-open .nav-more-group { display: flex; }
.nav-more-group button { flex-direction: row; justify-content: flex-start; gap: 12px; padding: 11px 14px; border-radius: 8px; font-size: 0.95rem; }
.navicon { font-size: 1.25rem; }

/* Agenda */
.agenda-row { display: flex; gap: 0.7rem; padding: 0.7rem 0.5rem; border-bottom: 1px solid var(--border);
  cursor: pointer; border-radius: 8px; transition: background 0.12s; }
.agenda-row:not(.urgent):hover { background: var(--surface-2); }
.agenda-row:last-child { border-bottom: none; }
.agenda-row .t { width: 46px; color: var(--muted); font-size: 0.85rem; flex-shrink: 0; }
.agenda-row .main { flex: 1; min-width: 0; }
.agenda-row .name { font-weight: 500; }
.agenda-row .sub { font-size: 0.82rem; color: var(--muted); }
.agenda-row.urgent { background: var(--warning-bg); border-radius: 8px; }
.agenda-row.urgent .t, .agenda-row.urgent .sub, .agenda-row.urgent .name { color: var(--warning); }

/* Queue cards */
.qcard { border: 1px solid var(--border); border-radius: var(--radius); padding: 0.75rem 0.85rem; display: flex; flex-direction: column; gap: 4px; background: var(--surface); box-shadow: var(--shadow-sm); }
.qcard.urgent { background: var(--warning-bg); border-color: color-mix(in srgb, var(--warning) 45%, var(--border)); }
/* Queue day cue: a card wanted for today (amber) or the next working day (green) so the day's work to
   place is obvious. Shared by the Queue screen (.qcard) and the day-view rail (.qmini). */
/* (The day cue now paints as an INSET shadow further down, so it can coexist with the group
   border instead of being overridden by it. These border rules are superseded.) */
.qcard .name { font-weight: 500; }
/* Tags live INSIDE .name here (unlike .qmini, where they get their own row), so they'd otherwise
   sit flush against the last letter of the name. Space them off the name, not off each other. */
.qcard .name > .tag { margin-left: 8px; vertical-align: middle; }
.qcard .sub { font-size: 0.82rem; color: var(--muted); }
.qcard .acts { display: flex; gap: 6px; margin-top: 4px; }

/* Gauge — native <progress>; value/max are data attributes, not inline style */
progress.gauge { width: 100%; height: 6px; border: none; border-radius: 3px;
  background: var(--surface-2); -webkit-appearance: none; appearance: none; }
progress.gauge::-webkit-progress-bar { background: var(--surface-2); border-radius: 3px; }
progress.gauge::-webkit-progress-value { background: var(--accent); border-radius: 3px; }
progress.gauge::-moz-progress-bar { background: var(--accent); border-radius: 3px; }

/* Month grid */
.month { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.month .dow { text-align: center; font-size: 0.72rem; color: var(--muted); font-weight: 500; padding-bottom: 2px; }
.month .cell { border: 1px solid var(--border); border-radius: 10px; padding: 6px 7px; min-height: 92px; background: var(--surface);
  cursor: pointer; display: flex; flex-direction: column; gap: 3px; box-shadow: var(--shadow-sm);
  transition: transform 0.08s, box-shadow 0.15s, border-color 0.15s; }
.month .cell:hover { box-shadow: var(--shadow); transform: translateY(-1px); border-color: var(--accent); }
.month .cell.empty { background: transparent; border-style: dashed; box-shadow: none; cursor: default; }
.month .cell.empty:hover { transform: none; box-shadow: none; border-color: var(--border); }
.month-head select { width: auto; font-weight: 500; }
.month .cell.has { background: var(--accent-bg); }
.month .cell.today { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.month .cell .d { font-size: 0.8rem; font-weight: 500; color: var(--text); }
.month .cell.empty .d { color: var(--muted); font-weight: 400; }
.month .cell .c { font-size: 0.7rem; color: var(--accent); background: var(--accent-bg); border-radius: 10px;
  padding: 1px 8px; align-self: flex-start; }
.mbk { border-left: 3px solid var(--border); padding-left: 5px; }
.mbk.st-scheduled { border-left-color: var(--warning); }
.mbk.st-confirmed { border-left-color: var(--info); }
.mbk-line { display: flex; align-items: center; gap: 4px; font-size: 0.66rem; }
.mbk-t { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mbk-sub { font-size: 0.6rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-left: 2px; }
.mdot { width: 8px; height: 8px; border-radius: 50%; background: var(--tag-fg, var(--muted)); flex-shrink: 0; }
.mmore { font-size: 0.6rem; color: var(--muted); }
.mcount { font-size: 0.72rem; }

/* Week view (7-day detail) */
.week { display: grid; grid-template-columns: repeat(7, minmax(124px, 1fr)); gap: 6px; overflow-x: auto; padding-bottom: 4px; }
.wk-col { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm); display: flex; flex-direction: column; }
.wk-col.today { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.wk-head { padding: 6px; text-align: center; border-bottom: 1px solid var(--border); cursor: pointer; }
.wk-head:hover { background: var(--surface-2); }
.wk-empty { text-align: center; padding: 10px 6px; }
.wk-item { padding: 5px 7px; border-bottom: 1px solid var(--border); border-left: 7px solid var(--border); cursor: pointer; }
.wk-item:last-child { border-bottom: none; }
.wk-item.st-scheduled { background: var(--warning-bg); }
.wk-item.st-confirmed { background: var(--info-bg); }
.wk-t { font-size: 0.72rem; font-weight: 500; }
.wk-s { font-size: 0.64rem; color: var(--muted); display: flex; align-items: flex-start; gap: 4px; }
.wk-s .mdot { margin-top: 3px; }

/* Modal */
.modal-bg { position: fixed; inset: 0; z-index: 10; background: rgba(0,0,0,0.45); display: flex; align-items: flex-end; justify-content: center; }
.modal { background: var(--surface); width: min(560px, 100%); max-height: 92dvh; overflow-y: auto;
  border-radius: 16px 16px 0 0; padding: 1rem 1.1rem calc(1.1rem + env(safe-area-inset-bottom)); box-shadow: var(--shadow-lg); }
/* Desktop: anchor the modal near the top (not vertically centred) so expanding a disclosure grows
   it DOWNWARD instead of re-centring the whole modal — the latter makes it jump "all over". */
@media (min-width: 600px) { .modal-bg { align-items: flex-start; padding: 4vh 0; } .modal { border-radius: 16px; } }
.modal .mhead { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 0.6rem; }
.modal .mhead h2 { font-size: 1.1rem; }
/* Click-to-edit patient name in the booking header (not-yet-reported bookings). */
.mhead-name-disp { cursor: pointer; display: inline-flex; align-items: baseline; gap: 5px; }
.mhead-name-pen { font-size: 0.68em; color: var(--muted); opacity: 0; transition: opacity 0.12s; }
.mhead-name-disp:hover .mhead-name-pen { opacity: 0.8; }
.mhead-name-input { font-family: var(--font-display); font-size: 1.1rem; font-weight: 600; color: var(--text);
  padding: 2px 8px; border: 1px solid var(--accent); border-radius: 8px; background: var(--surface); min-width: 14ch; max-width: 100%; }
.stepper { display: flex; align-items: center; gap: 8px; border: 1px solid var(--border); border-radius: var(--radius); padding: 0.3rem 0.5rem; }
.stepper button { background: none; border: none; color: var(--text); font-size: 1.2rem; padding: 0 8px; }
.stepper button:hover { background: none; }
.stepper .val { flex: 1; text-align: center; font-size: 0.9rem; white-space: nowrap; }
.status-flow { display: flex; gap: 5px; margin: 0.6rem 0; }
.status-flow .s { flex: 1; text-align: center; font-size: 0.72rem; padding: 5px 0; border-radius: 6px; background: var(--surface-2); color: var(--muted); cursor: pointer; }
.status-flow .s.on { background: var(--accent); color: var(--on-accent); }
.status-flow .s.auto { cursor: default; }              /* scheduled is automatic, not clickable */
.status-flow .s.disabled { opacity: 0.45; cursor: not-allowed; } /* confirm needs a scheduled item */

.toast { position: fixed; bottom: 86px; left: 50%; transform: translateX(-50%); z-index: 20;
  background: var(--text); color: var(--bg); padding: 0.5rem 0.9rem; border-radius: 20px; font-size: 0.85rem; }
.empty { text-align: center; color: var(--muted); padding: 1.5rem; }

/* helpers — keep presentational tweaks in CSS, not inline on elements */
.tac { text-align: center; }
.fw5 { font-weight: 500; }
.fs-sm { font-size: 0.82rem; }
.fs-xs { font-size: 0.72rem; }
/* Multi-line notes: preserve the booker's line breaks (paired with a tidy that caps blank lines). */
.note-pre { white-space: pre-line; overflow-wrap: anywhere; }
.self-center { align-self: center; }
.inactive { opacity: 0.6; }
.w-auto { width: auto; }
.flush { padding: 0.3rem 0.9rem; }
.check-row { gap: 8px; margin: 0.5rem 0; font-size: 0.85rem; }
.area-row { padding: 2px 0; }
.area-row > label { gap: 6px; }

/* address pull-out (native <details>, no JS) */
details.pullout { margin: 0.1rem 0; }
details.pullout > summary { cursor: pointer; color: var(--accent); font-size: 0.85rem; list-style: none; padding: 4px 0; }
details.pullout > summary::-webkit-details-marker { display: none; }
details.pullout[open] > summary { margin-bottom: 4px; }
details.pullout textarea { resize: vertical; }
/* Ease the revealed content in so a disclosure "moves to open" instead of snapping. */
details.pullout[open] > *:not(summary) { animation: pull-open 0.18s ease-out; }
@keyframes pull-open { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
@media (prefers-reduced-motion: reduce) { details.pullout[open] > *:not(summary) { animation: none; } }

/* action button rows (modal footers, call/whatsapp) */
.actions { display: flex; gap: 8px; margin-top: 0.8rem; }
.actions > button, .actions > a { flex: 1; }
.actions > .grow2 { flex: 2; }
.actions > .grow15 { flex: 1.4; }
.actions a { text-decoration: none; }
.actions a button { width: 100%; }

/* fab label only shows in the desktop side-nav */
.fab-label { display: none; }

/* ===== Day timeline + drag-and-drop ===== */
.day-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; }
/* Left cell holds the No-time bar + the scrolling calendar; min-width:0 lets the columns scroll
   inside their track instead of stretching the grid. */
.day-main { min-width: 0; }
.anybar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.admin-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.admin-key { display: inline-flex; align-items: center; gap: 5px; font-size: 0.78rem; }
.admin-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
.swatch { width: 24px; height: 24px; border-radius: 50%; cursor: pointer; border: 2px solid transparent; display: inline-block; }
.swatch.on { border-color: var(--text); }
.history { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }
.hist-row { border-left: 2px solid var(--border); padding-left: 8px; font-size: 0.82rem; }
.hist-changes { margin-top: 2px; }
.view-row { display: flex; justify-content: space-between; gap: 1rem; padding: 7px 0; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
.view-row:last-child { border-bottom: none; }
.view-row > span:last-child { text-align: right; }
.tscroll { max-height: 70vh; overflow-y: auto; -webkit-overflow-scrolling: touch; border-radius: var(--radius); }
.tgrid-wrap { display: flex; padding: 0; overflow: hidden; }
.tgutter { position: relative; width: 46px; flex-shrink: 0; }
.tlabel { position: absolute; right: 6px; transform: translateY(-50%); font-size: 0.7rem; color: var(--muted); }
.tgrid { position: relative; flex: 1; border-left: 1px solid var(--border); transition: background 0.12s; }
.tgrid.dragover { background: var(--accent-bg); }
.drop-ind { position: absolute; left: 0; right: 0; border-top: 2px solid var(--accent); z-index: 6; pointer-events: none; }
.drop-ind-t { position: absolute; left: 3px; top: -9px; background: var(--accent); color: var(--on-accent); font-size: 0.62rem;
  padding: 0 6px; border-radius: 8px; line-height: 1.5; }
.tline { position: absolute; left: 0; right: 0; border-top: 1px dashed var(--border); pointer-events: none; }
.tshade { position: absolute; left: 0; right: 0; background: var(--shade); pointer-events: none; z-index: 0; }
.tcard { position: absolute; background: var(--surface-2); border: 1px solid var(--border); border-left: 7px solid var(--side, var(--accent));
  border-radius: 6px; padding: 3px 7px; overflow: hidden; cursor: grab; box-shadow: var(--shadow-sm); line-height: 1.25; }
.tcard:active { cursor: grabbing; }
/* The side (left border) is the ASSIGNER's colour, held in --side: JS sets it per card (the one
   dynamic, per-person value), else it falls back to the status colour, else the accent. Status and
   nurse-reported OUTCOME only ever change the BACKGROUND — never the side. */
.tcard.st-scheduled { --side: var(--warning); background: var(--warning-bg); }
.tcard.st-confirmed { --side: var(--info); background: var(--info-bg); }
/* green = completed, pink = could-not-complete, dark red = visit over but nothing reported yet. */
.tcard.oc-done { background: var(--success-bg); }
.tcard.oc-missed { background: var(--missed-bg); }
.tcard.overdue { background: var(--overdue-bg); }
.tc-oc { font-size: 0.68rem; font-weight: 600; line-height: 1.2; }
.oc-done .tc-oc { color: var(--success); }
.oc-missed .tc-oc { color: var(--missed); }
.overdue .tc-oc { color: var(--overdue); }
.wk-item.oc-done { background: var(--success-bg); }
.wk-item.oc-missed { background: var(--missed-bg); }
/* Held (agreed time, no nurse) — same hatched-grey language as the day view's band, so "held"
   looks the same wherever it appears. Dashed left edge marks it as not yet staffed. */
.wk-item.held { border-left: 7px dashed var(--muted); color: var(--muted);
  background: repeating-linear-gradient(45deg, var(--surface-2), var(--surface-2) 5px, var(--bg) 5px, var(--bg) 10px); }
.mcount.mheld { color: var(--muted); font-weight: 600; }
/* Visit report block in the booking modal */
.visit-report { border: 1px solid var(--border); border-radius: 10px; padding: 8px 12px; margin: 6px 0 10px; }
.visit-report.vr-done { background: var(--success-bg); border-color: var(--success); }
.visit-report.vr-missed { background: var(--missed-bg); border-color: var(--missed); }
.visit-report button { margin-top: 6px; }
.rep-photos { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.rep-ph { width: 56px; height: 56px; object-fit: cover; border-radius: 8px; border: 1px solid var(--border); display: block; }
.offline-banner { background: var(--warning-bg); color: var(--warning); border: 1px solid var(--warning);
  border-radius: 10px; padding: 6px 12px; font-size: 0.82rem; font-weight: 500; }
/* Nurse editor: suburb list scrolls instead of growing the modal */
.area-scroll { max-height: 240px; overflow-y: auto; }
/* Save sits in the modal header beside the patient name; ✕ next to it. */
.mhead-btns { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.save-top { padding: 0.5rem 1.3rem; }
/* Mobile: Save stretches long; the ✕ gets a real finger-sized target. */
@media (max-width: 759px) {
  .modal .mhead { align-items: center; }
  .mhead-btns { flex: 1 1 auto; justify-content: flex-end; margin-left: 10px; }
  .save-top { flex: 1 1 auto; max-width: 230px; padding: 0.7rem 1rem; font-size: 1rem; }
  .mhead-btns .ghost.small { padding: 0.6rem 0.85rem; }
  .mhead-btns .ghost.small .icon { width: 20px; height: 20px; }
}
/* Modal action colours: Save = solid accent (default button); Cancel = red tint;
   Delete = solid red (destructive, gated behind cancel); Transfer = clay outline. */
/* Cancel stays quiet: red text only, neutral border — the tint appears on press/hover. */
button.btn-cancel { background: transparent; color: var(--danger); border-color: var(--border); }
button.btn-cancel:hover { background: var(--danger-bg); border-color: var(--danger); color: var(--danger); }
/* Quick-action row: Call/WhatsApp are the workhorses; "Cancel call" stays compact. */
.qa-cancel { flex: 0 0 auto; font-size: 0.78rem; padding: 0.4rem 0.8rem; }
@media (max-width: 759px) {
  .qa-contact { font-size: 0.95rem; padding: 0.65rem 0.5rem; }
}
button.btn-delete { background: var(--danger); border-color: var(--danger); color: var(--on-accent); }
button.btn-delete:hover { background: var(--danger); border-color: var(--danger); filter: brightness(1.08); }
button.btn-transfer { background: transparent; color: var(--clay); border-color: var(--clay); font-weight: 500; }
button.btn-transfer:hover { background: var(--warning-bg); color: var(--clay); border-color: var(--clay); }
/* Booking detail modal: two columns on desktop — fields left; actions/history right
   (Trello-style). Mobile stacks them; quick actions render at the top instead. */
.bcol-side .actions { margin-top: 0; }
.bcol-side > * { margin-bottom: 8px; }
.bcol-side .side-btn, .bcol-side .w-full { width: 100%; }
/* Both columns must be allowed to shrink below their content's min-content, or a non-wrapping
   child (e.g. the collapsed address summary, white-space:nowrap) floors the 1fr track and forces
   the whole modal to scroll sideways. With min-width:0 the track shrinks and the text ellipsises. */
.modal .bcol-main, .modal .bcol-side { min-width: 0; }
@media (min-width: 760px) {
  .modal.modal-detail { width: min(880px, 100%); }
  .modal-detail .bgrid { display: grid; grid-template-columns: 1fr 250px; gap: 0 20px; align-items: start; }
  .modal-detail .bcol-side { position: sticky; top: 0; display: flex; flex-direction: column; gap: 10px; }
  .bcol-side > * { margin-bottom: 0; }
  /* Desktop stacks Call/WhatsApp/Cancel vertically with real breathing room. */
  .bcol-side .actions.desk-only { display: flex; flex-direction: column; gap: 10px; align-items: stretch; }
  .bcol-side .side-btn, .bcol-side .qa-contact { padding: 0.62rem 0.8rem; }
  .bcol-side .qa-cancel { align-self: flex-start; }
  .bcol-side .pullout { margin-top: 2px; }
}
/* Booking modal redesign: denser fields + grouped sections + a schedule band on top. */
/* Inputs inherit font (theme.css), so an input's size depends on its parent — a .field label is
   0.82rem but the address field / other wrappers are 1rem. Pin one size so every modal input matches. */
.modal input, .modal select, .modal textarea { padding: 0.42rem 0.6rem; border-radius: 9px; font-size: 0.9rem; }
.modal label.field { font-size: 0.76rem; gap: 0.18rem; }
.bsec { font-size: 0.72rem; font-weight: 600; color: var(--muted); margin: 0.8rem 0 0.45rem;
  padding-bottom: 0.3rem; border-bottom: 1px solid var(--border); }
.grid3 { display: grid; grid-template-columns: 1.1fr 1fr 1.15fr; gap: 0.5rem; }
/* Native date input: the browser paints a fixed format hint (mm/dd/yyyy) PLUS a picker icon, and
   letters are wider than the digits of a real date — so the empty state clipped ("…subur"-style)
   in the narrow Date column even though a filled date fitted. Slightly smaller text + tighter side
   padding makes the hint, the date and the icon all fit without touching the other fields. */
.grid3 input[type="date"] { font-size: 0.82rem; padding-left: 0.45rem; padding-right: 0.3rem; }
.grid3 > * { min-width: 0; }   /* let native date/select inputs shrink instead of overflowing */
@media (max-width: 400px) { .grid3 { grid-template-columns: 1fr 1fr; } .grid3 > :last-child { grid-column: 1 / -1; } }
.sched-band { background: var(--accent-bg); border: 1px solid rgba(74,114,144,.22);
  border-radius: 12px; padding: 0.5rem 0.6rem 0.6rem; margin-bottom: 0.2rem; }
.sched-band.locked { background: var(--surface-2); border-color: var(--border); }
.sched-band .sched-lab { font-size: 0.7rem; font-weight: 500; color: var(--accent-strong); margin-bottom: 0.35rem; }
.sched-band.locked .sched-lab { color: var(--muted); }
.sched-band .sched-dur { margin-top: 0.5rem; }
/* Duration as an inline "label + control" row (not a lone box on the left); the control gets
   enough width that the text stays on one line. */
.sched-band .sched-dur .field { flex-direction: row; align-items: center; gap: 10px; max-width: none; }
.sched-band .sched-dur .stepper { flex: 1; max-width: 240px; }
/* "Show required tests" is a secondary action under the Tests field — small, and given room to
   breathe rather than pulled up against the input. */
button.tests-btn { margin: 8px 0 2px; padding: 0.28rem 0.6rem; font-size: 0.78rem; }
button.tests-btn .icon-sm { width: 13px; height: 13px; }
/* Keyboard-highlighted repeat-patient match (↓/↑), and the armed action (←/→) that Enter commits. */
.rp-row.active { border-color: var(--accent); background: var(--accent-bg); }
.rp-btns button.kb { box-shadow: 0 0 0 2px var(--accent); border-color: var(--accent); }
/* A repeat carries the rate but never the price — flag the blank cash price until it's dealt with.
   The field is empty, so the PLACEHOLDER has to carry the red, not the text colour. */
input.needs-price { border-color: var(--danger); background: var(--danger-bg); color: var(--danger); }
input.needs-price::placeholder { color: var(--danger); opacity: 0.85; }
/* Repeat-patient lookup at the top of a new request */
.rp-box { background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; padding: 8px 10px 9px; margin-bottom: 10px; }
.rp-lab { font-size: 0.72rem; font-weight: 500; color: var(--muted); margin-bottom: 5px; }
/* Cap the list so a run of matches scrolls here instead of stretching the whole modal. */
.rp-results { display: flex; flex-direction: column; gap: 6px; margin-top: 7px; max-height: 216px; overflow-y: auto; }
.rp-hint { padding: 1px 2px 0; }
.rp-row { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 9px; padding: 7px 9px; }
.rp-who { min-width: 0; }
/* name + tag on one line: the name takes the slack and ellipsises, the tag never shrinks away */
.rp-nameline { display: flex; align-items: center; gap: 6px; min-width: 0; }
.rp-nameline .rp-name { min-width: 0; flex: 0 1 auto; }
.tag.rp-canc-tag { flex: 0 0 auto; font-size: 0.68rem; padding: 1px 7px;
                   background: var(--surface-2); color: var(--muted); border: 1px solid var(--border); }
.rp-name { font-size: 0.85rem; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-btns { display: flex; gap: 6px; flex: 0 0 auto; }
button.rp-same { background: var(--accent-bg); color: var(--accent-strong); border-color: var(--accent); font-weight: 500; }
button.rp-same:hover { background: var(--accent-bg); border-color: var(--accent-strong); filter: brightness(0.98); }
@media (max-width: 460px) { .rp-row { flex-direction: column; align-items: stretch; gap: 7px; } .rp-btns > button { flex: 1; } }
/* Tube types editor (Settings) */
.tt-list { display: flex; flex-direction: column; gap: 6px; }
.tt-row { display: flex; align-items: center; gap: 6px; }
.tt-row input { flex: 1; min-width: 0; }
.tt-row > button { flex: 0 0 auto; }
.tt-off { opacity: 0.65; justify-content: space-between; }
.tt-add { display: flex; gap: 6px; margin-top: 10px; }
.tt-add input { flex: 1; min-width: 0; }
/* Per-type tube counts on a visit report (office side) */
.tube-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 6px 12px; }
.tube-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.tube-row .tube-name { font-size: 0.82rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Your name in the topbar opens "change password" — hint that it's clickable. */
#who:hover { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
/* Notes is a roomy multi-line field, not a cramped one-liner. */
.notes-ta { resize: vertical; min-height: 44px; line-height: 1.4; }
/* Billing lives in the side column for both new + existing — a card there. */
.bcol-side .bill-block { background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 12px; padding: 0.55rem 0.7rem 0.7rem; }
.bcol-side .bill-block .bsec { margin-top: 0; }
/* New request also goes two-column on desktop (Preference/Billing/Notes on the right) so it isn't
   one long scroll; below the breakpoint it stacks to a single column like before. */
@media (min-width: 760px) {
  .modal.modal-form { width: min(780px, 100%); }
  .modal-form .bgrid { display: grid; grid-template-columns: 1fr 300px; gap: 0 22px; align-items: start; }
  .modal-form .bcol-side { display: flex; flex-direction: column; gap: 10px; }
  .modal-form .bcol-side > * { margin-bottom: 0; }
}
/* ---- Compact modal: label-LEFT field rows ---- */
/* A .field row with its label beside the control (not stacked above it). One line per field. */
.modal label.field.fh { flex-direction: row; align-items: center; gap: 10px; margin-bottom: 8px; }
.modal label.field.fh > .lbl { flex: 0 0 auto; width: 92px; font-size: 0.76rem; color: var(--muted); }
.modal label.field.fh > input, .modal label.field.fh > select,
.modal label.field.fh > .combo, .modal label.field.fh > .addr-field { flex: 1 1 auto; min-width: 0; }
/* In a 2-col grid the labels are short — give them just their content width, and let the grid gap
   carry the vertical spacing instead of a per-row margin. */
.grid2 label.field.fh { margin-bottom: 0; }
.grid2 label.field.fh > .lbl { width: auto; min-width: 46px; }
/* Below the narrow breakpoint, drop back to label-on-top so nothing gets squeezed on a phone. */
@media (max-width: 520px) {
  .modal label.field.fh { flex-direction: column; align-items: stretch; gap: 0.18rem; }
  .modal label.field.fh > .lbl { width: auto; }
}
/* Address stays a normal 1-line field now (the placeholder carries the guidance) — drop the hint. */
.modal .addr-hint { display: none; }
.addr-expanded .field.fh:first-child { margin-bottom: 8px; }
/* Existing booking: address collapsed to a one-line summary with an "edit" affordance. */
.addr-collapsed { display: flex; align-items: center; gap: 8px; justify-content: space-between;
  flex: 1 1 auto; min-width: 0; background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 9px; padding: 0.42rem 0.6rem; font-size: 0.86rem; }
.addr-collapsed .txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.addr-collapsed .edit-link, .edit-link { flex: 0 0 auto; background: none; border: none; padding: 0;
  color: var(--accent); font-size: 0.8rem; font-weight: 600; text-decoration: underline; cursor: pointer; }
.addr-collapsed .edit-link:hover { background: none; }
/* Referral row: Referring Dr gets the width; Fasting sits beside it, vertically centred. */
.ref-grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: 0.6rem; align-items: center; }
.ref-grid > * { min-width: 0; }
.ref-grid .check-row { margin: 0; }
/* Tests: label + "Show tests" on one line, then a 2-row textarea. */
.tests-hdr { display: flex; align-items: center; justify-content: space-between; margin: 0.5rem 0 0.3rem; }
.tests-hdr .lbl { font-size: 0.76rem; color: var(--muted); }
button.tests-link { background: none; border: none; padding: 0; color: var(--accent); font-weight: 600;
  font-size: 0.78rem; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; }
button.tests-link:hover { background: none; text-decoration: underline; }
button.tests-link .icon-sm { width: 13px; height: 13px; }
.tests-ta { resize: vertical; min-height: 40px; line-height: 1.35; }
.tests-hdr-actions { display: inline-flex; align-items: center; gap: 14px; flex-wrap: wrap; justify-content: flex-end; }
/* Attached form shown large: beside the tests on a wide screen, stacked above on a narrow one. */
.tests-body { display: flex; gap: 10px; align-items: flex-start; }
.tests-body .tests-ta { flex: 1 1 auto; min-width: 0; }
.tests-img-wrap { position: relative; flex: 0 0 auto; }
.tests-img { display: block; max-width: 260px; max-height: 340px; width: auto; height: auto; border: 1px solid var(--border); border-radius: 8px; cursor: zoom-in; }
.tests-pdf { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--border); border-radius: 8px; padding: 9px 12px; background: var(--surface-2); color: var(--text); cursor: pointer; font-size: 0.82rem; }
.tests-img-x { position: absolute; top: -8px; right: -8px; width: 22px; height: 22px; border-radius: 50%; border: 1px solid var(--border); background: var(--surface); color: var(--text); cursor: pointer; font-size: 15px; line-height: 1; display: flex; align-items: center; justify-content: center; }
@media (max-width: 640px) { .tests-body { flex-direction: column; } .tests-img, .tests-img-wrap { max-width: 100%; width: 100%; } }
/* Import-from-quote review modal */
.ingest-modal { max-width: 560px; }
.ingest-summary { margin: 0 0 0.5rem; }
.ingest-list { max-height: 52vh; overflow-y: auto; border: 1px solid var(--border); border-radius: 10px; }
.ingest-row { display: flex; align-items: flex-start; gap: 8px; padding: 7px 9px; border-bottom: 1px solid var(--border); }
.ingest-row:last-child { border-bottom: none; }
.ingest-row.excluded { opacity: 0.45; }
.ingest-inc { flex: 0 0 auto; padding-top: 2px; }
.ingest-inc input { width: auto; margin: 0; }
.ingest-mid { flex: 1 1 auto; min-width: 0; }
.ingest-name { font-size: 0.83rem; font-weight: 600; color: var(--text); word-break: break-word; }
.ingest-ctl { display: flex; align-items: center; gap: 6px; margin-top: 4px; }
.ingest-sel { flex: 1 1 auto; min-width: 0; padding: 0.3rem 0.4rem; font-size: 0.8rem; }
.ingest-del { flex: 0 0 auto; align-self: center; background: none; border: none; color: var(--muted);
  font-size: 1.2rem; line-height: 1; cursor: pointer; padding: 2px 7px; border-radius: 6px; }
.ingest-del:hover { color: var(--danger, #dc2626); background: color-mix(in srgb, var(--danger, #dc2626) 12%, transparent); }
.ingest-tag { flex: 0 0 auto; font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
  padding: 2px 6px; border-radius: 999px; align-self: center; }
.ingest-tag.ok { background: color-mix(in srgb, var(--ok, #16a34a) 16%, transparent); color: var(--ok, #16a34a); }
.ingest-tag.mapped { background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); }
.ingest-tag.suggest { background: color-mix(in srgb, var(--warn, #d97706) 18%, transparent); color: var(--warn, #d97706); }
.ingest-tag.typed { background: var(--surface-2); color: var(--muted); }
/* A suggested row gets a faint amber cue so "confirm me" rows are scannable in the list. */
.ingest-row.is-suggested { box-shadow: inset 3px 0 0 color-mix(in srgb, var(--warn, #d97706) 55%, transparent); }
.ingest-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 0.7rem; flex-wrap: wrap; }
.ingest-count { font-size: 0.82rem; color: var(--text); white-space: nowrap; }
.ingest-btns { display: flex; gap: 8px; }
/* Actions in the header (top-right) so the tall preview never pushes them below the fold. */
.ingest-head { align-items: flex-start; gap: 12px; }
.ingest-head-title { min-width: 0; }
.ingest-head-actions { display: flex; align-items: center; gap: 12px; margin-left: auto; flex-wrap: wrap; justify-content: flex-end; }
.ingest-banner { background: color-mix(in srgb, var(--warn, #d97706) 14%, transparent); color: var(--text);
  border: 1px solid color-mix(in srgb, var(--warn, #d97706) 35%, transparent); border-radius: 8px;
  padding: 0.5rem 0.65rem; font-size: 0.8rem; margin-bottom: 0.5rem; }
.ingest-id { margin-bottom: 0.5rem; }
.ingest-id-line { font-size: 0.78rem; color: var(--muted); display: flex; align-items: center; gap: 5px; }
.ingest-id-line .icon-sm { width: 13px; height: 13px; flex: 0 0 auto; }
.ingest-prior { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; padding: 0.45rem 0.6rem; margin-top: 0.4rem; }
.ingest-prior .fw6 { font-size: 0.84rem; }
.ingest-add { display: flex; gap: 6px; margin-top: 0.5rem; }
.ingest-add-in { flex: 1 1 auto; padding: 0.4rem 0.5rem; font-size: 0.82rem; }
/* Two-column layout when the file preview is shown (tablet/desktop). The modal goes near-full-width
   and the PDF takes the majority of the room (the list is a fixed, comfortable column). */
.ingest-cols { display: flex; gap: 16px; align-items: flex-start; }
.ingest-main { flex: 1 1 0; min-width: 0; }
.ingest-modal.has-preview { width: 96vw; max-width: 1500px; }
.has-preview .ingest-main { flex: 0 0 380px; }
.has-preview .ingest-list { max-height: 74vh; }
.ingest-preview { flex: 1 1 0; min-width: 0; max-height: 80vh; overflow: auto; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 10px; padding: 8px; }
.has-preview .ingest-preview { max-height: 80vh; }
.pv-bar { position: sticky; top: -8px; z-index: 3; display: flex; align-items: center; gap: 6px; justify-content: center;
  padding: 4px 0 8px; margin: -8px -8px 4px; background: var(--surface-2); }
.pv-bar .ghost.small { padding: 3px 12px; font-size: 1rem; line-height: 1; }
.pv-zval { font-size: 0.78rem; color: var(--muted); min-width: 46px; text-align: center; }
.pv-pages { width: 100%; margin: 0 auto; }
.pv-page { position: relative; margin: 0 auto 10px; line-height: 0; box-shadow: 0 1px 4px rgba(0,0,0,0.18); }
.pv-page:last-child { margin-bottom: 0; }
.pv-canvas { display: block; width: 100%; height: auto; border-radius: 2px; }
.pv-img { display: block; width: 100%; height: auto; border-radius: 2px; }
/* "Needs attention" strip on the day view — fell-through past visits to resolve. */
.attn-box { margin: 8px 0; border: 1px solid color-mix(in srgb, var(--warn, #d97706) 45%, transparent);
  border-radius: 10px; background: color-mix(in srgb, var(--warn, #d97706) 8%, transparent); padding: 6px 7px; }
.attn-head { font-size: 0.82rem; font-weight: 700; color: var(--warn, #d97706); }
.attn-hint { margin: 1px 0 3px; }
.attn-card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 5px 7px; margin-top: 4px; }
.attn-card.click { cursor: pointer; }
.attn-card.click:hover { border-color: color-mix(in srgb, var(--warn, #d97706) 45%, var(--border)); }
.attn-line { font-size: 0.8rem; line-height: 1.25; }
.attn-name { font-weight: 600; color: var(--text); }
.attn-meta { font-size: 0.75rem; }
.attn-acts { display: flex; gap: 4px; margin-top: 5px; }
.attn-act { flex: 1 1 0; min-width: 0; text-align: center; white-space: nowrap;
  padding: 3px 2px; font-size: 0.68rem; font-weight: 600; border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface-2); color: var(--text); cursor: pointer; }
.attn-act:hover { border-color: color-mix(in srgb, var(--warn, #d97706) 55%, transparent); background: color-mix(in srgb, var(--warn, #d97706) 10%, transparent); }
.attn-act.danger:hover { border-color: color-mix(in srgb, var(--danger, #dc2626) 55%, transparent); background: color-mix(in srgb, var(--danger, #dc2626) 10%, transparent); }
/* Overdue-in-queue strip — same layout as needs-attention, blue-grey (overdue, not a crisis). */
.attn-box.od-box { border-color: color-mix(in srgb, var(--od, #64748b) 40%, transparent); background: color-mix(in srgb, var(--od, #64748b) 8%, transparent); }
.attn-box.od-box .attn-head { color: color-mix(in srgb, var(--od, #64748b) 92%, var(--text)); }
.attn-box.od-box .attn-card.click:hover { border-color: color-mix(in srgb, var(--od, #64748b) 45%, var(--border)); }
.attn-box.od-box .attn-act:hover { border-color: color-mix(in srgb, var(--od, #64748b) 55%, transparent); background: color-mix(in srgb, var(--od, #64748b) 12%, transparent); }
.attn-box.od-box .attn-card { cursor: grab; }
.attn-card.placing { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.attn-card.dragging { opacity: 0.5; }
.attn-card .qmini-hint { margin-top: 5px; }
.attn-head.clickable { cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.attn-chev { font-size: 0.7rem; }
.pv-layer { position: absolute; inset: 0; }
.pv-box { position: absolute; border: 1.5px solid transparent; border-radius: 3px; cursor: pointer; transition: background 0.1s; }
.pv-box:hover, .pv-box.hot { background: color-mix(in srgb, var(--accent) 24%, transparent); border-color: var(--accent); }
.ingest-row.locatable { cursor: pointer; }
.ingest-row.hot { background: color-mix(in srgb, var(--accent) 13%, transparent); }
@media (max-width: 899px) { .ingest-preview { display: none; } }
/* Follow-up: a numeric-only card (months ≥ 1 = active). No checkbox. */
.fu-card { background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; padding: 0.55rem 0.7rem; }
.fu-card .fu { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 0.82rem; color: var(--text); }
.modal .fu-card .fu-num { width: 54px; text-align: center; padding: 0.3rem 0.35rem; font-size: 0.85rem; }
.fu-card .fu-note { margin: 5px 0 0; }
/* Report action pair (Edit visit report · Reopen visit) once a visit is reported. */
.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.pair > * { margin: 0; width: 100%; }
.pair .side-btn { width: 100%; font-size: 0.8rem; }
/* Boot splash + list skeletons — shown only while loading, replaced the instant data paints. */
.boot-brand { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.boot-word { font-family: var(--font-display); font-size: 30px; font-weight: 600; letter-spacing: -0.5px; color: var(--text); }
.boot-word span { color: var(--accent); }
.boot-sub { font-size: 12px; letter-spacing: 2px; text-transform: uppercase; color: var(--muted); animation: boot-pulse 1.6s infinite ease-in-out; }
.boot-bar { position: relative; width: 150px; height: 3px; background: var(--border); border-radius: 3px; overflow: hidden; }
.boot-bar > span { position: absolute; top: 0; height: 100%; width: 40%; background: var(--accent); border-radius: 3px; animation: boot-sweep 1.2s infinite ease-in-out; }
@keyframes boot-pulse { 0%, 100% { opacity: 0.45; } 50% { opacity: 1; } }
@keyframes boot-sweep { 0% { left: -42%; } 100% { left: 100%; } }
/* In-app loading: a thin indeterminate bar at the top of the content (content paints beneath it). */
.loadbar { position: relative; height: 3px; background: var(--accent-bg); border-radius: 3px; overflow: hidden; margin-top: 2px; }
.loadbar > span { position: absolute; top: 0; height: 100%; width: 35%; background: var(--accent); border-radius: 3px; animation: loadbar-sweep 1.1s infinite ease-in-out; }
@keyframes loadbar-sweep { 0% { left: -35%; } 100% { left: 100%; } }
@media (prefers-reduced-motion: reduce) { .boot-sub, .boot-bar > span { animation: none; } .loadbar > span { animation: none; width: 100%; opacity: 0.55; } .scan-ring { animation: none; } }
/* Full-screen wait while a form scan runs (GPT-4o takes a few seconds). */
.scan-overlay { position: fixed; inset: 0; z-index: 1200; display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg, #000) 55%, transparent); backdrop-filter: blur(2px); }
.scan-card { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 26px 34px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 16px; box-shadow: 0 12px 40px rgba(0,0,0,0.28); }
.scan-ring { width: 44px; height: 44px; border-radius: 50%; border: 3px solid var(--accent-bg, var(--border));
  border-top-color: var(--accent); animation: scan-spin 0.8s linear infinite; }
.scan-word { font-family: var(--font-display); font-size: 22px; font-weight: 600; letter-spacing: -0.4px; color: var(--text); }
.scan-word span { color: var(--accent); }
.scan-msg { text-align: center; }
@keyframes scan-spin { to { transform: rotate(360deg); } }
/* Required-tests popup */
.tp-group { margin: 10px 0; }
.tp-tests { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 5px; }
.tp-chip { background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; padding: 3px 11px; font-size: 0.82rem; }
.tp-chip.tp-dup { background: transparent; border-style: dashed; color: var(--muted); }
.tp-dup-note { font-size: 0.7rem; opacity: 0.8; }
.tp-warn { background: var(--warning-bg); color: var(--warning); border-radius: 8px; padding: 6px 10px; font-size: 0.8rem; margin-bottom: 8px; }
button.btn-report { background: var(--accent-bg); color: var(--accent-strong); border-color: var(--accent); font-weight: 500; }
button.btn-report:hover { background: var(--accent-bg); border-color: var(--accent-strong); filter: brightness(0.98); }
/* Office visit-report sheet: Done / Could-not-complete toggle */
.seg2 { display: flex; gap: 8px; margin: 12px 0; }
.seg2b { flex: 1; padding: 12px 0; border-radius: 10px; border: 1px solid var(--border);
  background: var(--surface-2); color: var(--muted); font-weight: 600; }
.seg2b:hover { background: var(--surface-2); border-color: var(--border); color: var(--text); }
.seg2b.on, .seg2b.on:hover { background: var(--success); border-color: var(--success); color: var(--on-accent); }
.seg2b.on-miss, .seg2b.on-miss:hover { background: var(--missed); border-color: var(--missed); color: var(--on-accent); }
/* Same breakpoint as the modal's two-column switch: on narrow screens the Transfer button sits
   under the status flow; on wide screens it lives in the side column instead. */
.desk-only { display: none; }
@media (min-width: 760px) {
  .mob-only { display: none; }
  .desk-only { display: block; }
}
.bcol-main .side-btn { width: 100%; margin: 4px 0 8px; }
/* Compact day nav — a slim card at the TOP RIGHT of the day view; the nurse chips fill the
   rest of that first row. On mobile the two stack (date first, full width). */
.daynav { display: flex; align-items: center; gap: 4px; }
.daynav-mid { flex: 1; text-align: center; line-height: 1.25; min-width: 0; }
.daynav-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 10px 8px; box-shadow: var(--shadow-sm); flex: 0 0 auto; }
/* Desktop: EXACTLY the queue rail's width (day-grid right column = 280px) so they line up.
   width + min/max pin it — flex min-content sizing must not let the text push it wider. */
@media (min-width: 900px) {
  .daynav-card { flex: 0 0 280px; width: 280px; min-width: 280px; max-width: 280px; }
  .day-top { gap: 1rem; }   /* same gap as .day-grid, so the card's left edge matches the rail */
}
.daynav-mid .fw5 { font-size: 1rem; white-space: nowrap; text-decoration: underline dotted; text-underline-offset: 3px; }
.daynav-mid { cursor: pointer; }   /* tapping the date jumps back to today */
.daynav-hint { font-size: 0.62rem; line-height: 1.1; }
/* Day header. Desktop: nurse config (chips + legend) left, date card right — switcher and
   toggle hidden. Mobile: date card, then the scrollable one-row nurse switcher, then the
   "Nurse columns" disclosure; the config itself is folded away until toggled. */
.day-top { display: flex; align-items: flex-start; gap: 10px; }
.day-top .nurse-config { flex: 1; min-width: 0; }
.nurse-config .admin-legend { margin-top: 8px; }
.nurse-switch, .nurse-cfg-toggle { display: none; }
@media (max-width: 899px) {
  .day-top { flex-direction: column; align-items: stretch; gap: 8px; }
  .daynav-card { order: 1; }
  .nurse-switch { order: 2; display: flex; flex-wrap: nowrap; gap: 5px; overflow-x: auto;
    padding-bottom: 3px; -webkit-overflow-scrolling: touch; }
  .nurse-switch .chip { flex: 0 0 auto; }
  .nurse-cfg-toggle { order: 3; display: flex; justify-content: space-between; align-items: center;
    width: 100%; font-size: 0.8rem; padding: 8px 12px; }
  .nurse-config { order: 4; display: none; }
  .nurse-config.open { display: block; }
}
/* Synced horizontal scrollbar above the diary columns */
.tscroll-proxy { overflow-x: auto; overflow-y: hidden; height: 14px; margin-bottom: 2px; }
.tscroll-proxy > div { height: 1px; }
/* Transfer picker — one big touch row per nurse (mobile-first) */
.tr-row { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; width: 100%;
  padding: 10px 12px; margin-bottom: 8px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--surface); color: var(--text); text-align: left; cursor: pointer; }
.tr-row:hover { background: var(--surface-2); }
.tr-row.tr-disabled { cursor: default; }
.tr-row.tr-disabled > .tr-line .tr-name, .tr-row.tr-disabled > .tr-sub { opacity: 0.45; }
.tr-line { display: flex; align-items: center; justify-content: space-between; width: 100%; gap: 8px; }
.tr-diary { flex: 0 0 auto; }
.tr-row .tr-sub { font-size: 0.78rem; color: var(--muted); font-weight: 400; }
.tr-free { border-left: 5px solid var(--success); }
.tr-squeeze { border-left: 5px solid var(--warning); }
.tr-busy { border-left: 5px solid var(--border); }
.tcard.urgent { outline: 1px solid var(--clay); }
.tcard.dragging { opacity: 0.45; box-shadow: var(--shadow-lg); }
.tc-confirm { position: absolute; top: 3px; right: 3px; width: 19px; height: 19px; padding: 0; border-radius: 50%;
  font-size: 0.72rem; line-height: 1; background: var(--info); border-color: var(--info); color: var(--on-accent); }
.tc-confirm:hover { background: var(--info); border-color: var(--info); filter: brightness(1.05); }

/* Desktop resource columns (All + each nurse) */
.tcols-wrap { overflow: auto; max-height: 72vh; border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm); }
.tcols { display: flex; min-width: 100%; }
.tcol { display: flex; flex-direction: column; flex: 1 0 215px; border-left: 1px solid var(--border); }
.tcol:first-child { border-left: none; }
.tcol-gutter { position: sticky; left: 0; z-index: 4; background: var(--surface); flex: 0 0 46px; }
.tcol .tgrid { flex: 1; border-left: none; }
.tcol-head { position: sticky; top: 0; z-index: 2; background: var(--surface); border-bottom: 1px solid var(--border);
  padding: 4px 8px; height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center;
  font-size: 0.8rem; font-weight: 500; text-align: center; }
/* Schedule-acknowledgement status chip under the nurse's name (today/tomorrow). Empty on other days. */
.tcol-ack { margin-top: 3px; }
.tcol-ack:empty { display: none; }
.ackchip { display: inline-block; font-size: 0.6rem; font-weight: 700; padding: 1px 6px; border-radius: 99px; white-space: nowrap; }
/* Seen = the "all good" state — deliberately quiet (transparent, faded) so only the actionable
   "not seen" / "amended" chips draw the eye. */
.ackchip.seen { background: transparent; color: var(--muted); opacity: 0.55; font-weight: 600; }
.ackchip.not { background: var(--overdue-bg); color: var(--overdue); }
.ackchip.amend { background: var(--warning-bg); color: var(--warning); }
/* ---- Weekly nurse summary report ---- */
.nsum-wrap { overflow-x: auto; }
.nsum { border-collapse: collapse; width: 100%; min-width: 860px; font-size: 0.86rem; }
.nsum thead .grp th { font-size: 0.62rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); font-weight: 700; padding: 8px 9px 2px; text-align: center; }
.nsum thead .grp th.gcalls { color: var(--accent-strong); }
.nsum thead .grp th.gpay { color: var(--clay); }
.nsum thead .cols th { font-size: 0.72rem; font-weight: 600; color: var(--muted); padding: 2px 9px 8px; border-bottom: 2px solid var(--border); text-align: right; white-space: nowrap; }
.nsum thead .cols th.name { text-align: left; }
.nsum tbody td { padding: 8px 9px; border-bottom: 1px solid var(--border); text-align: right; font-variant-numeric: tabular-nums; }
.nsum tbody td.name { text-align: left; font-weight: 600; white-space: nowrap; }
.nsum .ndot { display: inline-block; width: 9px; height: 9px; border-radius: 99px; margin-right: 7px; background: var(--tag-fg, var(--accent)); }
.nsum td.sep, .nsum th.sep { border-left: 1px solid var(--border); }
.nsum .nmiss { color: var(--missed); font-weight: 700; }
.nsum .nzero { color: var(--muted); opacity: 0.45; }
.nsum .nrate { font-size: 0.7rem; color: var(--muted); font-weight: 400; }
.nsum tbody tr:hover { background: var(--surface-2); }
.nsum tfoot td { padding: 10px 9px; border-top: 2px solid var(--border); text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; background: var(--surface-2); }
.nsum tfoot td.name { text-align: left; }
.tcol-head.c0, .tcol-head.c1, .tcol-head.c2, .tcol-head.c3,
.tcol-head.c4, .tcol-head.c5, .tcol-head.c6, .tcol-head.c7 { background: var(--tag-bg); color: var(--tag-fg); }
.tcol-head.clickable { cursor: pointer; }
.tcol-head.clickable:hover { filter: brightness(0.96); }
.tcol-name { font-size: 0.92rem; line-height: 1.15; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tcol-sub { font-size: 0.66rem; font-weight: 400; line-height: 1.2; opacity: 0.85; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* clickable list cards (queue, nurses) */
.card.click, .qcard.click { cursor: pointer; }
.card.click:hover, .qcard.click:hover { background: var(--surface-2); }
.qcard { position: relative; }
.qcard.click { padding-right: 32px; }

/* single-column day heading (nurse name / All) */
.single-head { padding: 7px 10px; font-weight: 500; text-align: center; background: var(--surface);
  border: 1px solid var(--border); border-bottom: none; border-radius: var(--radius) var(--radius) 0 0; }
.single-head.c0, .single-head.c1, .single-head.c2, .single-head.c3,
.single-head.c4, .single-head.c5, .single-head.c6, .single-head.c7 { background: var(--tag-bg); color: var(--tag-fg); border-color: transparent; }
.single-head + .tscroll .tgrid-wrap { border-top-left-radius: 0; border-top-right-radius: 0; }
/* Card text flows as one wrapping block: name and number stay whole (nowrap spans), the
   suburb · Dr · price detail continues inline and wraps wherever it needs to. */
.tc-flow { font-size: 0.72rem; line-height: 1.3; overflow: hidden; }
.tc-name { font-weight: 500; white-space: nowrap; }
.tc-mob { font-weight: 400; font-size: 0.66rem; color: var(--muted); white-space: nowrap; }
.tc-sub { font-size: 0.7rem; color: var(--muted); }
.tcard .tag { font-size: 0.66rem; }
.tc-resize { position: absolute; left: 0; right: 0; bottom: 0; height: 9px; cursor: ns-resize; touch-action: none; }

/* Queue rail: a card above the day columns on mobile (so you can pick a request, then scroll
   to a slot and tap to place it); becomes a sticky side-column on desktop (≥900px). */
.queue-rail { display: block; order: -1; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 1rem; box-shadow: var(--shadow-sm); margin-bottom: 12px;
  transition: background 0.12s, border-color 0.12s; }
.queue-rail.dragover { background: var(--accent-bg); border-color: var(--accent); }
.rail-head { display: flex; justify-content: space-between; align-items: center; font-weight: 500; margin-bottom: 8px; }
.rail-hint { margin-top: 8px; }
.rail-hint-top { margin-top: 0; margin-bottom: 10px; }
/* Mobile: the drag/keyboard hint is desktop advice. q-mini = collapsed rail (empty queue,
   user-collapsed, or auto-collapsed while placing) — one slim row so the calendar shows. */
.q-count { background: var(--accent); color: var(--on-accent); border-radius: 999px; padding: 1px 10px;
  font-size: 0.85rem; font-weight: 600; min-width: 30px; text-align: center; }
.q-count.q-zero { background: var(--surface-2); color: var(--muted); }
.rail-chev { margin-left: 4px; }
@media (min-width: 900px) { .rail-chev { display: none; } .queue-rail .rail-head { cursor: default; } }
@media (max-width: 899px) {
  .rail-hint-top { display: none; }
  /* Big finger targets: the whole header row toggles, ≥44px tall, with a larger chevron. */
  .queue-rail .rail-head { cursor: pointer; min-height: 44px; align-items: center; justify-content: flex-start; gap: 10px; }
  .rail-chev { font-size: 1.05rem; padding: 4px 10px; margin-left: auto; }
  .queue-rail.q-mini { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; padding: 8px 14px; min-height: 60px; }
  .queue-rail.q-mini .rail-head { margin: 0; flex: 1; display: flex; align-items: center; gap: 10px; }
  .queue-rail.q-mini .rail-add { width: auto; margin: 0; padding: 9px 16px; font-size: 0.9rem; }
  .queue-rail.q-mini .q-empty, .queue-rail.q-mini .qmini, .queue-rail.q-mini .later-head, .queue-rail.q-mini .queue-band-head { display: none; }
}
.rail-hint kbd { font-family: var(--font-sans); font-size: 0.7rem; padding: 0 5px; border: 1px solid var(--border);
  border-bottom-width: 2px; border-radius: 4px; background: var(--surface); color: var(--text); }
.qmini { position: relative; background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
  padding: 8px; margin-bottom: 6px; cursor: grab; box-shadow: var(--shadow-sm); }
.qmini:active { cursor: grabbing; }
.qmini.dragging { opacity: 0.45; box-shadow: var(--shadow-lg); }
.qmini.placing { outline: 2px solid var(--accent); outline-offset: 1px; }
.qmini .name { font-weight: 500; font-size: 0.88rem; }
.q-mob { font-weight: 600; font-size: 0.8rem; color: var(--text); white-space: nowrap; }
.qmini .sub { font-size: 0.76rem; color: var(--muted); }
.qmini .tag { margin-top: 4px; display: inline-block; }
/* Card actions row (Place + delete), top-right. */
.qmini-actions { display: flex; justify-content: flex-end; align-items: center; gap: 6px; margin-bottom: 4px; }
/* Mobile: actions become a right-hand column (Place above Delete) beside the details, instead
   of their own row above — the card gets shorter and the text keeps full width below. */
@media (max-width: 899px) {
  .qmini { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 10px; align-items: start; }
  .qmini > * { grid-column: 1; }
  .qmini > .qmini-actions { grid-column: 2; grid-row: 1 / span 9; flex-direction: column; align-items: stretch; gap: 8px; margin: 0; }
  .qmini-actions .qmini-place { justify-content: center; }
  .qmini-actions .qmini-del { width: 100%; height: 32px; }
}
.qmini-place { display: inline-flex; align-items: center; gap: 5px; padding: 4px 10px; font-size: 0.8rem; font-weight: 500;
  background: var(--accent-bg); color: var(--accent); border: 1px solid var(--accent); border-radius: 8px; }
.qmini-place .icon { width: 17px; height: 17px; }
.qmini-place.on { background: var(--accent); color: var(--on-accent); }
.qmini-del { width: 28px; height: 28px; padding: 0; display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--border); border-radius: 8px; color: var(--muted); }
.qmini-del:hover { color: var(--danger); background: var(--danger-bg); border-color: var(--danger); }
/* Inline "tap a slot" hint shown on the selected card (no page-level layout shift). */
.qmini-hint { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 8px;
  padding-top: 8px; border-top: 1px dashed var(--border); font-size: 0.8rem; color: var(--accent); font-weight: 500; }
.rail-add { width: 100%; margin-bottom: 10px; display: inline-flex; align-items: center; justify-content: center; gap: 6px; }

/* search */
.search-results { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; max-height: 56vh; overflow-y: auto; }
.search-results .qcard { cursor: pointer; }

/* A held slot (agreed time, no nurse) shown in a free nurse's column. pointer-events:none is
   LOAD-BEARING: the tap must reach the grid underneath so placing still works right on top of the
   band — and lands at the band's own time. It signposts; it is never a button. */
.tres { position: absolute; border-radius: 6px; pointer-events: none; overflow: hidden;
  border: 1px dashed var(--muted); color: var(--muted);
  background: repeating-linear-gradient(45deg, var(--surface-2), var(--surface-2) 5px, var(--bg) 5px, var(--bg) 10px);
  padding: 2px 5px; font-size: 0.7rem; font-weight: 500; }
.tres-n { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Gutter marker for a held slot; red = no diary on screen is free across it. */
/* Juts out of the 46px gutter over the calendar so it reads as a tab rather than vanishing into
   the margin. The gutter is sticky at z-index 4, so it paints above the columns and stays put
   while they scroll sideways underneath. */
.thold { position: absolute; left: 3px; right: -14px; display: flex; flex-direction: column; align-items: center;
  line-height: 1.15; font-size: 0.62rem; font-weight: 600; border-radius: 4px 7px 7px 4px; padding: 3px 0;
  background: var(--surface-2); color: var(--muted); border: 1px dashed var(--muted);
  box-shadow: var(--shadow-sm); }
.thold.none { background: var(--danger-bg); color: var(--danger); border-color: var(--danger); border-style: solid; }
/* Follow-ups: the booking modal's control, the day-view link, and the register's status tags. */
/* One line, one type size — the label, the number and the "months" unit all read as a single
   sentence, so none of them may be sized or coloured differently from the others. */
.fu-row { display: flex; align-items: center; gap: 8px; margin-top: 10px; font-size: 0.82rem; }
.fu-row .check-row { margin: 0; gap: 6px; }
.fu-row .fu-unit { color: var(--muted); }
.modal .fu-row input[type=number] { font-size: 0.82rem; padding: 0.28rem 0.45rem; }
.fu-note { display: block; margin-top: 4px; }
.fu-link { width: 100%; margin-bottom: 10px; display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.fu-card { margin-bottom: 8px; }
.tag.fu-over { background: var(--danger-bg); color: var(--danger); }      /* overdue — call them */
.tag.fu-due { background: var(--warning-bg); color: var(--warning); }     /* due today */
.tag.fu-booked { background: var(--success-bg); color: var(--success); }  /* already on the books */
.tag.fu-soon, .tag.fu-none { background: var(--surface-2); color: var(--muted); }
/* Queue: held pin + the collapsed "Later" section */
/* Extra right padding + gap so the ✕ has room to breathe and isn't mistaken for part of the time. */
.held-tag { background: var(--surface-2); color: var(--muted); border: 1px dashed var(--muted);
  display: inline-flex; align-items: center; gap: 7px; padding-right: 5px; }
/* The pin's own "free this slot" ✕ — must shed the base button's accent fill and padding. */
button.held-x { background: none; border: none; padding: 2px 4px; margin: 0; color: inherit;
  font-size: 0.72rem; line-height: 1; font-weight: 700; opacity: 0.65; border-radius: 4px; }
button.held-x:hover { background: var(--danger-bg); border-color: transparent; color: var(--danger); opacity: 1; }
/* A held slot whose agreed time has passed with no nurse — off the diary, back in the queue to reschedule.
   Amber "needs attention", deliberately NOT red (nothing went wrong on the visit — it just lapsed). */
.resched-tag { background: var(--warning-bg); color: var(--warning); border: 1px solid var(--warning);
  display: inline-flex; align-items: center; gap: 7px; padding-right: 5px; }
.resched-head { margin: 6px 0 4px; font-size: 0.78rem; font-weight: 600; color: var(--warning); }
/* "Coming up" band header in the queue — day-2-to-horizon items, always visible (unlike "Later"). */
.queue-band-head { margin: 14px 0 6px; padding-top: 10px; border-top: 1px solid var(--border);
  font-size: 0.8rem; font-weight: 600; color: var(--muted); }
/* Working-days picker (Settings) */
.wd-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 6px; }
.wd-day { display: inline-flex; align-items: center; gap: 5px; font-size: 0.84rem; }
/* Non-working days recede to the page background (darker than the cell surface in BOTH themes — note
   --surface-2 is LIGHTER than --surface in dark, so it can't be used here), making working days read
   brighter by contrast. Their date is dimmed; a booked non-working day keeps its .has accent. */
.cell.nonworking { background: var(--bg); }
.cell.nonworking .d { opacity: 0.4; }
.month .cell.nonworking.has { background: var(--accent-bg); }
.wk-col.nonworking { background: var(--bg); }
.wk-col.nonworking .wk-head { color: var(--muted); }
/* Soft hint under the booking Date field (auto-pencilled / non-working-day). */
.sched-hint { margin-top: 4px; min-height: 1em; }
.sched-hint.warn { color: var(--warning); }
.later-head { width: 100%; display: flex; align-items: center; justify-content: space-between; margin-top: 12px; }
/* Armed tap-to-place: pinned across the top of the day view so the way out is always in sight. */
.placing-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--accent-bg); border: 1px solid var(--accent); color: var(--accent-strong);
  border-radius: 10px; padding: 7px 8px 7px 12px; margin-bottom: 10px;
  font-size: 0.85rem; font-weight: 500; }
/* combobox (suburb search / pick / add) */
.combo { position: relative; display: block; }
.combo-menu { position: absolute; left: 0; right: 0; top: calc(100% + 2px); z-index: 30;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); max-height: 200px; overflow-y: auto; }
/* Flipped above the field when the modal would clip it below (place() in comboInput decides). */
.combo-menu.up { top: auto; bottom: calc(100% + 2px); }
.combo-opt { padding: 8px 10px; cursor: pointer; font-size: 0.9rem; }
.combo-opt:hover, .combo-opt.active { background: var(--surface-2); }
.combo-add { color: var(--accent); }
.combo-empty { padding: 8px 10px; font-size: 0.85rem; }

/* Address field (Google Places autocomplete, with free-text fallback). */
.addr-input { width: 100%; }
.addr-hint { margin-top: 4px; }
/* Google's suggestion dropdown is appended to <body>; lift it above the modal. */
.pac-container { z-index: 10000 !important; border-radius: 8px; box-shadow: var(--shadow); font-family: var(--font-sans); }

/* month/day navigation entrance animation */
@keyframes slideInRight { from { opacity: 0; transform: translateX(18px); } to { opacity: 1; transform: none; } }
@keyframes slideInLeft { from { opacity: 0; transform: translateX(-18px); } to { opacity: 1; transform: none; } }
.anim-next { animation: slideInRight 0.22s ease; }
.anim-prev { animation: slideInLeft 0.22s ease; }
@media (prefers-reduced-motion: reduce) { .anim-next, .anim-prev { animation: none; } }

.navcollapse { display: none; }  /* only shown in the desktop side nav */
/* Never on touch devices (phones/tablets) — even when landscape width looks like desktop. */
@media (pointer: coarse) { .navcollapse { display: none !important; } }

/* ===== Desktop: side nav + roomier content ===== */
@media (min-width: 900px) {
  .day-grid { grid-template-columns: 1fr 280px; align-items: start; }
  .queue-rail { order: 0; margin: 0; position: sticky; top: 70px; min-height: calc(100dvh - 100px); }
  .app-wrap { max-width: none; padding-bottom: 0; }
  .bottomnav { top: 52px; bottom: 0; right: auto; width: 220px; flex-direction: column;
    justify-content: flex-start; align-items: stretch; gap: 4px; padding: 14px 12px;
    overflow-y: auto; overscroll-behavior: contain;   /* short landscape (iOS) can't fit every item — scroll rather than clip Admin */
    border-top: none; border-right: 1px solid var(--border); box-shadow: var(--shadow-sm); }
  .bottomnav button { flex-direction: row; justify-content: flex-start; gap: 12px;
    font-size: 0.95rem; padding: 10px 14px; }
  .bottomnav .fab { order: -1; width: 100%; height: auto; border-radius: var(--radius);
    margin: 0 0 8px; font-size: 1rem; justify-content: center; box-shadow: none; }
  .bottomnav .fab-label { display: inline; }
  #view { margin-left: 220px; max-width: 1000px; padding: 1.5rem 2rem; gap: 1rem; }
  #view.wide { max-width: none; }

  /* Collapse control pinned to the bottom of the side nav. */
  .navcollapse { display: inline-flex; margin-top: auto; color: var(--muted); border-top: 1px solid var(--border);
    border-radius: 0; padding-top: 14px !important; }
  .navcollapse:hover { color: var(--text); }

  /* collapsed (icon-only) side nav */
  #app.nav-collapsed .bottomnav { width: 62px; padding: 14px 8px; }
  #app.nav-collapsed .navlabel, #app.nav-collapsed .fab-label { display: none; }
  #app.nav-collapsed .bottomnav button { justify-content: center; padding: 10px 0; gap: 0; }
  #app.nav-collapsed .bottomnav .fab { order: -1; width: 42px; height: 42px; border-radius: 50%; align-self: center; }
  #app.nav-collapsed #view { margin-left: 62px; }
  /* Side nav has room for everything — no overflow popup: hide More, let the group's items flow inline.
     `.bottomnav .nav-more` (0,2,0) is needed to beat `.bottomnav button { display:flex }` (0,1,1). */
  .bottomnav .nav-more { display: none; }
  .nav-more-group { display: contents; }
}
@media (max-width: 899px) { .nav-toggle { display: none; } }

/* ===== Reports ===== */
.range-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 10px 0 4px; }
.seg { padding: 6px 14px; border: 1px solid var(--border); background: var(--surface); color: var(--text);
  border-radius: 8px; font-size: 0.84rem; font-weight: 500; cursor: pointer; }
.seg:hover { background: var(--surface-2); border-color: var(--accent); color: var(--text); }
.seg.on, .seg.on:hover { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.range-row .seg-date { width: auto; padding: 5px 8px; font-size: 0.82rem; }
.csv-btn { padding: 4px 12px; border: 1px solid var(--accent); background: var(--surface); color: var(--accent);
  border-radius: 8px; font-size: 0.8rem; font-weight: 600; cursor: pointer; white-space: nowrap; }
.csv-btn:hover { background: var(--accent); color: var(--on-accent); }
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; margin: 12px 0; }
.kpi { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; box-shadow: var(--shadow-sm); }
.kpi-n { font-size: 1.6rem; font-weight: 600; color: var(--accent); line-height: 1.1; }
.kpi-l { font-size: 0.74rem; color: var(--muted); margin-top: 2px; }
.kpi-click { cursor: pointer; transition: background .12s, border-color .12s; }
.kpi-click:hover { background: var(--surface-2); }
.kpi-on { border-color: var(--accent); }
.rep-card { margin-bottom: 14px; }
.rep-h { font-size: 1rem; margin: 0; }
.rep-title { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.rep-bars { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.rep-bar-row { display: grid; grid-template-columns: 120px 1fr 78px; align-items: center; gap: 8px; font-size: 0.8rem; }
.rep-bar-l { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rep-bar-track { background: var(--surface-2); border-radius: 5px; height: 16px; overflow: hidden; }
.rep-bar-fill { background: var(--tag-fg, var(--accent)); height: 100%; border-radius: 5px; min-width: 2px; }
.rep-bar-v { text-align: right; color: var(--muted); white-space: nowrap; }
/* Vertical column chart (daily capacity & fill) */
.rep-cols-wrap { overflow-x: auto; margin-top: 12px; padding-bottom: 4px; }
.rep-cols { display: flex; align-items: stretch; gap: 4px; height: 225px; min-width: min-content; }
.rep-col { display: flex; flex-direction: column; align-items: center; width: 26px; flex: none; }
.rep-col-track { width: 18px; flex: 1; background: var(--surface-2); border-radius: 4px 4px 0 0; display: flex; align-items: flex-end; overflow: hidden; }
.rep-col-track.stack { flex-direction: column-reverse; align-items: stretch; }
.rep-col-fill { width: 100%; background: var(--tag-fg, var(--accent)); border-radius: 4px 4px 0 0; min-height: 2px; }
.rep-col-track.stack .rep-col-fill { border-radius: 0; }
.rep-col-fill.over { background: var(--clay, #bc6a4a); }
.rep-col-l { font-size: 0.6rem; color: var(--muted); margin-top: 4px; }
.rep-table { width: 100%; border-collapse: collapse; font-size: 0.82rem; margin-top: 8px; }
.rep-table tr.click-row { cursor: pointer; }
.rep-table tr.click-row:hover td { background: var(--surface-2); }
/* Visit-photo evidence gallery */
.gal-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 10px; margin-top: 8px; }
.gal-item { display: block; text-decoration: none; color: var(--text); }
.gal-item img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 10px; border: 1px solid var(--border); display: block; }
.gal-cap { font-size: 0.68rem; color: var(--muted); line-height: 1.25; margin-top: 3px; }
.rep-table th { text-align: left; color: var(--muted); font-weight: 500; padding: 4px 8px; border-bottom: 1px solid var(--border); }
.rep-table td { padding: 4px 8px; border-bottom: 1px solid var(--border); }
.del-delivered { color: var(--success, #2f855a); font-weight: 500; }
.del-pending { color: var(--warning, #8a5a1a); font-weight: 500; }
.del-dead { color: var(--danger, #b03a3a); font-weight: 500; }
@media (max-width: 560px) { .rep-bar-row { grid-template-columns: 90px 1fr 64px; } }

/* ---------- Group Bookings (several patients at one stop) ---------- */
/* The "GROUP ·N" pill on a queue/diary card name, + "✓ X/N" once patients are reported. */
.grp-badge { display: inline-flex; align-items: center; gap: 4px; margin-left: 6px; padding: 1px 7px;
  font-size: 0.62rem; font-weight: 600; letter-spacing: 0.03em; border-radius: 999px;
  background: var(--accent-bg); color: var(--accent-strong); border: 1px solid var(--accent); vertical-align: middle; }
.grp-done { color: var(--muted); font-weight: 600; }
.grp-done.full { color: var(--success, #2f855a); }
/* Group cards read as a stop, not a single patient: a soft accent left-edge. */
.qcard.grp, .qmini.grp { border-left: 3px solid var(--accent); }
.qmini.grp { cursor: pointer; }
/* Group read-out modal: shared schedule line + tappable patient rows. */
.grp-sched { margin: 2px 0 10px; }
.rp-row.click { cursor: pointer; border-radius: 8px; padding: 7px 8px; }
.rp-row.click:hover { background: var(--surface-2); }
/* Booker: the "Group visit" toggle + the pre-add patient blocks. */
.grp-toggle { margin: 8px 0 2px; font-size: 0.9rem; }
.grp-box { margin: 4px 0 6px; padding: 10px; border: 1px dashed var(--accent); border-radius: 10px; background: var(--accent-bg); }
.grp-plist { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.grp-pblock { padding: 8px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); display: flex; flex-direction: column; gap: 6px; }
.grp-pnum { display: flex; align-items: center; justify-content: space-between; font-size: 0.72rem; font-weight: 600; color: var(--muted); }
.grp-prm { border: none; background: none; font-size: 1.1rem; line-height: 1; color: var(--muted); cursor: pointer; padding: 0 4px; }
.grp-prm:hover { color: var(--clay, #bc6a4a); }
/* Group blocks on the diary/week grids: a heavier accent edge so a stop reads as one multi-patient block. */
.tcard.grp { border-left: 4px solid var(--accent); }
.wk-item.grp { border-left-width: 4px; border-left-color: var(--accent) !important; }
.tcard.grp .grp-badge, .wk-item.grp .grp-badge { margin-left: 5px; padding: 0 5px; font-size: 0.58rem; }
/* The stop/anchor line in the group read-out — the facility header + group total, above the patients. */
.grp-anchor-row { background: var(--accent-bg); border: 1px solid var(--accent); border-radius: 8px; padding: 8px; margin-bottom: 8px; }
.grp-anchor-row .rp-name { font-weight: 600; }
/* Group stop finished by the nurse (explicit "call over", self-recorded time). */
.grp-fin { margin: 2px 0 10px; padding: 7px 10px; border-radius: 8px; background: var(--accent-bg);
  color: var(--success, #2f855a); font-weight: 500; }

/* ===== Needs-rescheduling ageing + the parked panel ===== */
/* Age chip ("7d") pushed to the right of a reschedule row — how long ago the request was captured. */
.age-chip { margin-left: auto; flex: none; padding: 1px 7px; border-radius: 999px; font-size: 0.66rem;
  font-weight: 600; background: var(--surface-2); color: var(--muted); border: 1px solid var(--border); }
.age-chip.age-mid { background: #f6ecda; color: #8a5a1a; border-color: #e6d3ae; }
.age-chip.age-old { background: #f7dede; color: #a32d2d; border-color: #eec4c4; }
[data-theme="dark"] .age-chip.age-mid { background: #3a2e17; color: #e0b36a; border-color: #5a4720; }
[data-theme="dark"] .age-chip.age-old { background: #3d1f1f; color: #e8a0a0; border-color: #5e2e2e; }
/* The reschedule row is a flex line, so the chip can sit hard right. */
.attn-card .attn-line { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
/* Queue screen: live list + parked panel. One column on a phone (panel drops underneath). */
.queue-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; align-items: start; }
.queue-main { min-width: 0; }
.queue-side { min-width: 0; }
/* 1100px, not the usual 900: the side nav eats 220px, so below this the 300px panel would squeeze the
   queue cards to ~350px. Under it the panel simply stacks beneath the list — same content, no crush. */
@media (min-width: 1100px) { .queue-grid { grid-template-columns: 1fr 300px; } }
.parked-box { border: 1px solid var(--border); border-radius: 12px; background: var(--surface-2); padding: 10px 12px; }
.parked-head { font-size: 0.8rem; font-weight: 600; color: var(--muted); }
.parked-hint { margin: 3px 0 8px; line-height: 1.35; }
.parked-row { padding: 7px 8px; border-radius: 8px; background: var(--surface); border: 1px solid var(--border); margin-bottom: 6px; }
.parked-row:last-child { margin-bottom: 0; }
.parked-row.click { cursor: pointer; }
.parked-row.click:hover { border-color: var(--accent); }
.parked-name { display: flex; align-items: center; gap: 6px; font-size: 0.84rem; font-weight: 500; }
.parked-sub { margin-top: 1px; }
/* "see queue ›" — jumps from the day-view strip to the full Queue screen (incl. parked). */
/* "+ 7 parked" sits INSIDE the heading, so it inherits the heading's size and reads as one phrase.
   Deliberately quiet: the strip's background is blue-grey, so an accent-coloured link read as
   blue-on-blue, and a <button> picked up the global filled-navy pill. */
.attn-link { cursor: pointer; color: var(--muted); text-decoration: underline; text-underline-offset: 2px; }
.attn-link:hover { color: var(--text); }
.attn-title { margin-right: auto; min-width: 0; }

/* ===== Online orders (main app → queue) ===== */
/* A source_key booking was inserted automatically, so nobody has checked it. Soft violet tint while
   UNREVIEWED only — the badge stays for life, the tint fades once a booker touches it, so the tint
   reads as a to-do rather than a permanent label. Violet is free here: amber = needs attention,
   blue-grey = overdue, blue = groups, green = done, pink = missed. Kept under 8% so it reads when
   scanning a column without competing with the outcome colours. */
:root { --online: #6d28d9; --online-fg: #5b21b6; }
[data-theme="dark"] { --online: #a78bfa; --online-fg: #c4b5fd; }
.qcard.online, .qmini.online { background: color-mix(in srgb, var(--online) 7%, var(--surface)); }
.qcard.online:hover, .qmini.online:hover { border-color: color-mix(in srgb, var(--online) 40%, var(--border)); }
.online-badge { display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 999px;
  font-size: 0.64rem; font-weight: 600; white-space: nowrap; vertical-align: middle;
  background: color-mix(in srgb, var(--online) 14%, transparent); color: var(--online-fg);
  border: 1px solid color-mix(in srgb, var(--online) 32%, transparent); }
/* Reviewed: provenance only — quieter, no border, so it stops asking for attention. */
.online-badge.seen { background: transparent; color: var(--muted); border-color: var(--border); font-weight: 500; }


/* ===== Interface pass: contrast, colour-only states, touch targets, overflow ===== */

/* 1. The per-nurse palette .c0-.c7 had no dark variant, so light pastel fills stayed light: a 60px
      pale band per nurse column across the diary, glaring nurse pills, and Reports bars (which use
      --tag-fg) nearly invisible on the dark track. Same hue identity per nurse, inverted. */
[data-theme="dark"] .c0{--tag-bg:#3a2733;--tag-fg:#e2b3c8}
[data-theme="dark"] .c1{--tag-bg:#1f332c;--tag-fg:#9fe1cb}
[data-theme="dark"] .c2{--tag-bg:#332c1f;--tag-fg:#dfc79a}
[data-theme="dark"] .c3{--tag-bg:#33232a;--tag-fg:#e0aab5}
[data-theme="dark"] .c4{--tag-bg:#2a3320;--tag-fg:#c3d69a}
[data-theme="dark"] .c5{--tag-bg:#272538;--tag-fg:#bdb6e0}
[data-theme="dark"] .c6{--tag-bg:#33271f;--tag-fg:#dcb69c}
[data-theme="dark"] .c7{--tag-bg:#232c33;--tag-fg:#a8c2d1}

/* 2. --accent-strong is DARKER than --accent in light (correct for emphasis) but the pair flips in
      dark, so "emphasis" became "recede" — worst on the GROUP pill at ~2.6:1. Use --accent there. */
[data-theme="dark"] .grp-badge,
[data-theme="dark"] .placing-bar,
[data-theme="dark"] button.btn-report,
[data-theme="dark"] button.rp-same,
[data-theme="dark"] .sched-band .sched-lab { color: color-mix(in srgb, var(--accent) 70%, var(--text)); }

/* 5. The week view was the ONLY view signalling outcome by background colour alone — the day view
      and the nurse page both carry text. Four pale tints of near-identical lightness are
      indistinguishable to a red-green colour-blind booker, and this is the "what happened this
      week" scan. Text backup, CSS-only. */
.wk-item.oc-done .wk-t::after { content: " \2713"; color: var(--success); font-weight: 600; }
.wk-item.oc-missed .wk-t::after { content: " \2715"; color: var(--missed, #b23a70); font-weight: 600; }

/* 13. .tcard clips its overflow and a 20-minute visit is only ~1.6 lines tall, so .tc-oc — the
       ✓/✕ text that backs up the colour — was cut off on exactly the shortest cards. Also caps an
       uncapped free-text outcome_reason. */
.tc-oc { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }

/* 9. Report / Reschedule / No-rebook were ~24px tall, side by side, on a full-width mobile rail —
      and one of them writes "Missed - no report" against a patient. */
@media (max-width: 899px) { .attn-act { padding: 10px 4px; font-size: 0.74rem; } }

/* 10. The diary confirm tick was a 19x19px target; the day view is reachable on a phone. */
@media (pointer: coarse) { .tc-confirm { width: 28px; height: 28px; font-size: 0.9rem; } }

/* 14. Month cells are ~44px wide on a 375px phone and "12 patients" cannot wrap below ~48px, so it
       spilled into the neighbouring cell. */
@media (max-width: 560px) {
  .month .cell { overflow: hidden; }
  .mcount { font-size: 0.6rem; overflow-wrap: anywhere; }
}


/* 15. The day cue and the group cue both owned border-left at equal specificity (0,2,0), and .grp
      comes later in the file — so a GROUP booking wanted TODAY silently lost its amber "place this
      today" edge. Give the day cue its own channel (an inset shadow) so the two can coexist: the
      group keeps the border, the day cue paints inside it. */
.qcard.qday-today { box-shadow: inset 5px 0 0 #d99a2b, var(--shadow-sm); }
.qcard.qday-tomorrow { box-shadow: inset 5px 0 0 #6fbf8f, var(--shadow-sm); }
.qmini.qday-today { box-shadow: inset 5px 0 0 #d99a2b; }
.qmini.qday-tomorrow { box-shadow: inset 5px 0 0 #6fbf8f; }

/* 16. .attn-card.grp is applied in JS (overdueQueueSection) but no rule existed, so a group stop in
      the To-reschedule strip was the one surface missing the group language. */
.attn-card.grp { border-left: 3px solid var(--accent); }
