:root {
  --bg: #f4f6f9; --panel: #ffffff; --panel-2: #f8fafc; --border: #dde3ea; --text: #1c2430; --muted: #5d6b7c;
  --primary: #1f5f8b; --primary-2: #17496b; --primary-soft: #e3eef7; --accent: #2a9d8f; --danger: #c0392b; --danger-soft: #fdecea;
  --warn: #8a5a12; --warn-soft: #fff5e0; --ok: #276749; --ok-soft: #e6f4ec; --info-soft: #e8f1fb; --purple: #6b46c1; --purple-soft: #efe9fb;
  --radius: 10px; --shadow: 0 1px 2px rgba(16,24,40,.06), 0 1px 3px rgba(16,24,40,.1);
  --sidebar-w: 14.75rem; /* 236px at the default text size; grows with the reader's text size (1.4.4) */ --font: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) {
  --bg: #0f151c; --panel: #161e27; --panel-2: #1b2531; --border: #2a3644; --text: #e6edf3; --muted: #97a6b6;
  --primary: #4f9bd9; --primary-2: #7ab6e6; --primary-soft: #1a2c3d; --accent: #4fc3b3; --danger: #ef6a5a; --danger-soft: #3a1f1c;
  --warn: #e8b24f; --warn-soft: #3a2f16; --ok: #5cc48a; --ok-soft: #173325; --info-soft: #17283a; --purple: #a78bfa; --purple-soft: #2a2140;
  --shadow: 0 1px 2px rgba(0,0,0,.4);
} }
:root[data-theme="dark"] {
  --bg: #0f151c; --panel: #161e27; --panel-2: #1b2531; --border: #2a3644; --text: #e6edf3; --muted: #97a6b6;
  --primary: #4f9bd9; --primary-2: #7ab6e6; --primary-soft: #1a2c3d; --accent: #4fc3b3; --danger: #ef6a5a; --danger-soft: #3a1f1c;
  --warn: #e8b24f; --warn-soft: #3a2f16; --ok: #5cc48a; --ok-soft: #173325; --info-soft: #17283a; --purple: #a78bfa; --purple-soft: #2a2140;
  --shadow: 0 1px 2px rgba(0,0,0,.4);
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
/* rem, not px: a phone's larger-text setting (or a reader's own default size) has to reach every screen,
   the top bar and the buttons included; at 14px they stayed small while the rest grew. */
body { font-family: var(--font); font-size: .875rem; color: var(--text); background: var(--bg); line-height: 1.45; }
a { color: var(--primary); text-decoration: none; } a:hover { text-decoration: underline; }
/* Looks and behaves like a link for a mouse, without being a second focusable control nested inside a
   row that is already one (see noteTable in notes.js) — deliberately not reachable by keyboard/Tab. */
.link-like { color: var(--primary); cursor: pointer; } .link-like:hover { text-decoration: underline; }
h1, h2, h3, h4 { margin: 0 0 .5rem; font-weight: 650; line-height: 1.25; }
h1 { font-size: 1.45rem; } h2 { font-size: 1.15rem; } h3 { font-size: 1rem; } h4, .eyebrow { font-size: .9rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
/* Headings go down one level at a time (page h1 → card h2 → group h3). A card's title is an h2 that looks the
   size a card title always has; a dialog's own title (also h2) keeps the larger size. */
.card h2 { font-size: 1rem; } .modal > .card-head h2 { font-size: 1.15rem; }
p { margin: 0 0 .75rem; }
code, .mono { font-family: var(--mono); font-size: .85em; }
.boot { padding: 4rem; text-align: center; color: var(--muted); }
.muted { color: var(--muted); } .small { font-size: .85em; } .right { text-align: right; } .center { text-align: center; } .nowrap { white-space: nowrap; }
.mt { margin-top: 1rem; } .mb { margin-bottom: 1rem; } .row { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; } .row.between { justify-content: space-between; } .grow { flex: 1; }
.grid { display: grid; gap: 1rem; } .grid.cols-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); } .grid.cols-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); } .grid.cols-4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 11.25rem), 1fr)); }
.hidden { display: none !important; }

/* Layout */
.app { min-height: 100%; }
.layout { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100vh; }
.sidebar { background: var(--panel); border-right: 1px solid var(--border); padding: 1rem .75rem; display: flex; flex-direction: column; gap: .25rem; position: sticky; top: 0; height: 100vh; overflow: auto; }
.brand { display: flex; align-items: center; gap: .6rem; padding: .25rem .5rem .9rem; border-bottom: 1px solid var(--border); margin-bottom: .5rem; }
.brand img { width: 30px; height: 30px; } .brand b { font-size: 1.05rem; } .brand small { display: block; color: var(--muted); font-size: .72rem; }
.nav a { display: flex; align-items: center; gap: .6rem; padding: .5rem .65rem; border-radius: 8px; color: var(--text); font-weight: 500; }
.nav a:hover { background: var(--panel-2); text-decoration: none; } .nav a.active { background: var(--primary-soft); color: var(--primary); }
.nav a .ico { width: 1.3em; flex: 0 0 auto; text-align: center; opacity: .8; } .nav a { overflow-wrap: anywhere; min-width: 0; } .nav .sec { margin: .6rem .65rem .2rem; font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.sidebar .foot { margin-top: auto; padding-top: .75rem; border-top: 1px solid var(--border); font-size: .85em; }
.main { padding: 1.25rem 1.5rem 3rem; min-width: 0; }
.topbar { display: flex; justify-content: space-between; align-items: center; gap: 1rem; margin-bottom: 1rem; }
.topbar .search { flex: 1; max-width: 460px; }
@media (max-width: 900px) { .layout { grid-template-columns: 1fr; } .sidebar { position: relative; height: auto; flex-direction: row; flex-wrap: wrap; } .sidebar .foot { margin-top: 0; width: 100%; } .nav { display: flex; flex-wrap: wrap; gap: .15rem; } .nav .sec { display: none; } .main { padding: 1rem; } }

/* Cards, tables */
.card { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); padding: 1rem 1.15rem; }
.card.tight { padding: .65rem .85rem; } .card h2, .card h3 { margin-bottom: .6rem; }
.card-head { display: flex; justify-content: space-between; align-items: center; gap: .75rem; margin-bottom: .6rem; flex-wrap: wrap; }
.stat { display: flex; flex-direction: column; gap: .15rem; } .stat .v { font-size: 1.6rem; font-weight: 700; line-height: 1.1; } .stat .l { color: var(--muted); font-size: .8rem; }
.stat.warn .v { color: var(--warn); } .stat.danger .v { color: var(--danger); } .stat.ok .v { color: var(--ok); }
table { width: 100%; border-collapse: collapse; font-size: .92em; } th, td { text-align: left; padding: .5rem .6rem; border-bottom: 1px solid var(--border); vertical-align: top; }
th { font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); font-weight: 600; background: var(--panel-2); position: sticky; top: 0; }
tr.click { cursor: pointer; } tr.click:hover td { background: var(--panel-2); } td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.table-wrap { overflow: auto; max-height: 70vh; border: 1px solid var(--border); border-radius: 8px; } .table-wrap table th { top: 0; }
.empty { padding: 1.5rem; text-align: center; color: var(--muted); }

