117:function toast(msg, kind = "info", ms = 4200) { 118- let box = $("#toasts"); 119- if (!box) { box = el("div", { id: "toasts" }); document.body.append(box); } 120- const icons = { info: "ℹ", ok: "✓", err: "✕", warn: "⚠" }; 121- const t = el("div", { class: "toast " + (kind === "info" ? "" : kind) }, 122- el("span", { class: "n-ico" }, icons[kind] || "ℹ"), 123- el("span", {}, msg)); 124- box.append(t); 125- setTimeout(() => { t.style.opacity = "0"; t.style.transition = "opacity .3s"; setTimeout(() => t.remove(), 320); }, ms); 126- return t; 127-} 128- 129-/* ---------- Modal / confirm ---------- */ 130-function openModal(title, bodyNode, { buttons = [], wide = false, xw = false, onClose } = {}) { 131- const back = el("div", { class: "modal-back open" }); 132- const modal = el("div", { class: "modal" + (wide ? " wide" : "") + (xw ? " xw" : "") });