.</p>${badge('LOCAL STORE','teal')}</div>`)}</div>`};
const analysisContent={Facts:'60 enquiries per week, two intake channels, three-day manual response. Source: EV-001, synthetic message-001. Required: human review before customer contact.',Assumptions:'Assume 12 minutes of handling per enquiry and €35/hour blended labor cost. Exception rate of 20% is unverified. Validate against a representative sample before commitment.',Uncertainties:'No live mailbox, customer dataset, or delivery receipt. PII boundaries and exception ownership still need an Owner decision. Unknown does not mean zero.',Citations:'EV-001 · fixture / message-001 · 2026-11-07 09:42Z. EV-002 · fixture / trace-070 · 2026-11-07 11:30Z. These are synthetic sources, not external research.',Alternatives:'Keep: improve the manual checklist. Reuse: adapt the qualified intake validator. Build: custom orchestration, higher maintenance and validation cost.',Experts:'DEMO expert response: retain a human approval gate. Contradiction: “fully automatic” intake conflicts with undefined exception rules. No expert service was contacted.',Visuals:'Intake → normalize → classify → exception queue → human review. Queue latency and invalid-field rate are the acceptance measures.',Revisions:'r1 · initial synthetic analytical memo. Gate requests are revision-bound; a material revision invalidates downstream approvals.'};
pages.analysis=()=>head('analysis',btn('Run local analysis','analyze','primary'))+`<div class="notice">${badge(job().analysis?'ANALYSIS_READY_DEMO':'ANALYSIS_REQUIRED')} ${badge(job().an?'G-AN APPROVED':'G-AN BLOCKED')} · ${esc(job().id)} / ${esc(job().client)} · analyst response is predefined, local and synthetic.</div><div class="grid"><div class="stack"><section class="panel">${tabs('analysis',Object.keys(analysisContent),V.analysis)}<div class="body"><div class="eyebrow">ANALYTICAL MEMO / r${job().rev||1}</div><h2 style="font-size:22px">${V.analysis}</h2><p>${analysisContent[V.analysis]}</p>${job().analysis?`<div class="notice"><strong>Local analysis complete.</strong> Recommended: reuse the intake schema validator, cap scope at two channels, require explicit Owner acceptance for exception policy.</div>`:'<div class="notice">Run the local analysis to generate the case-linked evidence record before requesting G-AN.</div>'}<div class="actions">${btn('Request G-AN','request-an','primary')}${btn('Challenge assumption','modal','','data-purpose="challenge"')}${btn('Request source','modal','','data-purpose="source-request"')}${btn('Revise memo','modal','','data-purpose="revision-request"')}</div></div></section>${panel('Evidence register',table(['Evidence','Source / timestamp','Classification'],S.evidence.filter(e=>e.job===S.selected).map(e=>[esc(e.id)+' · '+esc(e.name),`<span class="mono tiny">${esc(e.source)}<br>${esc(e.time)}</span>`,badge(e.kind)])),'SELECTED JOB')}</div><div class="stack">${panel('Gate predicate',`<div class="body"><h3 class="small">G-AN / analytical acceptance</h3><p class="small muted">Analysis generated → evidence attached → Owner decision on current revision.</p>${badge(job().an?'APPROVED':'BLOCKED')}<hr class="rule">${link('decisions','Open Decision Inbox')}<p class="small muted">A scope request before G-AN is DENIED.</p></div>`)}${panel('Case timeline',eventsHTML(S.selected,6))}</div></div>`;
pages.proposal=()=>head('proposal',btn('Request G-SCOPE','modal','primary','data-purpose="approve-scope"'))+`<div class="notice">${badge(job().an?'G-AN APPROVED':'G-AN REQUIRED')} ${badge(job().scope?'G-SCOPE APPROVED':'SCOPE UNAPPROVED')} ${badge(job().frozen?'FROZEN r1':'MUTABLE DRAFT')} · Agency owns the job. Factory owns technical execution.</div><div class="three">${[['Keep','€ 1,200','Manual checklist, shared inbox rules. Lowest implementation cost; limited reduction in handling.'],['Reuse','€ 6,400','Qualified validator + local review queue. Bounded integration surface. Recommended.'],['Build','€ 12,800','Custom intake orchestration. Larger test surface and ongoing maintenance.']].map(([n,c,t])=>`<button class="option ${job().option===n?'picked':''}" style="display:block;text-align:left" data-action="option" data-value="${n}"><span class="sectionlabel">OPTION ${n==='Keep'?'01':n==='Reuse'?'02':'03'}</span><h3>${n} ${job().option===n?'✓':''}</h3><div class="metric">${c}</div><p class="small muted">${t}</p>${badge(n==='Reuse'?'RECOMMENDED':'ALTERNATIVE',n==='Reuse'?'teal':'')}</button>`).join('')}</div><div class="grid" style="margin-top:18px"><div class="stack">${panel('Architecture / bounded scope',`<div class="body"><div class="row" style="flex-wrap:wrap">${['Inbound fixture','Schema validator','Review queue','Owner acceptance'].map((s,i)=>`${i?'<span class="muted">→</span>':''}<span class="badge blue">${s}</span>`).join('')}</div><hr class="rule"><div class="two"><div><h3 class="small">In scope</h3><p class="small muted">Two intake channels; schema validation; masked evidence; exception queue; audit events.</p><h3 class="small">Acceptance oracle</h3><p class="small muted">30 synthetic samples. No dropped fields. Every exception reaches human review. No automatic outreach.</p></div><div><h3 class="small">Explicit exclusions</h3><p class="small muted">Live mailbox, production deployment, accounting, payments, unrestricted autonomous sends.</p><h3 class="small">Risk / constraints</h3><p class="small muted">Undefined exception policy. PII masking. Legal and Accounting retain original authority.</p></div></div><div class="actions">${btn('View SOW draft','sow')}${btn('Revise scope','modal','','data-purpose="revision-request"')}${btn('Recalculate estimate','modal','','data-purpose="recalculate"')}</div></div>`,'SOW / DRAFT')}${panel('Handoff to Work Program',`<div class="body row between"><div><strong>Freeze a versioned plan</strong><p class="small muted">Requires Owner + approved G-SCOPE on the current revision.</p></div>${btn('Freeze plan r1','modal','primary','data-purpose="freeze"')}</div>`)}</div><div class="stack">${panel('Cost & authority',`<div class="body"><span class="sectionlabel">Production budget ceiling</span><div class="metric">€ ${job().budget}</div><p class="small muted">Estimate · not a provider commitment.<br>Repair limit: three identical failures.<br>Approval owner: Founder / Owner.</p>${badge('NOT_CONNECTED')}<hr class="rule">${link('decisions','Review gate decisions')}</div>`)}${panel('Audit / selected job',eventsHTML(S.selected,5))}</div></div>`;
pages.decisions=()=>head('decisions',btn('Request change','modal','','data-purpose="decision-change"'))+`<div class="notice"><strong>OWNER AUTHORITY</strong> · Current role: ${esc(S.role)}. Approvals bind to a job, gate and revision. Duplicate pending requests reuse their decision ID. Expired requests cannot be approved.</div><div class="grid"><div class="stack">${panel('Decision queue',S.decisions.filter(d=>d.status==='PENDING').map(d=>`<div class="listrow warning"><div class="row between"><h3>${d.id} / ${d.gate} / ${d.job}</h3>${badge(d.status)}</div><p>${esc(d.note)}</p><p class="mono tiny muted">Owner · r${d.rev} · expires ${d.expires} · source: local decision ledger</p><div class="actions">${btn('Review evidence','decision','','data-id="'+d.id+'"')}${btn('Approve','modal','primary','data-purpose="decision-confirm" data-id="'+d.id+'"')}${btn('Deny','modal','','data-purpose="decision-deny" data-id="'+d.id+'"')}${btn('Open case','openjob','','data-id="'+d.job+'"')}</div></div>`).join('')||'<div class="body muted">No pending gates. Request a gate from Analysis or Proposal.</div>','VERSIONED')}${panel('Permanent decision history',table(['ID / job','Gate / revision','Result','Time / reason'],S.decisions.filter(d=>d.status!=='PENDING').map(d=>[esc(d.id)+'<br>'+esc(d.job),esc(d.gate)+' · r'+d.rev,badge(d.status),`<span class="tiny mono">${esc(d.time)}</span><br>${esc(d.note)}`])),'APPEND-ONLY AUDIT')}</div><div class="stack">${panel('Unblock predicate',`<div class="body"><p class="small"><strong>G-AN</strong><br><span class="muted">Local analysis + attached evidence.</span></p><p class="small"><strong>G-SCOPE</strong><br><span class="muted">Approved G-AN on current revision.</span></p><p class="small"><strong>Business acceptance</strong><br><span class="muted">Technical DEMO QA + Owner decision.</span></p><hr class="rule">${btn('Switch demo role','role')}<p class="small muted">Try Operator approval to observe DENIED without changing approval state.</p></div>`)}${panel('Decision audit',eventsHTML(null,6))}</div></div>`;
function graphHTML(){const positions=S.nodes.map((n,i)=>({n,x:30+(i%3)*210,y:25+Math.floor(i/3)*100}));let pos=id=>positions.find(p=>p.n.id===id);return `<svg class="graph" viewBox="0 0 650 ${Math.max(330,Math.ceil(S.nodes.length/3)*110)}" style="transform:scale(${V.zoom});transform-origin:top left" role="img" aria-label="Editable workflow DAG. Select nodes using the inspector list."><defs><marker id="arrowhead" markerWidth="7" markerHeight="7" refX="5" refY="3" orient="auto"><path d="M0 0L6 3 0 6" style="fill:var(--blue);stroke:none"/></marker></defs>${S.edges.map(([a,b])=>{let x=pos(a),y=pos(b);if(!x||!y)return '';return `<path d="M${x.x+160} ${x.y+27} C${x.x+195} ${x.y+27},${y.x-30} ${y.y+27},${y.x} ${y.y+27}" marker-end="url(#arrowhead)"/>`}).join('')}${positions.map(({n,x,y})=>`<g data-action="node" data-id="${n.id}" class="${V.node===n.id?'picked':''}"><rect x="${x}" y="${y}" width="165" height="60" rx="4"/><text class="id" x="${x+12}" y="${y+20}">${n.id} / ${esc(n.type)}</text><text x="${x+12}" y="${y+42}">${esc(n.name.slice(0,23))}</text></g>`).join('')}</svg>`}
function studioFlow(){let n=S.nodes.find(n=>n.id===V.node)||S.nodes[0];return `<div class="grid"><section class="panel"><div class="panelhead"><h2>Intake delivery / directed graph</h2><span class="sub">${S.nodes.length} NODES · ${S.edges.length} EDGES</span></div><div class="modebar">${btn(icon('plus')+' Node','new-node')}${btn('Connect edge','edge')}${btn('Fit','fit')}${btn('−','zoom','','data-value="-0.1" aria-label="Zoom out"')}${btn('+','zoom','','data-value="0.1" aria-label="Zoom in"')}${btn('Reset graph','flow-reset')}${badge('DAG VALID','teal')}</div><div class="nodecanvas" id="nodecanvas" tabindex="0" aria-label="Workflow canvas; scroll to pan">${graphHTML()}</div><div class="body row between small"><span class="muted">Scroll to pan · ${Math.round(V.zoom*100)}% · edits are a Studio draft</span>${btn('Test n7 → n1','cycle-test','danger')}</div><div class="body" style="border-top:1px solid var(--line)"><span class="sectionlabel">Dependency minimap</span><div class="row" style="flex-wrap:wrap;margin-top:10px">${S.nodes.map(n=>btn(n.id,'node',V.node===n.id?'primary':'','data-id="'+n.id+'"')).join('')}</div></div></section><div class="stack">${panel('Node inspector',n?`<form class="body" id="nodeform" style="display:grid;gap:14px"><span class="mono tiny muted">${n.id} / STUDIO DRAFT</span><label>Node label<input name="name" value="${esc(n.name)}" required maxlength="50"></label><label>Typed node<select name="type">${['Input','Analysis','Gate','Plan','Worker','QA','Report'].map(t=>`<option ${n.type===t?'selected':''}>${t}</option>`).join('')}</select></label><button type="submit" class="primary">Save node</button>${btn('Delete node','delete-node','danger','data-id="'+n.id+'"')}<p class="tiny muted">Frozen Work Program snapshots remain immutable.</p></form>`:'<div class="body">Add a node to begin.</div>')}${panel('Edges / dependency inspector',`<div class="body">${S.edges.map(([a,b],i)=>`<div class="row between" style="margin-bottom:7px"><span class="mono small">${a} → ${b}</span>${btn(icon('close'),'remove-edge','quiet','data-id="'+i+'" aria-label="Remove edge '+a+' to '+b+'"')}</div>`).join('')}</div>`)}${panel('Validation rule',`<div class="body small muted">No back edges. The canonical n7 → n1 edge is rejected with the cycle path. Validation runs before any edge is committed.</div>`)}</div></div>`}
function studioUI(){let u=S.ui.find(u=>u.id===V.ui)||S.ui[0];return `<div class="grid"><section class="panel"><div class="panelhead"><h2>Intake workspace / page 01</h2><span class="sub">EDITABLE DEMO</span></div><div class="modebar">${['Desktop','Tablet','Mobile'].map(d=>btn(d,'device',V.device===d?'primary':'','data-value="'+d+'"')).join('')}${btn('+ Element','ui-add')}</div><div class="preview"><div class="mockpage" style="width:${V.device==='Desktop'?900:V.device==='Tablet'?620:320}px"><div class="row between"><span class="mono small">VELA / INTAKE</span>${badge('DEMO')}</div><h2 style="font-size:${V.device==='Mobile'?21:28}px">A clearer first response.</h2><p class="small muted">Structured intake. Human judgment.</p>${S.ui.map(u=>`<button class="mockcomponent ${u.id===V.ui?'picked':''}" data-action="ui-select" data-id="${u.id}" style="display:block;width:100%;text-align:left"><span class="sectionlabel">${esc(u.type)}</span><h3>${esc(u.name)}</h3><p class="small muted">${u.type==='Table'?'Contact · Request · Review status':'Editable local layout element'}</p></button>`).join('')}</div></div></section><div class="stack">${panel('Layout inspector',u?`<form class="body" id="uiform" style="display:grid;gap:14px"><label>Element<select id="uiselect">${S.ui.map(x=>`<option value="${x.id}" ${u.id===x.id?'selected':''}>${esc(x.name)}</option>`).join('')}</select></label><label>Live label<input name="name" id="uilabel" value="${esc(u.name)}" required></label><label>Component type<select name="type">${['Section','Table','Panel','Button'].map(t=>`<option ${u.type===t?'selected':''}>${t}</option>`).join('')}</select></label><button type="submit" class="primary">Save layout element</button><div class="actions">${btn('Move up','ui-shift','','data-value="-1"')}${btn('Move down','ui-shift','','data-value="1"')}${btn('Delete','ui-delete','danger')}</div></form>`:'<div class="body">No elements. Add an element to edit the page.</div>')}${panel('Responsive rules',`<div class="body"><p class="small muted">Desktop 900px / Tablet 620px / Mobile 320px. Preview is contained by the work surface. All edits are local.</p>${badge('STORED_INTERNAL')}</div>`)}</div></div>`}
function studioReport(){return `<div class="grid"><div class="stack">${panel('Consulting memo / r1',`<div class="body"><div class="eyebrow">${esc(job().client)} · ${esc(job().id)} / SYNTHETIC</div><h2 style="font-size:26px">Intake systems assessment</h2><p class="muted">A bounded route from unstructured requests to accountable review.</p><hr class="rule"><h3 class="small">01 / Findings</h3><p>Manual triage across two channels introduces delay and inconsistent exception handling. The recommended design keeps human approval in the delivery path.</p><h3 class="small">02 / Source quality</h3><p class="small muted">EV-001 / fixture transcript / 2026-11-07. Estimates are not independently verified. This is a draft consulting document.</p><h3 class="small">03 / Process</h3><div class="notice">Intake → validate → classify → human review → accepted output</div>${costchart()}<p class="tiny muted">Source: synthetic cost-ledger, checkpoints C1–C7, EUR. Model and compute estimates.</p><label>Report annotation<textarea id="reportnote">${esc(S.reportnote||'Validate exception policy before freezing scope.')}</textarea></label>${btn('Save annotation','report-save')}</div>`,'DRAFT / LEGAL REVIEW REQUIRED')}</div><div class="stack">${panel('Export classification',`<div class="body"><p class="small muted">Browser print: DEMO output.<br>Verified consulting PDF: NOT_CONNECTED.<br>DOCX producer: NOT_CONNECTED.</p><div class="actions">${btn('Browser print / DEMO','print')}${btn('DOCX status','not-connected')}${btn('Download local memo','report-download')}</div><hr class="rule">${badge('LEGAL_REVIEW_REQUIRED','amber')}<p class="small muted">No legal advice, signed report or provider artifact is claimed.</p></div>`)}</div></div>`}
pages.studio=()=>head('studio',badge('LOCAL WORKBENCH','violet'))+`<div class="panel" style="margin-bottom:18px">${tabs('studio',['Flow','UI Designer','Report Studio'],V.studio)}</div>`+(V.studio==='Flow'?studioFlow():V.studio==='UI Designer'?studioUI():studioReport());
const modeContent={Investigate:['Inspect evidence','Inventory available sources, identify provenance and missing readback.','Source inspector / EV-001 / fixture transcript. No repository provider connection.'],Analyze:['Analyze intake risk','Compare facts with assumptions and surface contradictions.','Analytical oracle: no automatic outreach; human exception review required.'],Design:['Draft bounded architecture','Compare keep, reuse and build without freezing scope.','Design output: intake → validator → review queue → Owner gate.'],Produce:['Prepare execution request','Inspect frozen-plan eligibility; use Factory for explicit local transitions.','Eligibility requires G-AN, G-SCOPE and frozen Work Program. No execution occurs here.'],Review:['Review acceptance criteria','Check evidence before technical QA and business acceptance.','Review oracle: 30 synthetic records, all exceptions queued, no dropped fields.'],Operate:['Inspect host health','Check source freshness and repair budget.','Boreal is STALE; CPU and available capacity remain UNKNOWN.'],Report:['Summarize delivery evidence','Compose a draft memo from the current local case state.','Output is a local report draft. Verified PDF and DOCX providers are NOT_CONNECTED.']};
pages.terminal=()=>head('terminal',btn('Clear history','terminal-clear'))+`<div class="notice"><strong>DEMO TERMINAL</strong> · Predefined local responses, no model calls, no raw reasoning. Model/provider: NOT_CONNECTED. Usage/billed tokens: UNKNOWN.</div><div class="grid"><section class="panel"><div class="modebar">${Object.keys(modeContent).map(m=>btn(m,'terminal-mode',V.terminalMode===m?'selected':'','data-value="'+m+'"')).join('')}</div><div class="terminal">${S.terminal.filter(t=>t.job===S.selected).map(t=>`<div class="termline"><span class="prompt">${esc(t.time)} ${esc(t.job)} / ${esc(t.mode.toLowerCase())} &gt;</span> ${esc(t.prompt)}<br><span class="muted">${esc(t.response)}</span><br><span style="color:var(--violet)">[${esc(t.receipt)} · SYNTHETIC · cost UNKNOWN]</span></div>`).join('')||'<div class="termline muted">No local conversation for this job. Compose a prompt to record a synthetic response.</div>'}<div class="termline"><span class="prompt">local@neisse</span><span class="muted"> : ${esc(S.selected)} / ${V.terminalMode.toLowerCase()} ▌</span></div></div><form id="terminalform" class="composer"><input name="prompt" required aria-label="Terminal prompt" placeholder="${modeContent[V.terminalMode][0]}…"><button type="submit" class="primary">Run local prompt ${icon('arrow')}</button></form></section><div class="stack">${panel(V.terminalMode+' / workflow',`<div class="body"><h3 class="small">${modeContent[V.terminalMode][0]}</h3><p class="small muted">${modeContent[V.terminalMode][1]}</p><div class="notice">${modeContent[V.terminalMode][2]}</div>${btn('Use suggested prompt','terminal-quick','primary')}${btn('Voice / status','not-connected','quiet')}<hr class="rule">${link(V.terminalMode==='Produce'?'factory':V.terminalMode==='Design'?'studio':'analysis','Open linked workspace')}</div>`)}${panel('Source / request inspector',`<div class="body small"><p class="mono tiny">repo: demo/intake-kit<br>file: schema/intake.json (fixture)<br>PR: DEMO-017 / no provider link<br>CI: SYNTHETIC / no GitHub readback</p><hr class="rule"><p>REQUEST → ELIGIBILITY → ACK_ONLY → SIMULATED_APPLIED</p>${badge(job().request)}<p class="muted">ACK is a receipt of intent. Application is a separate checkpoint in Factory.</p>${btn('Inspect source details','source-inspect')}</div>`)}</div></div>`;