/* Badges, pills */
.badge { display: inline-block; padding: .12rem .5rem; border-radius: 999px; font-size: .74rem; font-weight: 600; background: var(--panel-2); border: 1px solid var(--border); color: var(--muted); white-space: nowrap; }
.badge.ok { background: var(--ok-soft); color: var(--ok); border-color: transparent; } .badge.warn { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.badge.danger { background: var(--danger-soft); color: var(--danger); border-color: transparent; } .badge.info { background: var(--info-soft); color: var(--primary); border-color: transparent; }
.badge.purple { background: var(--purple-soft); color: var(--purple); border-color: transparent; }
.tabs { display: flex; gap: .25rem; border-bottom: 1px solid var(--border); margin-bottom: 1rem; overflow-x: auto; }
.tabs button { background: none; border: none; border-bottom: 2px solid transparent; padding: .55rem .8rem; cursor: pointer; color: var(--muted); font: inherit; font-weight: 500; white-space: nowrap; }
.tabs button.active { color: var(--primary); border-bottom-color: var(--primary); } .tabs button:hover { color: var(--text); }

/* Forms */
label { display: block; font-size: .8rem; font-weight: 600; color: var(--muted); margin-bottom: .25rem; }
input, select, textarea { width: 100%; font: inherit; color: var(--text); background: var(--panel); border: 1px solid var(--input-border, var(--border)); border-radius: 8px; padding: .5rem .6rem; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--primary-soft); border-color: var(--primary); }
input[type="checkbox"] { width: auto; margin-right: .4rem; } textarea { min-height: 90px; resize: vertical; }
.field { margin-bottom: .8rem; } .dt-pair { display: flex; gap: .4rem; } .dt-pair input[type="date"] { flex: 1 1 58%; min-width: 0; } .dt-pair .time-box { flex: 1 1 42%; min-width: 0; } .date-with-pick { display: flex; gap: .4rem; } .date-with-pick .date-box { flex: 1 1 auto; min-width: 0; } .date-with-pick input[type="date"] { flex: 1 1 auto; min-width: 0; } .date-native { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; } .date-pick { flex: 0 0 auto; padding-left: .55rem; padding-right: .55rem; } .field .help { font-size: .78rem; color: var(--muted); margin-top: .2rem; } .field.error input, .field.error select, .field.error textarea { border-color: var(--danger); } .err { color: var(--danger); } .field .err { font-size: .78rem; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0 1rem; } .form-grid .span { grid-column: 1 / -1; }
.check { display: flex; align-items: center; gap: .3rem; font-weight: 500; color: var(--text); margin-top: 1.4rem; }
fieldset { border: 1px solid var(--border); border-radius: 8px; padding: .6rem .9rem; margin: 0 0 1rem; } legend { font-size: .8rem; font-weight: 700; color: var(--muted); padding: 0 .3rem; }
.btn { display: inline-flex; align-items: center; gap: .4rem; font: inherit; font-weight: 600; padding: .5rem .85rem; border-radius: 8px; border: 1px solid var(--border); background: var(--panel); color: var(--text); cursor: pointer; white-space: nowrap; max-width: 100%; }
.btn:hover { background: var(--panel-2); } .btn:disabled, .btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }
/* A button that is really a file input: the input covers the label, invisible but hit-testable, so both a
   tap on the words and a click aimed at the input open the picker; the label carries the focus ring. */
