bq14 = daily_occ.filter(r => r.date === "2026-05-14")
function bq(key) { return bq14.find(r => r.key === key) }
function cr(key) { return city_ref.find(r => r.key === key) }
function n(v) { return v !== null && v !== undefined ? (+v).toLocaleString() : "—" }
function pct(v) { return v !== null && v !== undefined ? (+v).toFixed(1) + "%" : "—" }
// Known-difference keys (capacity/rate only — ind and occ match)
KNOWN_CAP_KEYS = new Set(["mix_emerg","men_emerg","wom_emerg","yth_emerg","emerg_total","singles_total"])
function mark(bqVal, cityVal, isCapOrRate, key) {
if (cityVal === null || cityVal === undefined) return ""
if (bqVal === null || bqVal === undefined) return ""
const match = Math.abs(+bqVal - +cityVal) < 0.11
if (match) return `<span style="color:#1a7a4a;font-weight:bold">✓</span>`
if (isCapOrRate && KNOWN_CAP_KEYS.has(key))
return `<span style="color:#b06000;font-weight:bold" title="Known difference — see notes">≈</span>`
return `<span style="color:#c0392b;font-weight:bold">✗</span>`
}
function compRow(key, bqRow, cityRow, opts = {}) {
const { indent = 0, isTot = false, summaryOnly = false } = opts
const pad = indent * 16
const bold = isTot ? "font-weight:600" : ""
const bg = isTot ? "#e8edf5" : "#fff"
if (!bqRow || !cityRow) return ""
const useCap = bqRow.col_type !== "summary"
if (summaryOnly || bqRow.col_type === "summary") {
return `<tr style="background:${bg}">
<td style="padding:5px 10px 5px ${pad}px;${bold}">${bqRow.label}</td>
<td style="padding:5px 8px;text-align:right;${bold}">
${n(bqRow.ind)} ${mark(bqRow.ind, cityRow.city_ind, false, key)}</td>
<td style="padding:5px 8px;text-align:right;color:#888">${n(cityRow.city_ind)}</td>
<td colspan="6"></td>
</tr>`
}
return `<tr style="background:${bg}">
<td style="padding:5px 10px 5px ${pad}px;${bold}">${bqRow.label}</td>
<td style="padding:5px 8px;text-align:right;${bold}">
${n(bqRow.ind)} ${mark(bqRow.ind, cityRow.city_ind, false, key)}</td>
<td style="padding:5px 8px;text-align:right;color:#888">${n(cityRow.city_ind)}</td>
<td style="padding:5px 8px;text-align:right">
${n(bqRow.occ)} ${mark(bqRow.occ, cityRow.city_occ, false, key)}</td>
<td style="padding:5px 8px;text-align:right;color:#888">${n(cityRow.city_occ)}</td>
<td style="padding:5px 8px;text-align:right">
${n(bqRow.unocc)} ${mark(bqRow.unocc, cityRow.city_unocc, true, key)}</td>
<td style="padding:5px 8px;text-align:right;color:#888">${n(cityRow.city_unocc)}</td>
<td style="padding:5px 8px;text-align:right">
${n(bqRow.cap)} ${mark(bqRow.cap, cityRow.city_cap, true, key)}</td>
<td style="padding:5px 8px;text-align:right;color:#888">${n(cityRow.city_cap)}</td>
<td style="padding:5px 8px;text-align:right">
${pct(bqRow.rate)} ${mark(bqRow.rate, cityRow.city_rate, true, key)}</td>
<td style="padding:5px 8px;text-align:right;color:#888">${pct(cityRow.city_rate)}</td>
</tr>`
}
function secHead(label, col1) {
return `<tr style="background:#1a3c6b;color:white;font-weight:600;font-size:0.82em">
<td style="padding:6px 10px" rowspan="2">${label}</td>
<td style="padding:6px 8px;text-align:center" colspan="2">Individuals</td>
<td style="padding:6px 8px;text-align:center" colspan="2">${col1[0]}</td>
<td style="padding:6px 8px;text-align:center" colspan="2">${col1[1]}</td>
<td style="padding:6px 8px;text-align:center" colspan="2">${col1[2]}</td>
<td style="padding:6px 8px;text-align:center" colspan="2">Occupancy Rate</td>
</tr>
<tr style="background:#2c5282;color:#cfe0f7;font-size:0.78em">
<td style="padding:3px 8px;text-align:center">BQ</td>
<td style="padding:3px 8px;text-align:center">City</td>
<td style="padding:3px 8px;text-align:center">BQ</td>
<td style="padding:3px 8px;text-align:center">City</td>
<td style="padding:3px 8px;text-align:center">BQ</td>
<td style="padding:3px 8px;text-align:center">City</td>
<td style="padding:3px 8px;text-align:center">BQ</td>
<td style="padding:3px 8px;text-align:center">City</td>
<td style="padding:3px 8px;text-align:center">BQ</td>
<td style="padding:3px 8px;text-align:center">City</td>
</tr>`
}
function summarySecHead() {
return `<tr style="background:#1a3c6b;color:white;font-weight:600;font-size:0.82em">
<td style="padding:6px 10px" rowspan="2">Occupancy Summary</td>
<td style="padding:6px 8px;text-align:center" colspan="2">Individuals</td>
<td colspan="8"></td>
</tr>
<tr style="background:#2c5282;color:#cfe0f7;font-size:0.78em">
<td style="padding:3px 8px;text-align:center">BQ</td>
<td style="padding:3px 8px;text-align:center">City</td>
<td colspan="8"></td>
</tr>`
}
bridgingRow = `<tr style="background:#f5f5f5;color:#888">
<td style="padding:5px 10px 5px 20px;font-style:italic">Bridging & Triage Programs</td>
<td style="padding:5px 8px;text-align:right;font-size:0.85em" colspan="2">Not published to open data (29 people)</td>
<td colspan="8"></td>
</tr>`
compTable = {
const rows = [
"all_shelter","room_based","singles_sector","singles_shelter","allied_summ","temp_summ","iso_summ"
]
return html`
<div style="overflow-x:auto;margin:1rem 0">
<table style="border-collapse:collapse;width:100%;font-size:0.83em;font-family:'Segoe UI',Arial,sans-serif;min-width:800px">
${summarySecHead()}
${compRow("all_shelter", bq("all_shelter"), cr("all_shelter"), {isTot:true, summaryOnly:true})}
${bridgingRow}
${compRow("room_based", bq("room_based"), cr("room_based"), {indent:1, summaryOnly:true})}
${compRow("singles_sector", bq("singles_sector"), {city_ind:5727}, {indent:1, summaryOnly:true})}
${compRow("singles_shelter", bq("singles_shelter"),cr("singles_total"), {indent:2, summaryOnly:true})}
${compRow("allied_summ", bq("allied_summ"), cr("allied_total"), {indent:2, summaryOnly:true})}
${compRow("temp_summ", bq("temp_summ"), {city_ind:1901}, {indent:2, summaryOnly:true})}
${compRow("iso_summ", bq("iso_summ"), cr("iso"), {indent:1, summaryOnly:true})}
${secHead("Shelter Programs, Room-Based", ["Occupied Rooms","Unoccupied Rooms","Actual Room Capacity"])}
${compRow("fam_total", bq("fam_total"), cr("fam_total"), {isTot:true})}
${compRow("fam_emerg", bq("fam_emerg"), cr("fam_emerg"), {indent:1})}
${compRow("fam_trans_r", bq("fam_trans_r"), cr("fam_trans_r"), {indent:1})}
${compRow("fam_hotel", bq("fam_hotel"), cr("fam_hotel"), {indent:1})}
${compRow("sng_hotel", bq("sng_hotel"), cr("sng_hotel"), {isTot:true})}
${secHead("Shelter Programs, Bed-Based", ["Occupied Beds","Unoccupied Beds","Actual Bed Capacity"])}
${compRow("singles_total", bq("singles_total"), cr("singles_total"), {isTot:true})}
${compRow("emerg_total", bq("emerg_total"), cr("emerg_total"), {indent:1, isTot:true})}
${compRow("mix_emerg", bq("mix_emerg"), cr("mix_emerg"), {indent:2})}
${compRow("men_emerg", bq("men_emerg"), cr("men_emerg"), {indent:2})}
${compRow("wom_emerg", bq("wom_emerg"), cr("wom_emerg"), {indent:2})}
${compRow("yth_emerg", bq("yth_emerg"), cr("yth_emerg"), {indent:2})}
${compRow("trans_total", bq("trans_total"), cr("trans_total"), {indent:1, isTot:true})}
${compRow("mix_trans", bq("mix_trans"), cr("mix_trans"), {indent:2})}
${compRow("fam_trans_b", bq("fam_trans_b"), cr("fam_trans_b"), {indent:2})}
${compRow("men_trans", bq("men_trans"), cr("men_trans"), {indent:2})}
${compRow("wom_trans", bq("wom_trans"), cr("wom_trans"), {indent:2})}
${compRow("yth_trans", bq("yth_trans"), cr("yth_trans"), {indent:2})}
${secHead("Allied Services", ["Occupied Spaces","Unoccupied Spaces","Actual Space Capacity"])}
${compRow("allied_total", bq("allied_total"), cr("allied_total"), {isTot:true})}
${compRow("respites", bq("respites"), cr("respites"), {indent:1})}
${compRow("dropin", bq("dropin"), cr("dropin"), {indent:1})}
${secHead("Temporary Programs (Bed/Space)", ["Occ. Beds/Spaces","Unocc. Beds/Spaces","Actual Capacity"])}
${compRow("temp_resp", bq("temp_resp"), cr("temp_resp"))}
${secHead("Temporary Programs (Room/Unit)", ["Occupied Rooms","Unoccupied Rooms","Actual Room Capacity"])}
${compRow("hotels", bq("hotels"), cr("hotels"))}
${secHead("Temporary Isolation/Recovery", ["Occupied Rooms","Unoccupied Rooms","Actual Room Capacity"])}
${compRow("iso", bq("iso"), cr("iso"))}
</table>
</div>`
}