|  |  | 
					
						
						|  | const flowchartData = { | 
					
						
						|  | q1: { | 
					
						
						|  | text: "Did you develop the GPAI model for the sole purpose of scientific research and development?", | 
					
						
						|  | type: "question", | 
					
						
						|  | context: "You develop a GPAI model", | 
					
						
						|  | choices: [ | 
					
						
						|  | { text: "Yes", next: "outcome_research" }, | 
					
						
						|  | { text: "No", next: "q2" } | 
					
						
						|  | ] | 
					
						
						|  | }, | 
					
						
						|  | q2: { | 
					
						
						|  | text: "Have you made the GPAI model available on the EU market (e.g. via API or open repository)", | 
					
						
						|  | type: "question", | 
					
						
						|  | choices: [ | 
					
						
						|  | { text: "Yes", next: "q3" }, | 
					
						
						|  | { text: "No", next: "outcome_research" } | 
					
						
						|  | ] | 
					
						
						|  | }, | 
					
						
						|  | q3: { | 
					
						
						|  | text: "Does the GPAI model you've published qualify as posing a potential systemic risk?", | 
					
						
						|  | type: "question", | 
					
						
						|  | choices: [ | 
					
						
						|  | { text: "Yes", next: "outcome_systemic_risk" }, | 
					
						
						|  | { text: "No", next: "q4" } | 
					
						
						|  | ] | 
					
						
						|  | }, | 
					
						
						|  | q4: { | 
					
						
						|  | text: "Have you published the GPAI model under a free and open-source license along with documentation about model architecture and usage?", | 
					
						
						|  | type: "question", | 
					
						
						|  | choices: [ | 
					
						
						|  | { text: "Yes", next: "q5" }, | 
					
						
						|  | { text: "No", next: "outcome_gpai_provider_with_obligations" } | 
					
						
						|  | ] | 
					
						
						|  | }, | 
					
						
						|  | q5: { | 
					
						
						|  | text: "Are you monetising the GPAI model by making its availability contingent on payment, procuring other products/services, viewing ads, or receiving/processing personal data?", | 
					
						
						|  | type: "question", | 
					
						
						|  | choices: [ | 
					
						
						|  | { text: "Yes", next: "outcome_gpai_provider_with_obligations" }, | 
					
						
						|  | { text: "No", next: "outcome_open_source" } | 
					
						
						|  | ] | 
					
						
						|  | }, | 
					
						
						|  | outcome_research: { | 
					
						
						|  | text: "You're not a GPAI provider. GPAI provisions do not apply.", | 
					
						
						|  | type: "outcome" | 
					
						
						|  | }, | 
					
						
						|  | outcome_systemic_risk: { | 
					
						
						|  | text: "All GPAISR provider obligations apply (open-source exemptions do not apply).", | 
					
						
						|  | type: "outcome", | 
					
						
						|  | articles: ["Article 53(1)(a)", "Article 53(1)(b)", "Article 53(1)(c)", "Article 53(1)(d)", "Article 54", "Article 55", "Annex XI", "Annex XII"], | 
					
						
						|  | additional: "Additional obligations for GPAI with Systemic Risk: Article 55" | 
					
						
						|  | }, | 
					
						
						|  | outcome_gpai_provider_with_obligations: { | 
					
						
						|  | text: "All GPAI provider obligations apply (open-source exemptions do not apply).", | 
					
						
						|  | type: "outcome", | 
					
						
						|  | class: "gpai", | 
					
						
						|  | articles: ["Article 53(1)(a)", "Article 53(1)(b)", "Article 53(1)(c)", "Article 53(1)(d)", "Article 54","Annex XI", "Annex XII"], | 
					
						
						|  | }, | 
					
						
						|  | outcome_open_source: { | 
					
						
						|  | text: "You're an open-source GPAI provider. Open-source exemptions apply.", | 
					
						
						|  | type: "outcome", | 
					
						
						|  | class: "gpai", | 
					
						
						|  | articles: ["Article 53(1)(a)", "Article 53(1)(b)"], | 
					
						
						|  | } | 
					
						
						|  | }; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | let currentNode = 'q1'; | 
					
						
						|  | let navigationHistory = []; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | let scale = 1; | 
					
						
						|  | let translateX = 0; | 
					
						
						|  | let translateY = 0; | 
					
						
						|  | let isDragging = false; | 
					
						
						|  | let lastMousePos = { x: 0, y: 0 }; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | document.addEventListener('DOMContentLoaded', function() { | 
					
						
						|  | updateGuidedView(); | 
					
						
						|  | initializeMermaid(); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | document.getElementById('guided-btn').addEventListener('click', () => switchMode('guided')); | 
					
						
						|  | document.getElementById('flowchart-btn').addEventListener('click', () => switchMode('flowchart')); | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  | function switchMode(mode) { | 
					
						
						|  | const guidedMode = document.getElementById('guided-mode'); | 
					
						
						|  | const flowchartMode = document.getElementById('flowchart-mode'); | 
					
						
						|  | const guidedBtn = document.getElementById('guided-btn'); | 
					
						
						|  | const flowchartBtn = document.getElementById('flowchart-btn'); | 
					
						
						|  |  | 
					
						
						|  | if (mode === 'guided') { | 
					
						
						|  | guidedMode.classList.remove('hidden'); | 
					
						
						|  | flowchartMode.classList.add('hidden'); | 
					
						
						|  | guidedBtn.classList.add('active'); | 
					
						
						|  | flowchartBtn.classList.remove('active'); | 
					
						
						|  | } else { | 
					
						
						|  | guidedMode.classList.add('hidden'); | 
					
						
						|  | flowchartMode.classList.remove('hidden'); | 
					
						
						|  | guidedBtn.classList.remove('active'); | 
					
						
						|  | flowchartBtn.classList.add('active'); | 
					
						
						|  | } | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | function updateGuidedView() { | 
					
						
						|  | updateContext(); | 
					
						
						|  | updateHistory(); | 
					
						
						|  | updateCurrentQuestion(); | 
					
						
						|  | updateArticles(); | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function updateContext() { | 
					
						
						|  | const contextElement = document.querySelector('.context-text'); | 
					
						
						|  | const currentData = flowchartData[currentNode]; | 
					
						
						|  | contextElement.textContent = currentData.context || "You develop a GPAI model"; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function updateHistory() { | 
					
						
						|  | const historyContainer = document.querySelector('.history-section'); | 
					
						
						|  | const historyHTML = navigationHistory.map((item, index) => ` | 
					
						
						|  | <div class="history-item" onclick="goToHistoryStep(${index})"> | 
					
						
						|  | <div class="history-question">${truncateText(item.question, 50)}</div> | 
					
						
						|  | <div class="history-answer">→ ${item.answer}</div> | 
					
						
						|  | <div class="tooltip">${item.question}</div> | 
					
						
						|  | </div> | 
					
						
						|  | `).join(''); | 
					
						
						|  |  | 
					
						
						|  | historyContainer.innerHTML = ` | 
					
						
						|  | <h3>Decision History</h3> | 
					
						
						|  | ${historyHTML} | 
					
						
						|  | `; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function updateCurrentQuestion() { | 
					
						
						|  | const container = document.getElementById('question-container'); | 
					
						
						|  | const currentData = flowchartData[currentNode]; | 
					
						
						|  |  | 
					
						
						|  | if (currentData.type === 'question') { | 
					
						
						|  | container.innerHTML = ` | 
					
						
						|  | <div class="question">${currentData.text}</div> | 
					
						
						|  | <div class="choices"> | 
					
						
						|  | ${currentData.choices.map(choice => | 
					
						
						|  | `<button class="choice-btn" onclick="nextQuestion('${choice.next}', '${choice.text}')">${choice.text}</button>` | 
					
						
						|  | ).join('')} | 
					
						
						|  | </div> | 
					
						
						|  | `; | 
					
						
						|  | } else { | 
					
						
						|  |  | 
					
						
						|  | let articlesHTML = ''; | 
					
						
						|  | if (currentData.articles) { | 
					
						
						|  | const articlesList = currentData.articles.map(article => | 
					
						
						|  | `<li>${article}</li>` | 
					
						
						|  | ).join(''); | 
					
						
						|  |  | 
					
						
						|  | articlesHTML = ` | 
					
						
						|  | <div class="articles-section" style="margin-top: 30px;"> | 
					
						
						|  | <h3>Applicable Articles</h3> | 
					
						
						|  | <ul class="articles-list"> | 
					
						
						|  | ${articlesList} | 
					
						
						|  | </ul> | 
					
						
						|  | </div> | 
					
						
						|  | `; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | container.innerHTML = ` | 
					
						
						|  | <div class="outcome ${currentData.class || ''}">${currentData.text}</div> | 
					
						
						|  | ${articlesHTML} | 
					
						
						|  | <button class="restart-btn" onclick="restart()">Start Over</button> | 
					
						
						|  | `; | 
					
						
						|  | } | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function updateArticles() { | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function nextQuestion(nodeId, selectedChoice = null) { | 
					
						
						|  | if (selectedChoice) { | 
					
						
						|  | navigationHistory.push({ | 
					
						
						|  | node: currentNode, | 
					
						
						|  | question: flowchartData[currentNode].text, | 
					
						
						|  | answer: selectedChoice, | 
					
						
						|  | nextNode: nodeId | 
					
						
						|  | }); | 
					
						
						|  | } | 
					
						
						|  | currentNode = nodeId; | 
					
						
						|  | updateGuidedView(); | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function goToHistoryStep(stepIndex) { | 
					
						
						|  | navigationHistory = navigationHistory.slice(0, stepIndex); | 
					
						
						|  | currentNode = stepIndex === 0 ? 'q1' : navigationHistory[stepIndex - 1].nextNode; | 
					
						
						|  | updateGuidedView(); | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function restart() { | 
					
						
						|  | currentNode = 'q1'; | 
					
						
						|  | navigationHistory = []; | 
					
						
						|  | updateGuidedView(); | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function truncateText(text, maxLength) { | 
					
						
						|  | return text.length > maxLength ? text.substring(0, maxLength) + '...' : text; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | function initializeMermaid() { | 
					
						
						|  | const svg = generateFlowchartSVG(); | 
					
						
						|  | document.getElementById('mermaid-container').innerHTML = svg; | 
					
						
						|  | setupFlowchartInteraction(); | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function generateFlowchartSVG() { | 
					
						
						|  |  | 
					
						
						|  | const config = { | 
					
						
						|  | startX: 200, | 
					
						
						|  | startY: 60, | 
					
						
						|  | questionSpacing: 220, | 
					
						
						|  | outcomeY: 1450, | 
					
						
						|  | outcomeSpacing: 350, | 
					
						
						|  | articleOffset: 70, | 
					
						
						|  | rightOutcomeX: 600, | 
					
						
						|  | diamondSize: 100 | 
					
						
						|  | }; | 
					
						
						|  |  | 
					
						
						|  | let svgContent = `<svg viewBox="0 0 1600 1600" style="width: 100%; height: auto;">`; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | svgContent += ` | 
					
						
						|  | <defs> | 
					
						
						|  | <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"> | 
					
						
						|  | <polygon points="0 0, 10 3.5, 0 7" fill="#333"/> | 
					
						
						|  | </marker> | 
					
						
						|  | </defs> | 
					
						
						|  | `; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | const startY = config.startY; | 
					
						
						|  | svgContent += generateStartNode(config.startX, startY); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | const questions = ['q1', 'q2', 'q3', 'q4', 'q5']; | 
					
						
						|  | questions.forEach((qId, index) => { | 
					
						
						|  | const y = startY + 60 + (index + 1) * config.questionSpacing; | 
					
						
						|  | svgContent += generateQuestion(qId, config.startX, y); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | const prevY = index === 0 ? startY + 30 : startY + 60 + index * config.questionSpacing + config.diamondSize; | 
					
						
						|  | svgContent += `<line x1="${config.startX}" y1="${prevY}" x2="${config.startX}" y2="${y - config.diamondSize}" stroke="#333" stroke-width="2" marker-end="url(#arrowhead)"/>`; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | if (index < questions.length - 1) { | 
					
						
						|  | svgContent += `<text x="${config.startX + 20}" y="${y + config.diamondSize + 20}" text-anchor="start" font-size="12" font-weight="bold" fill="#333">No</text>`; | 
					
						
						|  | } | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | svgContent += generateOutcome('outcome_research', config.rightOutcomeX, startY + 60 + 2 * config.questionSpacing); | 
					
						
						|  | svgContent += generateArticles('outcome_research', config.rightOutcomeX + config.articleOffset, startY + 60 + 2 * config.questionSpacing - 40); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | const q1Y = startY + 60 + config.questionSpacing; | 
					
						
						|  | const q2Y = startY + 60 + 2 * config.questionSpacing; | 
					
						
						|  | svgContent += `<line x1="${config.startX + config.diamondSize}" y1="${q1Y}" x2="${config.rightOutcomeX - 150}" y2="${q1Y}" stroke="#333" stroke-width="2"/>`; | 
					
						
						|  | svgContent += `<line x1="${config.rightOutcomeX - 150}" y1="${q1Y}" x2="${config.rightOutcomeX - 150}" y2="${q2Y}" stroke="#333" stroke-width="2"/>`; | 
					
						
						|  | svgContent += `<line x1="${config.rightOutcomeX - 150}" y1="${q2Y}" x2="${config.rightOutcomeX - 60}" y2="${q2Y}" stroke="#333" stroke-width="2" marker-end="url(#arrowhead)"/>`; | 
					
						
						|  | svgContent += `<text x="${config.startX + 140}" y="${q1Y - 5}" text-anchor="middle" font-size="12" font-weight="bold" fill="#333">Yes</text>`; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | svgContent += `<line x1="${config.startX + config.diamondSize}" y1="${q2Y}" x2="${config.rightOutcomeX - 60}" y2="${q2Y}" stroke="#333" stroke-width="2" marker-end="url(#arrowhead)"/>`; | 
					
						
						|  | svgContent += `<text x="${config.startX + 140}" y="${q2Y - 5}" text-anchor="middle" font-size="12" font-weight="bold" fill="#333">No</text>`; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | const bottomOutcomes = ['outcome_open_source', 'outcome_gpai_provider_with_obligations', 'outcome_systemic_risk']; | 
					
						
						|  | bottomOutcomes.forEach((outcomeId, index) => { | 
					
						
						|  | const x = config.startX + index * config.outcomeSpacing; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | svgContent += generateOutcome(outcomeId, x, config.outcomeY); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | svgContent += generateArticles(outcomeId, x + config.articleOffset, config.outcomeY - 40); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | svgContent += generateOutcomeArrow(outcomeId, x, config); | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  | svgContent += `</svg>`; | 
					
						
						|  | return svgContent; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function generateStartNode(x, y) { | 
					
						
						|  | return ` | 
					
						
						|  | <ellipse cx="${x}" cy="${y}" rx="100" ry="30" fill="#FFA726" stroke="#FF8F00" stroke-width="3"/> | 
					
						
						|  | <text x="${x}" y="${y + 5}" text-anchor="middle" font-size="14" font-weight="bold" fill="#333">You develop a GPAI model</text> | 
					
						
						|  | `; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function generateQuestion(questionId, x, y) { | 
					
						
						|  | const question = flowchartData[questionId]; | 
					
						
						|  | if (!question) return ''; | 
					
						
						|  |  | 
					
						
						|  | const lines = wrapText(question.text, 25); | 
					
						
						|  | const lineHeight = 15; | 
					
						
						|  | const totalHeight = lines.length * lineHeight; | 
					
						
						|  | const startY = y - totalHeight / 2 + lineHeight / 2; | 
					
						
						|  | const size = 100; | 
					
						
						|  |  | 
					
						
						|  | let content = `<polygon points="${x},${y-size} ${x-size},${y} ${x},${y+size} ${x+size},${y}" fill="#A5D6A7" stroke="#4CAF50" stroke-width="3"/>`; | 
					
						
						|  |  | 
					
						
						|  | lines.forEach((line, index) => { | 
					
						
						|  | content += `<text x="${x}" y="${startY + index * lineHeight}" text-anchor="middle" font-size="11" font-weight="bold" fill="#333">${line}</text>`; | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  | return content; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function generateOutcome(outcomeId, x, y) { | 
					
						
						|  | const outcome = flowchartData[outcomeId]; | 
					
						
						|  | if (!outcome) return ''; | 
					
						
						|  |  | 
					
						
						|  | const lines = wrapText(outcome.text, 18); | 
					
						
						|  | const lineHeight = 15; | 
					
						
						|  | const totalHeight = lines.length * lineHeight; | 
					
						
						|  | const startY = y - totalHeight / 2 + lineHeight / 2; | 
					
						
						|  |  | 
					
						
						|  | let content = `<circle cx="${x}" cy="${y}" r="60" fill="#333"/>`; | 
					
						
						|  |  | 
					
						
						|  | lines.forEach((line, index) => { | 
					
						
						|  | content += `<text x="${x}" y="${startY + index * lineHeight}" text-anchor="middle" font-size="10" fill="white" font-weight="bold">${line}</text>`; | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  | return content; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function generateArticles(outcomeId, x, y) { | 
					
						
						|  | const outcome = flowchartData[outcomeId]; | 
					
						
						|  | if (!outcome || !outcome.articles) return ''; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | const articleCount = outcome.articles.length; | 
					
						
						|  | const width = 180; | 
					
						
						|  | const height = Math.max(100, articleCount * 18 + 60); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | const adjustedY = y; | 
					
						
						|  |  | 
					
						
						|  | let content = `<rect x="${x}" y="${adjustedY}" width="${width}" height="${height}" fill="#E8F5E8" stroke="#4CAF50" stroke-width="3" rx="10"/>`; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | const titleLines = wrapText(`Applicable obligations for ${getOutcomeTitle(outcomeId)}`, 22); | 
					
						
						|  | let titleY = adjustedY + 20; | 
					
						
						|  | titleLines.forEach((line, index) => { | 
					
						
						|  | content += `<text x="${x + width/2}" y="${titleY + index * 15}" text-anchor="middle" font-size="11" font-weight="bold" fill="#333">${line}</text>`; | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | let articleStartY = adjustedY + 20 + titleLines.length * 15 + 15; | 
					
						
						|  | outcome.articles.forEach((article, index) => { | 
					
						
						|  | const articleY = articleStartY + index * 18; | 
					
						
						|  | content += `<text x="${x + 15}" y="${articleY}" text-anchor="start" font-size="10" fill="#667eea">${article}</text>`; | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  | return content; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function generateOutcomeArrow(outcomeId, x, config) { | 
					
						
						|  | const questionY = config.startY + 60; | 
					
						
						|  | let content = ''; | 
					
						
						|  |  | 
					
						
						|  | switch(outcomeId) { | 
					
						
						|  | case 'outcome_open_source': | 
					
						
						|  |  | 
					
						
						|  | const q5Y = questionY + 5 * config.questionSpacing; | 
					
						
						|  | content = ` | 
					
						
						|  | <line x1="${config.startX}" y1="${q5Y + config.diamondSize}" x2="${config.startX}" y2="${config.outcomeY - 60}" stroke="#333" stroke-width="2" marker-end="url(#arrowhead)"/> | 
					
						
						|  | <text x="${config.startX - 30}" y="${q5Y + config.diamondSize + 40}" text-anchor="middle" font-size="12" font-weight="bold" fill="#333">No</text> | 
					
						
						|  | `; | 
					
						
						|  | break; | 
					
						
						|  |  | 
					
						
						|  | case 'outcome_gpai_provider_with_obligations': | 
					
						
						|  |  | 
					
						
						|  | const q4Y = questionY + 4 * config.questionSpacing; | 
					
						
						|  | const q5Y_yes = questionY + 5 * config.questionSpacing; | 
					
						
						|  | const midPointX = x - 50; | 
					
						
						|  |  | 
					
						
						|  | content = ` | 
					
						
						|  | <!-- Q4 No path --> | 
					
						
						|  | <line x1="${config.startX + config.diamondSize}" y1="${q4Y}" x2="${midPointX}" y2="${q4Y}" stroke="#333" stroke-width="2"/> | 
					
						
						|  | <line x1="${midPointX}" y1="${q4Y}" x2="${midPointX}" y2="${config.outcomeY - 100}" stroke="#333" stroke-width="2"/> | 
					
						
						|  | <text x="${config.startX + 150}" y="${q4Y - 5}" text-anchor="middle" font-size="12" font-weight="bold" fill="#333">No</text> | 
					
						
						|  |  | 
					
						
						|  | <!-- Q5 Yes path --> | 
					
						
						|  | <line x1="${config.startX + config.diamondSize}" y1="${q5Y_yes}" x2="${midPointX}" y2="${q5Y_yes}" stroke="#333" stroke-width="2"/> | 
					
						
						|  | <line x1="${midPointX}" y1="${q5Y_yes}" x2="${midPointX}" y2="${config.outcomeY - 100}" stroke="#333" stroke-width="2"/> | 
					
						
						|  | <text x="${config.startX + 150}" y="${q5Y_yes - 5}" text-anchor="middle" font-size="12" font-weight="bold" fill="#333">Yes</text> | 
					
						
						|  |  | 
					
						
						|  | <!-- Combined path to circle --> | 
					
						
						|  | <line x1="${midPointX}" y1="${config.outcomeY - 100}" x2="${x}" y2="${config.outcomeY - 60}" stroke="#333" stroke-width="2" marker-end="url(#arrowhead)"/> | 
					
						
						|  | `; | 
					
						
						|  | break; | 
					
						
						|  |  | 
					
						
						|  | case 'outcome_systemic_risk': | 
					
						
						|  |  | 
					
						
						|  | const q3Y = questionY + 3 * config.questionSpacing; | 
					
						
						|  | content = ` | 
					
						
						|  | <line x1="${config.startX + config.diamondSize}" y1="${q3Y}" x2="${x}" y2="${q3Y}" stroke="#333" stroke-width="2"/> | 
					
						
						|  | <line x1="${x}" y1="${q3Y}" x2="${x}" y2="${config.outcomeY - 60}" stroke="#333" stroke-width="2" marker-end="url(#arrowhead)"/> | 
					
						
						|  | <text x="${config.startX + 150}" y="${q3Y - 5}" text-anchor="middle" font-size="12" font-weight="bold" fill="#333">Yes</text> | 
					
						
						|  | `; | 
					
						
						|  | break; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | return content; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function getOutcomeTitle(outcomeId) { | 
					
						
						|  | switch(outcomeId) { | 
					
						
						|  | case 'outcome_research': return 'research providers'; | 
					
						
						|  | case 'outcome_open_source': return 'open-source GPAI providers'; | 
					
						
						|  | case 'outcome_gpai_provider_with_obligations': return 'GPAI providers'; | 
					
						
						|  | case 'outcome_systemic_risk': return 'GPAISR providers'; | 
					
						
						|  | default: return 'providers'; | 
					
						
						|  | } | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function wrapText(text, maxLength) { | 
					
						
						|  | const words = text.split(' '); | 
					
						
						|  | const lines = []; | 
					
						
						|  | let currentLine = ''; | 
					
						
						|  |  | 
					
						
						|  | words.forEach(word => { | 
					
						
						|  | if ((currentLine + word).length <= maxLength) { | 
					
						
						|  | currentLine += (currentLine ? ' ' : '') + word; | 
					
						
						|  | } else { | 
					
						
						|  | if (currentLine) lines.push(currentLine); | 
					
						
						|  | currentLine = word; | 
					
						
						|  | } | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  | if (currentLine) lines.push(currentLine); | 
					
						
						|  | return lines; | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | function updateTransform() { | 
					
						
						|  | const mermaidContainer = document.getElementById('mermaid-container'); | 
					
						
						|  | if (mermaidContainer) { | 
					
						
						|  | mermaidContainer.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scale})`; | 
					
						
						|  | } | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function zoomIn() { | 
					
						
						|  | scale = Math.min(scale * 1.2, 3); | 
					
						
						|  | updateTransform(); | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function zoomOut() { | 
					
						
						|  | scale = Math.max(scale / 1.2, 0.3); | 
					
						
						|  | updateTransform(); | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function resetView() { | 
					
						
						|  | scale = 1; | 
					
						
						|  | translateX = 0; | 
					
						
						|  | translateY = 0; | 
					
						
						|  | updateTransform(); | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | function setupFlowchartInteraction() { | 
					
						
						|  | const container = document.getElementById('flowchart-container'); | 
					
						
						|  | if (!container) return; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | container.addEventListener('mousedown', function(e) { | 
					
						
						|  | isDragging = true; | 
					
						
						|  | lastMousePos = { x: e.clientX, y: e.clientY }; | 
					
						
						|  | e.preventDefault(); | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  | document.addEventListener('mousemove', function(e) { | 
					
						
						|  | if (!isDragging) return; | 
					
						
						|  |  | 
					
						
						|  | const deltaX = e.clientX - lastMousePos.x; | 
					
						
						|  | const deltaY = e.clientY - lastMousePos.y; | 
					
						
						|  |  | 
					
						
						|  | translateX += deltaX; | 
					
						
						|  | translateY += deltaY; | 
					
						
						|  |  | 
					
						
						|  | updateTransform(); | 
					
						
						|  |  | 
					
						
						|  | lastMousePos = { x: e.clientX, y: e.clientY }; | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  | document.addEventListener('mouseup', function() { | 
					
						
						|  | isDragging = false; | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | container.addEventListener('wheel', function(e) { | 
					
						
						|  | e.preventDefault(); | 
					
						
						|  |  | 
					
						
						|  | const rect = container.getBoundingClientRect(); | 
					
						
						|  | const x = e.clientX - rect.left; | 
					
						
						|  | const y = e.clientY - rect.top; | 
					
						
						|  |  | 
					
						
						|  | const zoom = e.deltaY > 0 ? 0.9 : 1.1; | 
					
						
						|  | const newScale = Math.min(Math.max(scale * zoom, 0.3), 3); | 
					
						
						|  |  | 
					
						
						|  | const factor = newScale / scale; | 
					
						
						|  | translateX = x - (x - translateX) * factor; | 
					
						
						|  | translateY = y - (y - translateY) * factor; | 
					
						
						|  | scale = newScale; | 
					
						
						|  |  | 
					
						
						|  | updateTransform(); | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | let touchStartDistance = 0; | 
					
						
						|  | let touchStartScale = 1; | 
					
						
						|  |  | 
					
						
						|  | container.addEventListener('touchstart', function(e) { | 
					
						
						|  | if (e.touches.length === 1) { | 
					
						
						|  | isDragging = true; | 
					
						
						|  | lastMousePos = { x: e.touches[0].clientX, y: e.touches[0].clientY }; | 
					
						
						|  | } else if (e.touches.length === 2) { | 
					
						
						|  | isDragging = false; | 
					
						
						|  | const touch1 = e.touches[0]; | 
					
						
						|  | const touch2 = e.touches[1]; | 
					
						
						|  | touchStartDistance = Math.sqrt( | 
					
						
						|  | Math.pow(touch2.clientX - touch1.clientX, 2) + | 
					
						
						|  | Math.pow(touch2.clientY - touch1.clientY, 2) | 
					
						
						|  | ); | 
					
						
						|  | touchStartScale = scale; | 
					
						
						|  | } | 
					
						
						|  | e.preventDefault(); | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  | container.addEventListener('touchmove', function(e) { | 
					
						
						|  | if (e.touches.length === 1 && isDragging) { | 
					
						
						|  | const deltaX = e.touches[0].clientX - lastMousePos.x; | 
					
						
						|  | const deltaY = e.touches[0].clientY - lastMousePos.y; | 
					
						
						|  |  | 
					
						
						|  | translateX += deltaX; | 
					
						
						|  | translateY += deltaY; | 
					
						
						|  |  | 
					
						
						|  | updateTransform(); | 
					
						
						|  |  | 
					
						
						|  | lastMousePos = { x: e.touches[0].clientX, y: e.touches[0].clientY }; | 
					
						
						|  | } else if (e.touches.length === 2) { | 
					
						
						|  | const touch1 = e.touches[0]; | 
					
						
						|  | const touch2 = e.touches[1]; | 
					
						
						|  | const currentDistance = Math.sqrt( | 
					
						
						|  | Math.pow(touch2.clientX - touch1.clientX, 2) + | 
					
						
						|  | Math.pow(touch2.clientY - touch1.clientY, 2) | 
					
						
						|  | ); | 
					
						
						|  |  | 
					
						
						|  | scale = Math.min(Math.max(touchStartScale * (currentDistance / touchStartDistance), 0.3), 3); | 
					
						
						|  | updateTransform(); | 
					
						
						|  | } | 
					
						
						|  | e.preventDefault(); | 
					
						
						|  | }); | 
					
						
						|  |  | 
					
						
						|  | container.addEventListener('touchend', function(e) { | 
					
						
						|  | isDragging = false; | 
					
						
						|  | e.preventDefault(); | 
					
						
						|  | }); | 
					
						
						|  | } |