<!-- SOLID CITY · part 3769 -->
units\nFormula: √((x₂−x₁)²+(y₂−y₁)²)',events:[
      ev('handoff','Route Planner','Transferred the drafted stop order to Surveyor for independent distance verification.','planner',null,'planner','surveyor'),
      ev('result','Surveyor','Computed all five route legs and the loop total.','surveyor','Deterministic Euclidean calculation from supplied coordinates'),
      ev('review','Surveyor','Submitted the distance result for human review.','surveyor')
    ]},
    {id:'t4',title:'Safety and language review',description:'Check that the board is honest about planning status and does not imply live transportation.',state:'claimed',owner:'safety',previousOwner:null,work:'Review checklist:\n• planned-service label visible\n• no operational status claims\n• no invented departure times\n• straight-line distance units explained\n• only supplied city locations used',events:[
      ev('claim','Safety Checker','Claimed safety and claims review.','safety'),
      ev('blocker','Safety Checker','Release is blocked until a human confirms the planned-service label.','safety')
    ]},
    {id:'t5',title:'Approve and publish the board',description:'Consequential release gate. Only The King can approve completion.',state:'open',owner:null,previousOwner:null,work:'Release target: Harbor Shuttle Board\nScope: planned inaugural service board\nRequired approvals: distance verification + safety language + explicit human confirmation',events:[
      ev('blocker','Workshop','Human approval is required before this release task can be completed.',null)
    ]}
  ];
  var tasks=taskSeed;
  function ev(type,actor,message,workerId,source,from,to){clock+=1;return{id:'e'+clock,type:type,actor:actor,message:message,workerId:workerId||null,source:source||null,from:from||null,to:to||null,order:clock,time:'E'+String(clock).padStart(2,'0')}}
  function allEvents(){var a=[];tasks.forEach(function(t){t.events.forEach(function(e){a.push({task:t,event:e})})});return a.sort(function(a,b){return b.event.order-a.event.order})}
  function ownerName(id){return id&&workers[id]?workers[id].name:'Unassigned'}
  function stateClass(s){return s==='in-progress'?'progress':s}
  function esc(v){return String(v==null?'':v).replace(/[&<>"]/g,function(c){return{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]})}
  function taskById(id){return tasks.find(function(t){return t.id===id})}
  function addEvent(t,type,actor,msg,wid,source,from,to){t.events.push(ev(type,actor,msg,wid,source,from,to));renderAll()}
  function renderTasks(){var out='';tasks.forEach(function(t,i){out+='<article class="task '+(selectedTask===t.id?'active':'')+'" tabindex="0" role="button" data-task="'+t.id+'"><div class="task-num">'+String(i+1).padStart(2,'0')+'</div><div><h3>'+esc(t.title)+'</h3><div class="task-meta"><span class="state '+stateClass(t.state)+'">'+esc(t.state)+'</span><span class="owner">'+esc(ownerName(t.owner))+'</span><span>'+t.events.length+' events</span></div></div><span class="task-arrow">›</span></article>'});document.getElementById('taskList').innerHTML=out}
  function renderWorkers(){var out='';Object.keys(workers).forEach(function(k){var w=workers[k],held=tasks.filter(function(t){return t.owner===w.id&&t.state!=='done'}).length;out+='<div class="worker"><div class="avatar '+(w.kind==='human'?'human':(w.id==='safety'?'safe':''))+'">'+w.initials+'</div><div><strong>'+esc(w.name)+'</strong><span>'+esc(w.role)+' · '+esc(w.capabilities)+'</span></div><div class="worker-status">'+held+' TASK'+(held===1?'':'S')+'<br>'+w.status.toUpperCase()+'</div></div>'});document.getElementById('workerList').innerHTML=out}
  function renderFeed(){var events=allEvents(),out='';events.slice(0,18).forEach(function(x){var e=x.event,cls=e.type==='handoff'||e.type==='exchange'?'exchange':e.type.indexOf('info')===0?'info':e.type==='edit'?'edit':e.type==='blocker'?'blocker':'';out+='<div class="feed-item"><span class="feed-dot '+cls+'"></span><div><p><strong>'+esc(e.actor)+'</strong> · '+esc(e.message)+'</p><time>'+e.time+' · '+esc(x.task.title)+'</time></div></div>'});document.getElementById('activityFeed').innerHTML=out;document.getElementById('feedCount').textContent=events.length+' EVENTS';document.getElementById('navEvents').textContent=events.length+' events'}
  function activeBlockers(){return allEvents().filter(function(x){return x.event.type==='blocker'&&x.task.state!=='done'})}
  function sources(){var map={};allEvents().forEach(function(x){if(x.event.source){var key=x.event.source+'|'+x.task.id;map[key]={source:x.event.source,task:x.task,event:x.event}}});return Object.keys(map).map(function(k){return map[k]})}
  function exchanges(){return allEvents().filter(function(x){var e=x.event;return (e.type==='handoff'&&e.from&&e.to&&e.from!=='king'&&e.to!=='king')||e.type==='info-answer'||e.type==='exchange'})}
  function renderStats(){var done=tasks.filter(function(t){return t.state==='done'}).length,active=tasks.length-done,pct=Math.round(done/tasks.length