diff --git a/tools/field-problem-workshop.html b/tools/field-problem-workshop.html
index 106d669..5c40938 100644
--- a/tools/field-problem-workshop.html
+++ b/tools/field-problem-workshop.html
@@ -164,6 +164,13 @@
.toast{position:fixed; bottom:24px; left:50%; transform:translateX(-50%); background:var(--text); color:#fff; padding:12px 22px; font-size:14px; opacity:0; pointer-events:none; transition:opacity .2s; z-index:50;}
.toast.show{opacity:1;}
#jsonFile{display:none;}
+ .btn.danger{background:var(--danger); color:#fff; border:none;}
+ .btn.danger:hover{background:#b3121d;}
+ .confirm-backdrop{position:fixed; inset:0; background:rgba(22,22,22,.5); display:flex; align-items:center; justify-content:center; z-index:70; padding:20px;}
+ .confirm-card{background:var(--layer); border:1px solid var(--border); border-left:4px solid var(--danger); padding:22px 26px; max-width:420px; width:100%;}
+ .confirm-card h3{font-size:16px; font-weight:600; margin-bottom:8px;}
+ .confirm-card p{font-size:14px; color:var(--text-secondary); line-height:1.5; margin-bottom:20px;}
+ .confirm-actions{display:flex; justify-content:flex-end; gap:10px;}
@media (max-width:1200px){ .bc-top{grid-template-columns:1fr;} .bc-out{grid-template-columns:1fr 1fr;} }
@media (prefers-reduced-motion: reduce){ *{transition:none !important;} }
@@ -503,10 +510,16 @@ document.getElementById('panel-map').addEventListener('click', e=>{
}
if(t.dataset.cdel){
const c = clusterById(t.dataset.cdel);
- if(c && confirm(`Remove cluster "${c.name}"? Its issues return to Unclustered.`)){
- S.problems.forEach(p=>{ if(p.cluster===c.id) p.cluster=''; });
- S.clusters = S.clusters.filter(x=>x.id!==c.id);
- save(); renderMap();
+ if(c){
+ confirmModal({
+ title: 'Remove cluster?',
+ message: `Remove cluster "${c.name}"? Its issues return to Unclustered.`,
+ confirmLabel: 'Remove cluster'
+ }, ()=>{
+ S.problems.forEach(p=>{ if(p.cluster===c.id) p.cluster=''; });
+ S.clusters = S.clusters.filter(x=>x.id!==c.id);
+ save(); renderMap();
+ });
}
return;
}
@@ -530,9 +543,16 @@ document.getElementById('panel-map').addEventListener('click', e=>{
return;
}
if(t.dataset.pdel){
- S.problems = S.problems.filter(p=>p.id !== t.dataset.pdel);
- editingItems.delete(t.dataset.pdel);
- save(); renderMap();
+ const pid = t.dataset.pdel;
+ confirmModal({
+ title: 'Remove issue?',
+ message: 'Remove this issue from the problem map? This cannot be undone.',
+ confirmLabel: 'Remove issue'
+ }, ()=>{
+ S.problems = S.problems.filter(p=>p.id !== pid);
+ editingItems.delete(pid);
+ save(); renderMap();
+ });
return;
}
const head = t.closest('[data-toggle]');
@@ -685,8 +705,15 @@ document.getElementById('bcDetail').addEventListener('click', e=>{
}
if(e.target.dataset.aibc){ aiDraftBreadcrumb(e.target.dataset.aibc, e.target); return; }
if(e.target.dataset.bdel){
- S.breadcrumbs = S.breadcrumbs.filter(b=>b.id!==e.target.dataset.bdel);
- save(); renderBc();
+ const bid = e.target.dataset.bdel;
+ confirmModal({
+ title: 'Remove breadcrumb?',
+ message: 'Remove this breadcrumb? Its fields will be lost unless you have already saved or exported this session.',
+ confirmLabel: 'Remove breadcrumb'
+ }, ()=>{
+ S.breadcrumbs = S.breadcrumbs.filter(b=>b.id!==bid);
+ save(); renderBc();
+ });
}
});
document.getElementById('btnAddBc').addEventListener('click', ()=>{
@@ -762,7 +789,14 @@ function renderAct(){
}
document.getElementById('actList').addEventListener('click', e=>{
if(e.target.dataset.done){ const a=S.actions.find(x=>x.id===e.target.dataset.done); if(a){a.done=!a.done; save(); renderAct();} }
- if(e.target.dataset.adel){ S.actions=S.actions.filter(a=>a.id!==e.target.dataset.adel); save(); renderAct(); }
+ if(e.target.dataset.adel){
+ const aid = e.target.dataset.adel;
+ confirmModal({
+ title: 'Remove action?',
+ message: 'Remove this action item? This cannot be undone.',
+ confirmLabel: 'Remove action'
+ }, ()=>{ S.actions=S.actions.filter(a=>a.id!==aid); save(); renderAct(); });
+ }
});
document.getElementById('actList').addEventListener('change', e=>{
const t = e.target;
@@ -864,10 +898,14 @@ document.getElementById('btnExport').addEventListener('click', ()=>{
toast('Summary downloaded');
});
document.getElementById('btnReset').addEventListener('click', ()=>{
- if(confirm('Reset to the clustered July 21 baseline? Anything entered since will be lost unless saved to JSON.')){
+ confirmModal({
+ title: 'Reset to baseline?',
+ message: 'Reset to the clustered July 21 baseline? Anything entered since will be lost unless saved to JSON.',
+ confirmLabel: 'Reset'
+ }, ()=>{
S = JSON.parse(JSON.stringify(DEFAULT_STATE));
save(); renderAll(); toast('Reset to baseline');
- }
+ });
});
let toastTimer;
@@ -879,6 +917,27 @@ function toast(msg){
toastTimer = setTimeout(()=>t.classList.remove('show'), 2200);
}
+function confirmModal(opts, onConfirm){
+ const backdrop = document.createElement('div');
+ backdrop.className = 'confirm-backdrop';
+ backdrop.innerHTML = `
+
${esc(opts.title || 'Remove this?')}
+
${esc(opts.message || 'This cannot be undone.')}
+
+
+
+
+
`;
+ document.body.appendChild(backdrop);
+ function close(){ document.removeEventListener('keydown', onKey); backdrop.remove(); }
+ function onKey(e){ if(e.key==='Escape') close(); }
+ document.addEventListener('keydown', onKey);
+ backdrop.addEventListener('click', e=>{ if(e.target===backdrop) close(); });
+ backdrop.querySelector('[data-cc="cancel"]').addEventListener('click', close);
+ backdrop.querySelector('[data-cc="ok"]').addEventListener('click', ()=>{ close(); onConfirm(); });
+ backdrop.querySelector('[data-cc="ok"]').focus();
+}
+
function renderAll(){ renderMap(); renderBc(); renderAct(); }
renderAll();
diff --git a/tools/scope-lock-meeting-suite.html b/tools/scope-lock-meeting-suite.html
index 7de1b29..495aba7 100644
--- a/tools/scope-lock-meeting-suite.html
+++ b/tools/scope-lock-meeting-suite.html
@@ -214,6 +214,13 @@
opacity:0; pointer-events:none; transition:opacity .2s;
}
.toast.show{opacity:1;}
+ .btn.danger{background:var(--danger); color:#fff; border:none;}
+ .btn.danger:hover{background:#b3121d;}
+ .confirm-backdrop{position:fixed; inset:0; background:rgba(22,22,22,.5); display:flex; align-items:center; justify-content:center; z-index:70; padding:20px;}
+ .confirm-card{background:var(--layer); border:1px solid var(--border); border-left:4px solid var(--danger); padding:22px 26px; max-width:420px; width:100%;}
+ .confirm-card h3{font-size:16px; font-weight:600; margin-bottom:8px;}
+ .confirm-card p{font-size:14px; color:var(--text-secondary); line-height:1.5; margin-bottom:20px;}
+ .confirm-actions{display:flex; justify-content:flex-end; gap:10px;}
@media (max-width:1100px){ .board{grid-template-columns:repeat(2,1fr);} .reg-form{grid-template-columns:1fr 1fr;} }
@media (prefers-reduced-motion: reduce){ *{transition:none !important;} }
@@ -502,8 +509,12 @@ document.getElementById('panel-board').addEventListener('click', e=>{
if(item){ item.b = (item.b === t.dataset.b) ? '' : t.dataset.b; save(); renderScope(); }
}
if(t.dataset && t.dataset.del){
- S.scope = S.scope.filter(i=>i.id!==t.dataset.del);
- save(); renderScope();
+ const iid = t.dataset.del;
+ confirmModal({
+ title: 'Remove item?',
+ message: 'Remove this item from the Scope Boundary Board? This cannot be undone.',
+ confirmLabel: 'Remove item'
+ }, ()=>{ S.scope = S.scope.filter(i=>i.id!==iid); save(); renderScope(); });
}
});
@@ -553,9 +564,16 @@ document.getElementById('rankList').addEventListener('click', e=>{
[S.rank[i], S.rank[i+1]] = [S.rank[i+1], S.rank[i]];
save(); renderRank();
} else if(t.dataset.rdel !== undefined){
- S.rank.splice(+t.dataset.rdel, 1);
- if(S.cutAfter > S.rank.length) S.cutAfter = S.rank.length;
- save(); renderRank();
+ const idx = +t.dataset.rdel;
+ confirmModal({
+ title: 'Remove item?',
+ message: 'Remove this item from the priority ranking? This cannot be undone.',
+ confirmLabel: 'Remove item'
+ }, ()=>{
+ S.rank.splice(idx, 1);
+ if(S.cutAfter > S.rank.length) S.cutAfter = S.rank.length;
+ save(); renderRank();
+ });
}
});
@@ -609,8 +627,12 @@ document.getElementById('btnAddDecision').addEventListener('click', ()=>{
document.getElementById('regTableWrap').addEventListener('click', e=>{
if(e.target.dataset.ddel !== undefined){
- S.decisions.splice(+e.target.dataset.ddel, 1);
- save(); renderRegistry();
+ const idx = +e.target.dataset.ddel;
+ confirmModal({
+ title: 'Remove decision?',
+ message: 'Remove this decision from the registry? This cannot be undone.',
+ confirmLabel: 'Remove decision'
+ }, ()=>{ S.decisions.splice(idx, 1); save(); renderRegistry(); });
}
});
@@ -719,10 +741,14 @@ document.getElementById('btnExport').addEventListener('click', ()=>{
/* ================= RESET ================= */
document.getElementById('btnReset').addEventListener('click', ()=>{
- if(confirm('Reset all four tools to their starting state? This clears everything entered in this meeting.')){
+ confirmModal({
+ title: 'Reset everything?',
+ message: 'Reset all four tools to their starting state? This clears everything entered in this meeting.',
+ confirmLabel: 'Reset'
+ }, ()=>{
S = JSON.parse(JSON.stringify(DEFAULT_STATE));
save(); renderAll(); toast('Reset complete');
- }
+ });
});
/* ================= TOAST ================= */
@@ -735,6 +761,27 @@ function toast(msg){
toastTimer = setTimeout(()=>t.classList.remove('show'), 2000);
}
+function confirmModal(opts, onConfirm){
+ const backdrop = document.createElement('div');
+ backdrop.className = 'confirm-backdrop';
+ backdrop.innerHTML = `
+
${esc(opts.title || 'Remove this?')}
+
${esc(opts.message || 'This cannot be undone.')}
+
+
+
+
+
`;
+ document.body.appendChild(backdrop);
+ function close(){ document.removeEventListener('keydown', onKey); backdrop.remove(); }
+ function onKey(e){ if(e.key==='Escape') close(); }
+ document.addEventListener('keydown', onKey);
+ backdrop.addEventListener('click', e=>{ if(e.target===backdrop) close(); });
+ backdrop.querySelector('[data-cc="cancel"]').addEventListener('click', close);
+ backdrop.querySelector('[data-cc="ok"]').addEventListener('click', ()=>{ close(); onConfirm(); });
+ backdrop.querySelector('[data-cc="ok"]').focus();
+}
+
function renderAll(){ renderScope(); renderRank(); renderRegistry(); renderReady(); }
renderAll();