.file-btn { position: relative; overflow: hidden; }
.file-btn input[type=file] { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; opacity: 0; cursor: pointer; margin: 0; font-size: 0; }
.file-btn:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }
.btn.primary { background: var(--primary); border-color: var(--primary); color: #fff; } .btn.primary:hover { background: var(--primary-2); }
.btn.danger { background: var(--danger-soft); border-color: transparent; color: var(--danger); } .btn.sm { padding: .3rem .6rem; font-size: .82rem; } .btn.ghost { border-color: transparent; background: transparent; }
.btn-row { display: flex; gap: .5rem; justify-content: flex-end; margin-top: 1rem; flex-wrap: wrap; }
.filters { display: flex; gap: .5rem; align-items: end; flex-wrap: wrap; margin-bottom: .75rem; } .filters .field { margin: 0; min-width: 140px; }

/* Modal, toasts */
/* Layering: banners (60) sit over the page, a dialog (70) over the banners — on a phone the MFA banner used to
   cover the first row of the + Log sheet — and toasts (100) over everything, so a save error is never hidden. */
.modal-bg { position: fixed; inset: 0; background: rgba(10,15,20,.55); display: flex; align-items: flex-start; justify-content: center; padding: 3vh 1rem; overflow: auto; z-index: 70; }
.modal { background: var(--panel); border-radius: 12px; width: 100%; min-width: 0; max-width: 760px; box-shadow: 0 20px 60px rgba(0,0,0,.35); padding: 1.25rem 1.4rem; margin: auto; }
.modal.wide { max-width: 1040px; } .modal h2 { margin-bottom: 1rem; } .modal .card h2 { margin-bottom: .6rem; }
.toasts { position: fixed; right: 1rem; bottom: 1rem; display: flex; flex-direction: column; gap: .5rem; z-index: 100; }
/* A toast only says something; it has no controls. It must never take a tap or click meant for what is under
   it — a "Task saved" toast lying over the next dialog's date field swallowed the tap on its calendar button. */
.toasts, .toast { pointer-events: none; }
.toast { background: var(--text); color: var(--bg); padding: .6rem .9rem; border-radius: 8px; box-shadow: var(--shadow); max-width: 380px; font-weight: 500; }
.toast.error { background: var(--danger); color: #fff; } .toast.ok { background: var(--ok); color: #fff; }
/* The one toast with a control (Undo): it takes taps and clicks, on its own area only. */
.toast.undo-toast { pointer-events: auto; display: flex; align-items: center; gap: .75rem; justify-content: space-between; }
.toast.undo-toast .btn { background: var(--bg); color: var(--text); border-color: var(--bg); flex: none; }
.toast.undo-toast .undo-toast-actions { display: flex; flex-wrap: wrap; gap: .5rem; flex: none; justify-content: flex-end; }

/* Login */
.login-wrap { min-height: 100vh; display: grid; place-items: center; padding: 1rem; background: linear-gradient(160deg, var(--primary-soft), var(--bg) 60%); }
.login { width: 100%; max-width: 460px; }
/* One column that never grows past the screen (a long link in the statement page pushed it wider). */
.login-wrap { grid-template-columns: minmax(0, 1fr); justify-items: center; }
.statement { overflow-wrap: anywhere; } .card p, .card li { overflow-wrap: break-word; }
/* Log in / Sign up: a two-option segmented control (role=tablist) that fills the card on a phone. */
.seg { display: grid; grid-template-columns: 1fr 1fr; gap: .25rem; padding: .25rem; margin: .25rem 0 1rem; background: var(--primary-soft); border-radius: 10px; }
.seg-btn { min-height: 44px; border: 0; border-radius: 8px; background: transparent; color: var(--text); font: inherit; font-weight: 600; cursor: pointer; }
.seg-btn.active { background: var(--panel); color: var(--primary); box-shadow: 0 1px 3px rgba(0,0,0,.18); }
.seg-btn:hover:not(.active) { background: rgba(255,255,255,.35); }
.login .brand { border: 0; justify-content: center; margin-bottom: .5rem; }
.banner { border-left: 4px solid var(--primary); background: var(--info-soft); padding: .6rem .8rem; border-radius: 6px; margin-bottom: 1rem; font-size: .88em; }
.banner.warn { border-color: var(--warn); background: var(--warn-soft); } .banner.danger { border-color: var(--danger); background: var(--danger-soft); }
/* The "possible duplicate" question inside the time form (public/views/time.js askDuplicate, 1.24.0). */
.time-dup .time-dup-title { font-size: 1.05rem; margin: 0 0 .35rem; } .time-dup ul { margin: .25rem 0 .5rem; padding-left: 1.2rem; }
.time-dup fieldset { border: 0; padding: 0; margin: .4rem 0; } .time-dup legend { font-weight: 600; padding: 0; } .time-dup .btn-row { margin-top: .5rem; }
/* A form's save error repeated beside its Save button on a long form (app.js form(), 1.24.0): looks like the danger banner. */
.banner.form-error-near { border-color: var(--danger); background: var(--danger-soft); }
/* What kind of funder report run this is (public/views/funder.js runKindBanner): the first thing on the page. */
.banner.run-kind { font-size: 1em; }
.banner.run-kind .run-kind-title { font-size: 1.15rem; margin: 0 0 .25rem; }
.banner.run-kind .run-kind-line { margin: 0 0 .35rem; }
.banner.run-kind details > summary { cursor: pointer; font-weight: 600; }
.banner.run-kind details > p { margin: .4rem 0 0; }

/* Timeline */
/* A client record's History tab (views/history.js): one card per change; the one a change notice links to is outlined. */
.rev-list { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: 1rem; }
.rev-highlight { outline: 3px solid var(--primary); outline-offset: 2px; }
.timeline { list-style: none; margin: 0; padding: 0 0 0 1.4rem; border-left: 2px solid var(--border); }
.timeline li { position: relative; padding: 0 0 1rem .9rem; }
.timeline li::before { content: ""; position: absolute; left: -1.4rem; top: .35rem; width: 12px; height: 12px; border-radius: 50%; background: var(--panel); border: 3px solid var(--primary); transform: translateX(-50%); margin-left: 1px; }
.timeline li.call::before { border-color: var(--accent); } .timeline li.note::before { border-color: var(--purple); } .timeline li.referral::before { border-color: var(--warn); }
.timeline li.milestone::before { border-color: var(--ok); background: var(--ok); } .timeline li.task::before { border-color: var(--muted); } .timeline li.expense::before { border-color: #d97706; } .timeline li.consent::before { border-color: #0ea5e9; }
.timeline .t { font-size: .78rem; color: var(--muted); } .timeline .h { font-weight: 600; } .timeline .d { color: var(--muted); font-size: .9em; white-space: pre-wrap; }

/* Bars / charts */
.bar { display: flex; align-items: center; gap: .5rem; font-size: .85em; margin: .25rem 0; } .bar .lbl { width: 40%; min-width: 0; overflow-wrap: anywhere; }
.bar .trk { flex: 1; background: var(--panel-2); border-radius: 4px; height: 12px; overflow: hidden; } .bar .fil { height: 100%; background: var(--primary); border-radius: 4px; } .bar .n { min-width: 3.5rem; text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.progress { height: 10px; background: var(--panel-2); border-radius: 5px; overflow: hidden; } .progress > div { height: 100%; background: var(--accent); } .progress > div.warn { background: var(--warn); } .progress > div.danger { background: var(--danger); }
.spark { display: flex; align-items: flex-end; gap: 2px; height: 48px; } .spark div { flex: 1; background: var(--primary); border-radius: 2px 2px 0 0; min-height: 2px; opacity: .85; }
.kv { display: grid; grid-template-columns: fit-content(40%) minmax(0, 1fr); gap: .25rem .9rem; font-size: .92em; } .kv dt { color: var(--muted); } .kv dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
/* A badge is nowrap by default; inside a max-content grid on a phone that pushes the whole page sideways. */
.kv .badge { white-space: normal; }
pre.note { white-space: pre-wrap; font-family: var(--font); background: var(--panel-2); border: 1px solid var(--border); border-radius: 8px; padding: .8rem; max-height: 50vh; overflow: auto; }
.dropzone { border: 2px dashed var(--border); border-radius: 10px; padding: 1.5rem; text-align: center; color: var(--muted); cursor: pointer; } .dropzone.over { border-color: var(--primary); background: var(--primary-soft); }
.list-item { padding: .6rem 0; border-bottom: 1px solid var(--border); } .list-item:last-child { border-bottom: 0; }
.idle-warn { position: fixed; top: 0; left: 0; right: 0; background: var(--warn); color: #fff; text-align: center; padding: .4rem; z-index: 200; font-weight: 600; }
.qr { font-family: var(--mono); font-size: .8em; word-break: break-all; background: var(--panel-2); padding: .5rem; border-radius: 6px; }
@media print { .sidebar, .topbar, .btn, .tabs { display: none !important; } .layout { display: block; } .card { box-shadow: none; } }
/* Shown only on paper: the 42 CFR Part 2 label a printed record carries. */
.print-only { display: none; }
@media print { .print-only { display: block !important; border: 1px solid #000; padding: .3rem .5rem; margin: .5rem 0; } }
.row > select, .row > input:not([type="checkbox"]) { width: auto; }

/* Mobile navigation */
.mobilebar { display: none; }
@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; }
  .mobilebar { display: flex; align-items: center; justify-content: space-between; gap: .5rem; position: sticky; top: 0; z-index: 30; background: var(--panel); border-bottom: 1px solid var(--border); padding: .4rem .6rem; padding-top: calc(.4rem + env(safe-area-inset-top)); }
  .mobilebar .btn { font-size: 1.25rem; padding: .3rem .6rem; }
  .mobilebar-title { display: flex; flex-direction: column; align-items: center; line-height: 1.15; min-width: 0; }
  .mobilebar-stamp { font-size: .7rem; color: var(--muted); }
  .sidebar { position: fixed; inset: 0 25% 0 0; height: 100vh; z-index: 40; transform: translateX(-100%); transition: transform .2s ease; box-shadow: 0 0 40px rgba(0,0,0,.4); flex-direction: column; flex-wrap: nowrap; }
  .sidebar.open { transform: translateX(0); }
  body.nav-open::after { content: ""; position: fixed; inset: 0; background: rgba(0,0,0,.4); z-index: 35; }
  .nav { display: block; } .nav .sec { display: block; } .nav a { padding: .7rem .65rem; font-size: 1rem; }
  .sidebar .foot { margin-top: auto; }
  /* Room at the end of the page for the floating action button, which is fixed over the bottom-right
     corner: without it the last control on a screen (a Load/Remove button, the last row of a list)
     sits underneath the FAB and cannot be tapped. */
  .main { padding: .75rem .75rem calc(7rem + env(safe-area-inset-bottom)); }
  .topbar { flex-direction: column; align-items: stretch; } .topbar h1 { font-size: 1.25rem; } .topbar .row { justify-content: flex-start; }
  .modal-bg { padding: 0; align-items: stretch; } .modal, .modal.wide { max-width: none; border-radius: 0; min-height: 100vh; padding: 1rem; padding-bottom: calc(1rem + env(safe-area-inset-bottom)); }
  .form-grid { grid-template-columns: 1fr; }
  .btn { padding: .65rem 1rem; } input, select, textarea { font-size: max(16px, 1rem); padding: .6rem .7rem; } /* 16px prevents iOS zoom */
  .filters .field { min-width: 45%; }
  .tabs button { padding: .7rem .8rem; }
  .table-wrap { max-height: none; }
  .stat .v { font-size: 1.3rem; }
  .timeline { padding-left: 1rem; }
  .toasts { left: .75rem; right: .75rem; bottom: calc(.75rem + env(safe-area-inset-bottom)); } .toast { max-width: none; }
}
@media (display-mode: standalone) { .mobilebar { padding-top: calc(.4rem + env(safe-area-inset-top)); } }

/* Intuitive-UI additions */
.content { min-width: 0; }
.appbar { display: flex; align-items: center; gap: .75rem; padding: .75rem 1.5rem 0; }
.gsearch { position: relative; flex: 1; max-width: 520px; } .gsearch input { padding-left: .8rem; }
.search-results { position: absolute; top: 100%; left: 0; right: 0; z-index: 25; margin-top: .25rem; max-height: 300px; overflow: auto; }
.search-results .list-item { display: block; } .search-results .result-type { display: inline-block; min-width: 5.5rem; }
.btn.quick { font-size: 1rem; padding: .55rem 1.1rem; border-radius: 999px; }
.fab { display: none; }
.quick-list { display: grid; gap: .5rem; } .quick-list .btn { justify-content: flex-start; font-size: 1.05rem; padding: .8rem 1rem; } .quick-list .ico { width: 1.6rem; text-align: center; font-size: 1.2rem; }
.help-wrap { position: relative; display: inline-block; }
.help-btn { width: 1.4rem; height: 1.4rem; border-radius: 50%; border: 1px solid var(--border); background: var(--panel-2); color: var(--primary); font-weight: 700; cursor: pointer; font-size: .8rem; vertical-align: middle; }
.helptip { position: absolute; top: 130%; left: 0; z-index: 30; width: min(360px, 80vw); background: var(--panel); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 10px 30px rgba(0,0,0,.2); padding: .75rem .9rem; font-size: .92rem; font-weight: 400; color: var(--text); text-transform: none; letter-spacing: 0; }
.empty-state { text-align: center; padding: 2rem 1rem; } .empty-state .big { font-size: 1.15rem; font-weight: 650; margin: 0 0 .3rem; }
.today-item { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .35rem .75rem; padding: .6rem 0; border-bottom: 1px solid var(--border); }
.today-item > * { min-width: 0; } .today-due { max-width: 100%; text-align: right; margin-left: auto; } .today-item:last-child { border-bottom: 0; }
/* Home's to-dos (1.23.2): the box marks one done, the title (a button) opens it; each at least 24px to hit. */
.today-main { display: flex; align-items: center; gap: .3rem; min-width: 0; }
.today-check { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; min-height: 24px; cursor: pointer; flex: 0 0 auto; margin: 0; }
.today-check input[type="checkbox"] { margin: 0; }
.today-open { background: none; border: 0; padding: 0; margin: 0; font: inherit; color: var(--primary); text-align: left; cursor: pointer; min-height: 24px; overflow-wrap: anywhere; }
.today-open:hover { text-decoration: underline; }
.chip { display: inline-flex; align-items: center; gap: .35rem; padding: .35rem .7rem; border-radius: 999px; background: var(--primary-soft); color: var(--primary); font-weight: 600; font-size: .85rem; }
details.section { border: 1px solid var(--border); border-radius: 8px; padding: .4rem .9rem; margin-bottom: .8rem; grid-column: 1 / -1; } details.section summary { cursor: pointer; font-weight: 600; padding: .3rem 0; } details.section .form-grid { margin-top: .5rem; }
.autosave { font-size: .8rem; color: var(--muted); }
@media (max-width: 900px) {
  .appbar { padding: .5rem .75rem 0; } .appbar .btn.quick { display: none; }
  .fab { display: block; position: fixed; right: 1rem; bottom: calc(1.25rem + env(safe-area-inset-bottom)); z-index: 45; } .fab .btn { box-shadow: 0 6px 20px rgba(0,0,0,.3); font-size: min(1.1rem, 20px); padding: 12px 20px; }
  /* Out of the way while the menu drawer or a dialog is up: it was floating over both. */
  body.nav-open .fab, body:has(.modal-bg) .fab, body:has(.tabs-menu:not(.hidden)) .fab, body:has(.helptip:not(.hidden)) .fab { display: none; }
  /* Room to scroll the last card ("Continue where you left off") out from under the floating + Log button. */
  .main { padding-bottom: calc(7.5rem + env(safe-area-inset-bottom)); }
  /* And a control brought into view from the keyboard (Tab, or a link to a part of the page) stops above the button
     rather than under it (1.23.2), as Street outreach's form already did. */
  html { scroll-padding-bottom: calc(6rem + env(safe-area-inset-bottom)); }
  /* Toasts stack above the button rather than underneath it. */
  .toasts { bottom: calc(5.75rem + env(safe-area-inset-bottom)); }
  /* Checkboxes in lists are tapped one-handed between visits; 13px is a mis-tap waiting to happen. */
  table input[type="checkbox"], .check input[type="checkbox"], .compact-row input[type="checkbox"] { width: 24px; height: 24px; margin: 0 .4rem 0 0; accent-color: var(--primary); flex: 0 0 auto; }
  /* Home's to-do box too (1.23.3): its label is .today-check, not .check, since 1.23.2, and the box had shrunk to 13px. */
  .today-check input[type="checkbox"] { width: 24px; height: 24px; margin: 0; accent-color: var(--primary); }
  table td:has(> input[type="checkbox"]:only-child) { padding: .5rem .35rem; }
  /* The tab strip scrolls sideways; fade the right edge so the tabs off-screen are not a secret. */
  .tabs { position: relative; scrollbar-width: none; -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent); scroll-snap-type: x proximity; }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs button { scroll-snap-align: start; }
  /* Banners must never cover the table someone is reading. */
  #banners { position: static; }
  /* Wide tables scroll inside their own wrapper; the page itself never scrolls sideways. */
  .content, .main { overflow-x: clip; }
  /* Never break a figure ("$1,2|34.56") to fit: the cards go one to a row instead when the text is large. */
  .stat .v { overflow-wrap: normal; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .grid.cols-4 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 10rem), 1fr)); }
}
.modal .card-head { flex-wrap: nowrap; align-items: flex-start; } .modal .card-head h2 { margin-bottom: 0; }
.quick-list .btn { width: 100%; white-space: normal; text-align: left; }

/* ---------- navigator fixes: tap targets, compact lists, tab overflow, due bell, contact links ---------- */
/* Fingers, not pointers: every small control is at least 44px on a touch screen. */
@media (pointer: coarse) {
  .btn.sm, .help-btn, .filters .btn, .tabs button, .tabs-more, .sidebar .foot a, .mobilebar .btn, .card-head a, .today-item a, a.chip, button.chip, .bell { min-height: 44px; }
  .btn.sm, .help-btn, .mobilebar .btn, .bell { min-width: 44px; }
  .sidebar .foot a, .card-head a, .today-item a { display: inline-flex; align-items: center; padding: 0 .35rem; }
  .help-btn { width: 44px; height: 44px; font-size: 1rem; }
  .nav a { min-height: 44px; }
  .badge a, .contact a, a.tel, a.sms, a.maplink { display: inline-flex; align-items: center; min-height: 44px; padding: 0 .25rem; }
}
a.tel { font-variant-numeric: tabular-nums; } a.sms { font-weight: 600; }
.contact { display: inline-flex; align-items: center; gap: .15rem; flex-wrap: wrap; }
/* Two-line rows for a phone; the full table stays for a desk. */
.compact-list { display: none; }
.compact-row { padding: .6rem .25rem; border-bottom: 1px solid var(--border); }
.compact-row:last-child { border-bottom: 0; } .compact-row.click { cursor: pointer; } .compact-row.click:hover, .compact-row.click:focus-visible { background: var(--panel-2); }
.compact-row .primary { display: flex; align-items: center; justify-content: space-between; gap: .5rem; font-weight: 600; }
.compact-row .primary > :first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.compact-row .secondary { margin-top: .15rem; display: flex; gap: .5rem; flex-wrap: wrap; }
.compact-row .compact-actions { flex-basis: 100%; } .compact-row .compact-actions:empty { display: none; }
/* filterBar(): the "Filters" button shows on a phone only; elsewhere the bar is open and looks as it always did. */
.filters-box > summary { display: none; }
@media (max-width: 640px) {
  .filters-box > summary { display: inline-flex; margin-bottom: .6rem; min-height: 44px; list-style: none; }
  .filters-box > summary::-webkit-details-marker { display: none; }
  .filters-box > summary::after { content: " ▾" / ""; white-space: pre; } .filters-box[open] > summary::after { content: " ▴" / ""; }
  .table-wrap.has-compact table { display: none; }
  .table-wrap.has-compact .compact-list { display: block; }
}
/* Tab strip with a "More" menu for what does not fit. */
.tabs.managed { overflow: visible; flex-wrap: nowrap; -webkit-mask-image: none; mask-image: none; position: relative; }
.tabs-more-wrap { position: relative; margin-left: auto; flex: 0 0 auto; }
.tabs-more { background: none; border: none; border-bottom: 2px solid transparent; padding: .55rem .8rem; cursor: pointer; color: var(--primary); font: inherit; font-weight: 600; white-space: nowrap; }
.tabs-menu { position: absolute; right: 0; top: 100%; z-index: 30; min-width: 200px; background: var(--panel); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 10px 30px rgba(0,0,0,.2); padding: .3rem; display: flex; flex-direction: column; }
.tabs-menu button { text-align: left; background: none; border: 0; padding: .6rem .8rem; font: inherit; color: var(--text); cursor: pointer; border-radius: 6px; white-space: nowrap; }
.tabs-menu button:hover, .tabs-menu button:focus-visible { background: var(--panel-2); } .tabs-menu button.active { color: var(--primary); font-weight: 600; }
/* The reminders bell in the header. */
.bell { position: relative; font-size: 1.1rem; text-decoration: none; }
.bell-count { position: absolute; top: -.2rem; right: -.2rem; min-width: 1.2rem; height: 1.2rem; padding: 0 .3rem; border-radius: 999px; background: var(--danger); color: #fff; font-size: .7rem; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; }
.bell.has-due { color: var(--danger); }
/* The bell's panel (1.15.3): below the bell, inside the screen on a phone. */
.bell-wrap { position: relative; display: inline-flex; }
.bell-panel { position: absolute; right: 0; top: calc(100% + .35rem); width: min(22rem, calc(100vw - 2rem)); z-index: 65; box-shadow: var(--shadow); }
.bell-panel h2 { margin: 0 0 .4rem; }
.bell-panel-foot { justify-content: space-between; align-items: center; gap: .5rem; margin-top: .5rem; flex-wrap: wrap; }
/* A safety plan on file is a chip, not a badge: it opens the plan. */
button.chip { border: 0; cursor: pointer; font: inherit; }
button.chip:hover { background: var(--primary); color: #fff; }
/* Offline: the whole shell says so, and the top banner is the loud version. */
html.offline .appbar, html.offline .mobilebar { filter: grayscale(.4); }
.hand-off { border-left: 3px solid var(--warn); padding-left: .6rem; margin-bottom: .6rem; }
.hand-off .excerpt { white-space: pre-wrap; }

/* ---- resource directory & treatment center profiles ---- */
.thumb { width: 44px; height: 44px; border-radius: 8px; object-fit: cover; display: block; background: var(--panel-2); }
.placeholder { display: flex; align-items: center; justify-content: center; color: var(--muted); font-weight: 700; background: linear-gradient(135deg, var(--panel-2), var(--border)); }
.res-cards .res-card { display: flex; flex-direction: column; padding: 0; overflow: hidden; color: inherit; text-decoration: none; transition: transform .08s, box-shadow .08s; }
.res-cards .res-card:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(0,0,0,.12); }
.res-cover { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; display: block; border-radius: 0; font-size: 2rem; }
.res-cover.placeholder { aspect-ratio: 16 / 5; font-size: 1.4rem; }
.res-body { padding: .75rem .9rem .85rem; display: flex; flex-direction: column; gap: .3rem; }
.res-summary { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; margin: 0; }
.res-tags .badge { margin-bottom: .2rem; }
.res-head { margin-bottom: 1rem; } .res-lead { font-size: 1.02rem; max-width: 70ch; white-space: pre-wrap; }
.gallery .hero { margin: 0; } .hero-btn { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: zoom-in; border-radius: 10px; } .gallery .hero img { width: 100%; max-height: 380px; object-fit: cover; border-radius: 10px; cursor: zoom-in; display: block; background: var(--panel-2); }
.gallery .hero figcaption { font-size: .82rem; color: var(--muted); margin-top: .3rem; }
.gallery .thumbs { display: flex; gap: .4rem; flex-wrap: wrap; margin-top: .5rem; }
.thumb-btn { padding: 0; border: 2px solid transparent; border-radius: 8px; background: none; cursor: pointer; } .thumb-btn:hover, .thumb-btn:focus { border-color: var(--primary); outline: none; }
.thumb-btn img { width: 72px; height: 72px; object-fit: cover; border-radius: 6px; display: block; }
.gallery-empty { text-align: center; padding: 1.5rem 1rem; border: 1px dashed var(--border); border-radius: 10px; } .gallery-empty .big { font-size: 2rem; }
.lightbox img { width: 100%; max-height: 70vh; object-fit: contain; border-radius: 8px; background: #000; display: block; }
.tag-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: .15rem .6rem; } .tag-grid .check { margin: 0; font-size: .86rem; }
.seg { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; align-self: end; } .seg button { border: 0; background: var(--panel); padding: .4rem .6rem; cursor: pointer; color: var(--muted); }
.seg button.active { background: var(--primary); color: #fff; }
@media (max-width: 640px) { .gallery .hero img { max-height: 240px; } .thumb-btn img { width: 60px; height: 60px; } }

/* clickable cards and bars */
a.card.link, a.bar.link { color: inherit; text-decoration: none; cursor: pointer; }
a.card.link:hover, a.card.link:focus-visible { border-color: var(--primary); box-shadow: 0 4px 14px rgba(0,0,0,.12); transform: translateY(-1px); outline: none; }
a.card.link::after { content: '›'; position: absolute; right: .7rem; top: .5rem; color: var(--muted); font-size: 1rem; opacity: .6; } a.card.link { position: relative; transition: transform .08s, box-shadow .08s; }
a.bar.link:hover .lbl { color: var(--primary); text-decoration: underline; } a.bar.link:hover .fil { filter: brightness(1.15); }
.today-item.link { cursor: pointer; } .today-item.link:hover { background: var(--panel-2); border-radius: 6px; }

/* form library & filler */
.tpl-card { display: flex; gap: .9rem; } .tpl-card:hover { border-color: var(--primary); } .tpl-card.inactive { opacity: .6; }
.tpl-icon { font-size: 1.8rem; line-height: 1; padding-top: .1rem; } .tpl-desc { margin: .25rem 0; color: var(--text); } .btn-row.tight { margin-top: .5rem; gap: .35rem; }
.tpl-open-name { background: none; border: none; padding: 0; margin: 0; font: inherit; font-weight: 700; color: inherit; cursor: pointer; text-align: left; } .tpl-open-name:hover { color: var(--primary); text-decoration: underline; }
.designer { display: flex; flex-direction: column; gap: .4rem; } .dfield { display: flex; gap: .6rem; align-items: flex-start; padding: .45rem .55rem; border: 1px solid var(--border); border-radius: 8px; background: var(--panel-2); }
.dfield.section { background: var(--info-soft); } .dfield.note { background: var(--panel); } .dfield .dgrip { width: 1.4rem; padding-top: .5rem; text-align: right; } .dfield select { max-width: 170px; } .dfield input { min-width: 0; }
.dfield .row.small label { display: inline-flex; align-items: center; gap: .3rem; margin-right: .6rem; } .dfield .row.small select { max-width: 200px; }
.ff .ff-section { grid-column: 1 / -1; margin: .6rem 0 .2rem; padding-bottom: .2rem; border-bottom: 1px solid var(--border); } .ff .ff-note { grid-column: 1 / -1; margin: 0 0 .4rem; }
.ff input.sig { font-family: 'Segoe Script', 'Brush Script MT', cursive; font-size: 1.15rem; } .ff input:disabled, .ff textarea:disabled, .ff select:disabled { background: var(--panel-2); color: var(--text); opacity: .9; }
.ff-modal { max-width: 900px; } .btn.ok { background: var(--ok); color: #fff; border-color: var(--ok); }
@media (max-width: 640px) { .dfield { flex-wrap: wrap; } .dfield .row.small { flex-wrap: wrap; } }

/* phones: tables become stacked cards, one row per record, each cell labelled */
@media (max-width: 640px) {
  .table-wrap { border: 0; }
  table.cards, .table-wrap table { display: block; }
  .table-wrap thead { display: none; }
  .table-wrap tbody { display: block; }
  .table-wrap tr { display: block; border: 1px solid var(--border); border-radius: 10px; margin-bottom: .6rem; padding: .35rem .6rem; background: var(--panel); }
  .table-wrap tr.click { cursor: pointer; }
  .table-wrap td { display: flex; gap: .6rem; align-items: baseline; border: 0; padding: .28rem 0; text-align: left; }
  .table-wrap td.num { text-align: left; }
  .table-wrap td[data-label]:not([data-label=""])::before { content: attr(data-label); flex: 0 0 34%; color: var(--muted); font-size: .78rem; text-transform: uppercase; letter-spacing: .02em; padding-top: .1rem; }
  .table-wrap td:empty { display: none; }
}
/* Settings › Security status: a long unbroken value (the audit anchor directory, a key id, the mono "Where" column)
   wraps instead of widening its table into a scrolling region at phone width (axe: scrollable-region-focusable). */
[data-security-status] td { overflow-wrap: anywhere; }
[data-security-status] td > * { min-width: 0; overflow-wrap: anywhere; }

/* ---------- accessibility and persistent messages ---------- */
/* Visually hidden but still announced by a screen reader. */
.skip-link { position: absolute; left: -9999px; top: .5rem; z-index: 100; background: var(--panel); color: var(--primary); padding: .5rem .8rem; border-radius: 6px; border: 1px solid var(--border); }
.skip-link:focus { left: .5rem; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
#banners { position: sticky; top: 0; z-index: 60; }
/* 1.23.1: on a phone the open menu drawer (40) and its shade (35) cover the banners, which sat over the drawer's
   brand and programme name. */
@media (max-width: 900px) { body.nav-open #banners { z-index: 30; } }
.banner {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; justify-content: space-between;
  padding: .6rem 1rem; font-size: .95rem; border-bottom: 1px solid var(--line);
  background: var(--warn-bg, #fff4d6); color: var(--warn-fg, #5a4200);
}
.banner.error { background: var(--err-bg, #fde8e8); color: var(--err-fg, #7a1b1b); }
.banner.ok { background: var(--ok-bg, #e6f6ec); color: var(--ok-fg, #14532d); }

/* A clickable table row is a button: it must show focus and respond to the keyboard. */
tr.click { cursor: pointer; }
tr.click:focus-visible,
[role="button"]:focus-visible,
.card.link:focus-visible {
  outline: 3px solid var(--focus, #2563eb);
  outline-offset: -3px;
}
/* Never remove the focus ring without replacing it. */
:focus-visible { outline: 3px solid var(--focus, #2563eb); outline-offset: 2px; }

.boot.error { color: var(--err-fg, #7a1b1b); }

/* Keyboard highlight in the client picker's list of matches. */
.list-item.active, .list-item:hover { background: var(--hover, rgba(0, 0, 0, .05)); }

/* ---------- phone review round: large text, tap targets ---------- */
/* Nothing in a form may be wider than the screen at 200% text: grid and flex children shrink, rows wrap. */
.form-grid > *, .field, .row > *, .filters > *, .card, .grid > * { min-width: 0; }
input, select, textarea { max-width: 100%; }
.field label { overflow-wrap: anywhere; }
/* "Edit this list" / "Manage" beside a list-driven field's label (Settings → Lists). */
.field > .field-link { float: right; font-weight: normal; margin-left: .5rem; }
@media (max-width: 900px) {
  /* 1fr alone lets the widest thing on the page (a card grid, the search bar) set the column's minimum. */
  .layout { grid-template-columns: minmax(0, 1fr); }
  .btn { white-space: normal; text-align: center; }
  .btn-row { justify-content: flex-start; }
  .modal .card-head h2 { min-width: 0; overflow-wrap: anywhere; }
  .kv { grid-template-columns: minmax(5.5em, 38%) minmax(0, 1fr); }
  .kv dt { overflow-wrap: anywhere; }
  .mobilebar-title > b { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 1rem; }
  .gsearch { min-width: 0; }
  .appbar { flex-wrap: wrap; }
}
@media (pointer: coarse) {
  /* A checkbox is 24px to look at but 44px to hit: its label is the target (tasks.js, dashboard.js). */
  .tap-target { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; margin: 0; cursor: pointer; flex: 0 0 auto; }
  .today-item .check, .outreach-foot .check, .today-open { min-height: 44px; }
  .today-item { padding: .35rem 0; }
  a.bar.link { min-height: 44px; }
}
/* A figure of money is one word. */
.money { white-space: nowrap; font-variant-numeric: tabular-nums; }
/* The + Log sheet at large text: a long word ("paperwork…)") set the column wider than the screen. */
.quick-list { grid-template-columns: minmax(0, 1fr); } .quick-list .btn { min-width: 0; overflow-wrap: anywhere; }
/* The closed drawer's shadow bled 40px into the left edge of every phone screen. */
@media (max-width: 900px) { .sidebar:not(.open) { box-shadow: none; } }

/* Client header badges are a list (screen readers meet each on its own); look unchanged. */
ul.badge-list { list-style: none; margin: 0; padding: 0; }
ul.badge-list > li { display: contents; }
/* A picture dragged over a resource profile's Pictures card (public/views/resources.js). */
.card.drop-over { outline: 2px dashed var(--primary); outline-offset: -4px; background: var(--primary-soft); }

/* ---------- WCAG 2.1 AA (docs/accessibility/DEVELOPERS.md) ---------- */
/* 1.4.1: a link inside text is underlined, not told apart by colour alone. Controls that look like buttons,
   cards, navigation and list rows are already obviously interactive and keep their own look. */
a { text-decoration: underline; text-underline-offset: .15em; }
a.btn, .nav a, a.list-item, a.card, a.bar, a.bell, a.chip, a.badge, .mobilebar a, .skip-link, a.res-card { text-decoration: none; }
a.btn:hover, a.card:hover, .nav a:hover, a.list-item:hover { text-decoration: none; }
/* 2.4.7 / 1.4.11: one focus ring for everything the keyboard reaches, 3:1 against the page in both themes.
   Form fields used to show only a pale ring (--primary-soft) and a 1px border change. */
:root { --focus: #1d4ed8; --on-fill: #fff; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --focus: #7cb7ff; --on-fill: #0b1219;
  --warn-bg: #3a2f16; --warn-fg: #f5dca8; --err-bg: #3a1f1c; --err-fg: #ffc2b8; --ok-bg: #173325; --ok-fg: #bff0d2; } }
:root[data-theme="dark"] { --focus: #7cb7ff; --on-fill: #0b1219;
  --warn-bg: #3a2f16; --warn-fg: #f5dca8; --err-bg: #3a1f1c; --err-fg: #ffc2b8; --ok-bg: #173325; --ok-fg: #bff0d2; }
/* 1.4.11: a text field's edge is what shows where to type, so it is 3:1 against the card and the page. */
:root { --input-border: #7d8a99; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --input-border: #66788c; } }
:root[data-theme="dark"] { --input-border: #66788c; }
.btn.primary, .btn.primary:hover, .seg button.active, button.chip:hover, .toast.error, .toast.ok, .bell-count, .btn.ok { color: var(--on-fill); }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--focus); outline-offset: 1px; border-color: var(--focus); }
.thumb-btn:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
/* The idle sign-out warning (2.2.1) reads in either theme, with its button. */
.idle-warn { background: #7a4a00; color: #fff; display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; justify-content: center; }
.idle-warn .btn { background: #fff; color: #5a3600; border-color: #fff; }
/* A badge wraps between words, never inside one ("Cont-acted" at 1280 px): break-word, unlike anywhere, does
   not shrink a table column below its longest word. In a table on a wide screen (inside its scrolling
   wrapper) a status badge stays on one line. */
.badge { max-width: 100%; white-space: normal; overflow-wrap: break-word; }
@media (min-width: 901px) { table .badge { white-space: nowrap; } }
.mfa-link { text-decoration: none; white-space: nowrap; }
/* 1.4.1 / 4.1.2: a filter that is on or off is a toggle button with aria-pressed; when on it shows a check mark, not
   only the primary colour (the To-dos list's "Assigned to me" and "Overdue", 1.23.5). The mark is not read out: the
   button's pressed state already is. */
.btn[aria-pressed="true"]::before { content: "\2713"; content: "\2713" / ""; font-weight: 700; }
/* A button's words wrap inside it rather than running out of it at large text sizes. */
.btn { white-space: normal; }
.kv dt { overflow-wrap: anywhere; }
/* table({ onRow }): the first cell's content is the row's button; it looks like the text it was. */
.row-open { font: inherit; color: inherit; background: none; border: 0; padding: 0; margin: 0; text-align: inherit; cursor: pointer; display: block; width: 100%; line-height: inherit; }
.row-open:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 3px; }
tr.click:focus-within td { background: var(--panel-2); }
/* flag() in app.js: an at-risk value carries ⚠ and a reason, not only a colour (1.4.1). */
.flag.danger { color: var(--danger); font-weight: 600; } .flag.warn { color: var(--warn); font-weight: 600; } .flag.ok { color: var(--ok); font-weight: 600; }
/* The sign-in and first-run screens name the product in their level-one heading, sized as the brand. */
.brand .brand-title { font-size: 1.05rem; margin: 0; font-weight: 700; line-height: 1.25; }
.a11y-link { margin: .75rem 0 0; }
/* Focus moved to a page's <main> or heading (skip link, a new page) is where reading starts, not a control:
   no ring around the whole page. */
main[tabindex="-1"]:focus, h1[tabindex="-1"]:focus { outline: none; }
input::-webkit-calendar-picker-indicator:focus-visible { outline: 2px solid var(--focus); border-radius: 2px; }
/* A focusable scrolling region (app.js scrollRegions) shows its ring inside the frame. */
.table-wrap:focus-visible, .table-scroll:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; }
.table-scroll { overflow-x: auto; max-width: 100%; }
/* A link inside a coloured banner takes the banner's text colour (always 4.5:1 on it) and stays underlined. */
.banner a:not(.btn) { color: inherit; font-weight: 600; }
/* Visually hidden means 1px whatever else applies to the element (a file input in a .row is width: auto). */
.sr-only { width: 1px !important; height: 1px !important; max-width: 1px !important; }

/* ---- Sidebar "More" group: a front-line worker's less-used pages, folded away (app.js sidebar()) ---- */
.nav-more { margin-top: .4rem; }
.nav-more > summary { cursor: pointer; padding: .5rem .65rem; border-radius: 8px; color: var(--muted); font-weight: 600; font-size: .85rem; list-style-position: inside; }
.nav-more > summary:hover { background: var(--panel-2); color: var(--text); }
@media (pointer: coarse) { .nav-more > summary { min-height: 44px; padding: .75rem .65rem; box-sizing: border-box; } }

/* ---- Client record on a phone (views/client.js): one "Add…" button instead of a wall of buttons, so the
   section tabs start in the upper half of the screen. ---- */
.client-actions.narrow { display: none; }
.add-list { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .5rem; }
@media (max-width: 600px) {
  .client-actions.wide { display: none; }
  .client-actions.narrow { display: block; }
  .client-record .topbar { gap: .5rem; margin-bottom: .6rem; }
  .client-record .topbar h1 { margin: 0 0 .25rem; }
  .client-record .badge-list { gap: .25rem; }
  /* A banner someone already dismissed once comes back as one line (app.js banner({ compact })). */
}
.banner.compact { padding: .3rem .6rem; margin-bottom: .5rem; display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.banner.compact > span { flex: 1 1 12rem; min-width: 0; }
/* A folded form section whose title is a heading (app.js form(), section heading: true). */
details.section > summary .summary-heading { display: inline; font-size: 1rem; margin: 0; font-weight: 600; }
/* A tab strip with everyday sections on a phone (app.js tabStrip core): they wrap rather than hide. */
.tabs.managed.core-wrap { flex-wrap: wrap; row-gap: 0; }
/* A standing message across the top keeps its dismiss button beside the text, not on a line of its own. */
#banners > .banner { flex-wrap: nowrap; align-items: flex-start; }
#banners > .banner > span { flex: 1 1 auto; min-width: 0; }
#banners > .banner > button, #banners > .banner > a.btn { flex: 0 0 auto; }
#banners > .banner.compact { align-items: center; margin-bottom: 0; padding: .25rem .6rem; }
@media (max-width: 600px) { #banners > .banner { padding: .45rem .75rem; font-size: .88rem; } .client-record .badge { font-size: .72rem; } }
/* The two-step verification reminder (app.js loadSession): one short line on a phone, the deadline kept. */
.mfa-short { display: none; }
@media (max-width: 600px) { #banners > .banner.compact[data-banner="mfa-required"] { padding-top: 0; padding-bottom: 0; } [data-banner="mfa-required"] .mfa-long { display: none; } [data-banner="mfa-required"] .mfa-short { display: inline; } }

/* ---- Supplies given on a visit (views/interventions.js supplyPicker): each item a row with a − count +
   stepper, one tap each; the name wraps, the stepper keeps its place, nothing scrolls sideways at 320px. ---- */
.supply-picker { margin-top: .5rem; }
.supply-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .35rem .75rem; padding: .3rem 0; border-bottom: 1px solid var(--border); }
.supply-row > label { flex: 1 1 10rem; min-width: 0; overflow-wrap: anywhere; font-weight: 600; }
.supply-step { gap: .3rem; flex: 0 0 auto; }
.supply-step input.supply-qty { width: 4.5rem; text-align: center; }
.supply-add { margin-top: .5rem; gap: .4rem; }
.supply-add select { flex: 1 1 10rem; min-width: 0; max-width: 100%; }

/* ---- Street outreach (views/outreach.js): one screen, one hand, at 390px. Every control is at least 48px tall,
   the − and + sit on the right where a thumb reaches, the item name wraps, and nothing scrolls sideways at 320px. */
.outreach { max-width: 40rem; }
.outreach-form fieldset { border: 0; padding: 0; margin: 0 0 1rem; min-width: 0; }
.outreach-form legend { font-weight: 650; font-size: 1rem; margin-bottom: .4rem; padding: 0; }
.outreach-types { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr)); gap: .5rem; }
.outreach-type { display: flex; align-items: center; gap: .6rem; min-height: 3.25rem; padding: .5rem .8rem; border: 2px solid var(--border); border-radius: var(--radius); background: var(--panel-2); cursor: pointer; font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
.outreach-type input { width: 1.35rem; height: 1.35rem; flex: 0 0 auto; margin: 0; accent-color: var(--primary); }
.outreach-type:has(input:checked) { border-color: var(--primary); background: var(--primary-soft); }
.outreach-type:has(input:focus-visible) { outline: 3px solid var(--focus, var(--primary)); outline-offset: 2px; }
.outreach-item { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .35rem .75rem; padding: .45rem 0; border-bottom: 1px solid var(--border); }
.outreach-item > label { flex: 1 1 8rem; min-width: 0; overflow-wrap: anywhere; font-weight: 600; font-size: 1rem; }
.outreach-step { display: flex; align-items: center; gap: .4rem; flex: 0 0 auto; margin-left: auto; }
.outreach-btn { min-width: 3rem; min-height: 3rem; padding: 0; justify-content: center; font-size: 1.5rem; line-height: 1; font-weight: 700; }
.outreach-qty { width: 3.75rem; min-height: 3rem; text-align: center; font-size: 1.15rem; font-weight: 650; }
.outreach-other { margin-top: .6rem; } .outreach-other > label { display: block; font-weight: 600; margin-bottom: .25rem; }
.outreach-other .row { gap: .5rem; flex-wrap: nowrap; } .outreach-other select { flex: 1 1 auto; min-width: 0; }
.outreach-other .btn, .outreach-where select, .outreach-other select { min-height: 3rem; }
.outreach-where { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr)); gap: .5rem .75rem; }
.outreach-where select { width: 100%; }
.outreach-notes textarea { width: 100%; font-size: 1rem; }
.outreach-save { width: 100%; min-height: 3.5rem; font-size: 1.15rem; justify-content: center; margin-top: .5rem; }
.outreach-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .5rem; margin-bottom: .75rem; }
.outreach-list { margin: 0 0 .75rem; padding-left: 1.1rem; } .outreach-list li { margin: .2rem 0; overflow-wrap: anywhere; }
.outreach-foot { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: .5rem 1rem; margin: 1rem 0 5rem; }
.outreach-foot .check { margin-top: 0; }
.outreach-where { margin-bottom: 1rem; }
.outreach-newshift { min-height: 3rem; min-width: 3rem; }
/* The screen is itself the logger: the floating + Log button would only cover the − / + counters (r10 M2). */
body:has([data-outreach]) .fab { display: none; }
/* 1.22.0: Save contact stays in reach of the thumb at the foot of the screen while the counts are filled in (at 390px
   it was a scroll below them on every contact), and a focused field is never scrolled in under it. */
.outreach-savebar { position: sticky; bottom: 0; z-index: 5; background: var(--panel); padding: .5rem 0 calc(.5rem + env(safe-area-inset-bottom)); margin: .5rem 0 -.25rem; border-top: 1px solid var(--border); }
.outreach-savebar .outreach-save { margin-top: 0; }
html:has([data-outreach]) { scroll-padding-bottom: 6rem; }
.outreach-same { width: 100%; min-height: 3rem; justify-content: flex-start; text-align: left; white-space: normal; margin-bottom: .5rem; overflow-wrap: anywhere; }
.outreach-same[hidden] { display: none; }
.queue-chip[hidden], .outreach-waiting[hidden] { display: none; }
/* The header's sync state on a device that syncs with the office (app.js syncChip). */
.sync-chip { text-decoration: none; white-space: nowrap; }
.sync-chip.pending { border-color: var(--warn); color: var(--text); background: var(--warn-soft, transparent); font-weight: 650; }
.sync-chip .sync-short { display: none; }
/* On a phone the short form shows; the words stay in the link's name for a screen reader (visually hidden, not removed). */
@media (max-width: 600px) {
  .sync-chip .sync-short { display: inline; }
  .sync-chip .sync-long { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
/* Quick choices under a due or follow-up date (app.js quickDates). */
.quick-dates { gap: .35rem; flex-wrap: wrap; margin-top: .35rem; }
.quick-dates .btn { min-height: 2.25rem; }
/* State reporting › Settings: one row of fields per CalOMS provider (views/caloms.js providerEditor). */
.caloms-prov { border: 1px solid var(--border); border-radius: var(--radius); padding: .5rem .75rem .75rem; margin: 0 0 .75rem; min-width: 0; }
.caloms-prov legend { font-weight: 650; padding: 0 .25rem; }
.caloms-prov .grid { gap: .25rem .75rem; }

/* ---- Settlement outcomes (views/settlement.js): a card per fund, spending beside outcomes; prints as a report. ---- */
.settlement-fund .kv { margin-bottom: .75rem; }
.settlement-note { max-width: 60rem; }
@media print { .settlement-print-head { display: block !important; } .settlement-controls { display: none !important; } .settlement-fund { break-inside: avoid; } }
.settlement-print-head { display: none; }
.settlement-controls .field:has(#so-counts) { flex: 1 1 14rem; } .settlement-controls #so-counts { width: 100%; max-width: 100%; }
/* ---- The county view and Send to the county (views/county.js, views/settlement.js; docs/COUNTY-VIEW.md). ---- */
/* A public key is one long base-64 run per line: it wraps anywhere rather than pushing a phone sideways. */
pre.county-pem { overflow-wrap: anywhere; word-break: break-all; }
.county-code code { font-size: 1.4rem; letter-spacing: .08em; }
.county-period { font-size: 1.05rem; margin: .5rem 0; }
[data-so-county-funds] { border: 0; padding: 0; margin: 0; min-width: 0; }
[data-so-county-funds] legend { font-weight: 600; margin-bottom: .3rem; }
[data-so-county-funds] .check { display: flex; gap: .5rem; align-items: baseline; margin: .2rem 0; overflow-wrap: anywhere; }

/* ---- Navigation (1.14.0 usability): a sideways-scrolling tab strip says it scrolls, the welcome card on
   Home, and the phone's Clients shortcut. ---- */
/* app.js pageTabs: a chevron on the side that has more tabs, instead of a faded, cut-off last label. */
.tabs-scroll { position: relative; margin-bottom: 1rem; }
.tabs-scroll > .tabs { margin-bottom: 0; -webkit-mask-image: none; mask-image: none; scrollbar-width: none; position: relative; } /* relative: a tab's screen-reader-only text (position: absolute) stays inside the scroller, not past the page's edge */
.tabs-scroll > .tabs::-webkit-scrollbar { display: none; }
.tabs-cue { display: none; position: absolute; top: 0; bottom: 1px; width: 2.5rem; z-index: 2; align-items: center; font-size: 1.5rem; font-weight: 700; line-height: 1; color: var(--primary); cursor: pointer; user-select: none; }
.tabs-cue.right { right: 0; justify-content: flex-end; padding-right: .2rem; background: linear-gradient(to right, transparent, var(--bg) 55%); }
.tabs-cue.left { left: 0; justify-content: flex-start; padding-left: .2rem; background: linear-gradient(to left, transparent, var(--bg) 55%); }
.tabs-scroll.more-right > .tabs-cue.right, .tabs-scroll.more-left > .tabs-cue.left { display: flex; }
/* dashboard.js: the welcome, once, beside everything else on Home (it was a dialog over all of it). */
.welcome-card { border-left: 4px solid var(--primary); }
.welcome-card .welcome-close { font-size: 1.25rem; line-height: 1; min-width: 44px; min-height: 44px; padding: 0; }
/* Home's program-wide cards fold away (1.23.0): the heading is the summary, with the usual disclosure triangle. */
details.home-fold > summary { cursor: pointer; display: flex; align-items: center; flex-wrap: wrap; gap: .25rem .5rem; }
@media (pointer: coarse) { details.home-fold > summary { min-height: 44px; } }
details.home-fold > summary::before { content: '▸' / ''; color: var(--muted); }
details.home-fold[open] > summary::before { content: '▾' / ''; }
details.home-fold > summary::-webkit-details-marker { display: none; }
details.home-fold > summary h2 { margin: 0; }
details.home-fold[open] > summary { margin-bottom: .6rem; }
details.home-fold:not(.card) > summary { margin-bottom: .4rem; }
.home-alerts { gap: .4rem; }
/* 1.23.1, a 390 px phone: the + Log button (fixed, bottom right) covered the Part 2 notice badge. The alert badges
   stop short of the button's column, wherever the page is scrolled, and wrap instead. */
@media (max-width: 900px) { .home-alerts > a.badge { max-width: calc(100% - 7.5rem); } }
.home-foot { margin-top: 1rem; }
.welcome-steps { margin: .25rem 0 .75rem; padding-left: 1.1rem; } .welcome-steps li { margin: .3rem 0; }
/* The phone's top-right shortcut to the client list says what it is (a lone 👤 read as "my account"). */
.mobilebar a.mobilebar-clients { font-size: .9rem; font-weight: 600; display: inline-flex; align-items: center; gap: .3rem; }
/* With a word in it the top bar has to fit at 200% text too: the page title takes the room left and wraps. */
.mobilebar-title { flex: 1 1 0; min-width: 0; } .mobilebar-title b { overflow-wrap: anywhere; text-align: center; } .mobilebar a.mobilebar-clients { flex: 0 1 auto; min-width: 0; }
/* The bell's count stays inside the bell's own box, so nothing past the screen's edge can clip it. */
.bell { padding-right: .55rem; } .bell-count { right: 0; top: -.1rem; }
.mobilebar-spacer { width: 44px; flex: 0 0 auto; }

/* ---- A dialog's actions stay in view (1.14.0): the row of buttons at the end of a dialog (Save, Cancel)
   sticks to the bottom of the screen while the dialog is taller than it, so Save is never below the fold.
   Only the dialog's own last row (a form's, or a confirmation's), never a button row inside a banner or card.
   It stays where it is in the page, so the Tab order and what a screen reader reads are unchanged; at the end
   of the dialog it sits under the last field in its own space, and the scroll padding keeps a field that
   takes the focus clear of it. ---- */
.modal-bg { scroll-padding-bottom: 5.5rem; }
.modal form > .btn-row:last-child, .modal > .btn-row:last-child, .modal > div > .btn-row:last-child {
  /* The dialog's backdrop is padded 3vh top and bottom, and a sticky box stops at that padding: -3vh puts the
     row on the screen's bottom edge, with nothing of the form showing beneath it. */
  position: sticky; bottom: -3vh; z-index: 3; background: var(--panel);
  margin: 1rem -1.4rem 0; padding: .7rem 1.4rem; border-top: 1px solid var(--border);
  box-shadow: 0 -6px 12px -10px rgba(0,0,0,.35);
}
@media (max-width: 900px) {
  .modal form > .btn-row:last-child, .modal > .btn-row:last-child, .modal > div > .btn-row:last-child {
    bottom: 0; margin-left: -1rem; margin-right: -1rem; padding: .6rem 1rem calc(.6rem + env(safe-area-inset-bottom));
  }
}

/* ---- A visit's disclosure sections (views/interventions.js): the everyday fields show, the rest fold away
   under a heading that says what is inside and, folded, what it holds now. ---- */
details.section > summary [data-section-hint] { font-weight: 400; }
.supply-notice { margin: .5rem 0 0; }
/* A field, row or notice a dialog hides (the referral's outcome while it is under way, a step set aside). */
.modal [hidden] { display: none !important; }
.step-heading { font-size: 1.05rem; margin: 0 0 .25rem; }
.readmit-panel { margin-top: .5rem; }
/* The owner's recovery code, shown once (views/local.js): large, spaced, and wrapping on a narrow screen. */
.recovery-code { margin: 0 0 1rem; font-family: var(--mono); font-size: 1.35rem; letter-spacing: .06em; line-height: 1.6; background: var(--panel-2); color: var(--text); border: 1px solid var(--border); border-radius: 8px; padding: .75rem 1rem; overflow-wrap: anywhere; user-select: all; }
/* "Can't sign in?" on a device's sign-in page: the ways back in, and what each keeps. */
.cant-sign-in { border-top: 1px solid var(--border); padding-top: .75rem; }
.cant-sign-in ul { margin: .25rem 0 0; padding-left: 1.1rem; }
.cant-sign-in li { margin-bottom: .4rem; }
/* The funder report's downloads: each file's button with a line saying what it is for. */
.download-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; }
.download-list li { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
.download-list li span { flex: 1 1 16rem; min-width: 0; }
/* Keyboard shortcuts list (1.15.3) */
kbd { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .85em; padding: .1rem .4rem; border: 1px solid var(--border); border-bottom-width: 2px; border-radius: 4px; background: var(--panel-2); color: var(--text); white-space: nowrap; }
/* "Your first day" in the welcome card (1.15.3) */
.first-day { margin: .25rem 0 .75rem; padding-left: 1.25rem; }
.first-day li { margin-bottom: .6rem; }
.first-day-row { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: .5rem; }
.welcome-tips { margin-bottom: .75rem; }
/* A tab strip that wraps rather than scrolls (Settings, 1.15.3): every tab stays inside the page at 200% zoom. */
.tabs.wrapped { flex-wrap: wrap; overflow: visible; row-gap: 0; -webkit-mask-image: none; mask-image: none; scroll-snap-type: none; }
/* One control or line for a phone, another for wider screens (r9 L5): Notes' Import folds into More. */
.phone-only { display: none; }
@media (max-width: 640px) {
  .wide-only { display: none !important; }
  .phone-only { display: revert; }
  .banner.phone-line { padding-top: .3rem; padding-bottom: .3rem; }
}
details.more-menu > summary { list-style: none; } details.more-menu > summary::-webkit-details-marker { display: none; }
details.more-menu > summary::after { content: " ▾" / ""; } details.more-menu[open] > summary::after { content: " ▴" / ""; }
details.more-menu[open] { flex-basis: 100%; } details.more-menu > a { margin-top: .4rem; }
/* A table wider than its card (r9 L4): said above it, in words. */
.scroll-hint { margin: 0 0 .3rem; }
/* "Confirm with fingerprint" in a signature or approval dialog, and "Sign in with fingerprint" (docs/FINGERPRINT.md). */
.fingerprint-confirm { margin: .75rem 0; padding: .6rem .75rem; border: 1px solid var(--border); border-radius: 8px; }
.fingerprint-confirm p { margin: .35rem 0 0; }
.fingerprint-btn { min-height: 44px; }
.fingerprint-btn[aria-disabled="true"] { cursor: progress; }
.fp-icon { vertical-align: -4px; }
.or-use { margin: .25rem 0 .5rem; }
[data-fingerprint-status]:empty { display: none; }
