game_1_AI_Maturity / index.html
eaglelandsonce's picture
Update index.html
dd1aefa verified
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>AI Adoption Arena — Team A vs Team B (10 Turns)</title>
<style>
:root{
--bg:#0b0f17; --panel:#12192a; --panel2:#0f1524; --text:#e7ecf7; --muted:#a7b2cc;
--accent:#7aa2ff; --accent2:#ff6fae; --good:#4ce6b3; --warn:#ffcc66; --bad:#ff6b6b;
--line:rgba(231,236,247,.12);
--radius:14px;
--shadow: 0 10px 25px rgba(0,0,0,.35);
font-synthesis-weight:none;
}
*{box-sizing:border-box}
body{
margin:0; background:radial-gradient(1200px 800px at 20% 10%, rgba(122,162,255,.18), transparent 60%),
radial-gradient(1000px 700px at 90% 20%, rgba(255,111,174,.14), transparent 55%),
var(--bg);
color:var(--text);
font: 14px/1.4 system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
}
header{
padding:22px 18px 10px;
max-width:1200px; margin:0 auto;
}
h1{margin:0; font-size:20px; letter-spacing:.2px}
.sub{margin-top:6px; color:var(--muted)}
.wrap{max-width:1200px; margin:0 auto; padding:14px 18px 26px}
.grid{
display:grid;
grid-template-columns: 1.2fr .8fr;
gap:14px;
}
@media (max-width: 980px){
.grid{grid-template-columns:1fr}
}
.card{
background:linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,.02));
border:1px solid var(--line);
border-radius:var(--radius);
box-shadow:var(--shadow);
overflow:hidden;
}
.card .hd{
padding:14px 14px 10px;
border-bottom:1px solid var(--line);
display:flex; align-items:center; justify-content:space-between; gap:10px;
background:linear-gradient(180deg, rgba(122,162,255,.10), transparent 60%);
}
.badge{
display:inline-flex; align-items:center; gap:8px;
padding:6px 10px;
border-radius:999px;
border:1px solid var(--line);
background:rgba(0,0,0,.18);
color:var(--muted);
font-weight:600;
white-space:nowrap;
}
.dot{width:9px; height:9px; border-radius:50%;}
.dot.a{background:var(--accent)}
.dot.b{background:var(--accent2)}
.dot.turn{background:var(--warn)}
.actions{display:flex; gap:8px; flex-wrap:wrap; justify-content:flex-end}
button{
border:1px solid var(--line);
background:rgba(0,0,0,.22);
color:var(--text);
padding:9px 11px;
border-radius:12px;
cursor:pointer;
font-weight:700;
transition: transform .05s ease, background .15s ease;
}
button:hover{background:rgba(255,255,255,.06)}
button:active{transform: translateY(1px)}
button.primary{
border-color: rgba(122,162,255,.35);
background: rgba(122,162,255,.18);
}
button.danger{
border-color: rgba(255,107,107,.35);
background: rgba(255,107,107,.14);
}
button.ghost{
background:transparent;
}
button:disabled{
opacity:.45; cursor:not-allowed;
}
.body{padding:14px}
.row{display:grid; grid-template-columns:1fr 1fr; gap:12px}
@media (max-width:700px){ .row{grid-template-columns:1fr} }
label{display:block; color:var(--muted); font-weight:700; margin-bottom:6px}
input[type="text"], textarea, select{
width:100%;
border:1px solid var(--line);
background: rgba(0,0,0,.22);
color: var(--text);
padding:10px 10px;
border-radius:12px;
outline:none;
}
textarea{min-height:74px; resize:vertical}
.hint{color:var(--muted); font-size:12px; margin-top:6px}
.kpi{display:flex; gap:10px; flex-wrap:wrap; align-items:center}
.kpi .pill{
padding:7px 10px; border-radius:999px; border:1px solid var(--line);
background:rgba(0,0,0,.18); color:var(--muted); font-weight:800;
}
.kpi .pill strong{color:var(--text)}
.split{
display:grid; grid-template-columns:1fr 1fr; gap:12px;
}
@media (max-width:900px){ .split{grid-template-columns:1fr} }
.log{
display:flex; flex-direction:column; gap:10px;
max-height:520px; overflow:auto; padding-right:6px;
}
.entry{
border:1px solid var(--line);
border-radius:14px;
background: rgba(0,0,0,.16);
padding:10px 10px;
}
.entry .meta{
display:flex; justify-content:space-between; gap:10px; flex-wrap:wrap;
margin-bottom:8px;
}
.entry .meta .t{font-weight:900}
.entry .meta .s{color:var(--muted); font-weight:700}
.entry pre{
margin:0;
white-space:pre-wrap;
font: 12px/1.35 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
color:#dbe4ff;
}
.mini{
font-size:12px; color:var(--muted);
}
.bar{
height:10px; border-radius:999px;
background:rgba(255,255,255,.06);
border:1px solid var(--line);
overflow:hidden;
}
.bar > div{height:100%; width:0%; background:linear-gradient(90deg, var(--accent), var(--accent2));}
.sectionTitle{font-size:13px; font-weight:900; letter-spacing:.2px; margin:0 0 10px}
.divider{height:1px; background:var(--line); margin:12px 0}
.inline{
display:flex; gap:10px; flex-wrap:wrap; align-items:center;
}
.toggle{
display:flex; align-items:center; gap:8px; padding:8px 10px; border:1px solid var(--line);
border-radius:12px; background:rgba(0,0,0,.16);
color:var(--muted); font-weight:800;
}
.toggle input{transform: translateY(1px)}
.modal{
position:fixed; inset:0;
background: rgba(0,0,0,.60);
display:none;
align-items:center; justify-content:center;
padding:18px;
z-index:50;
}
.modal.show{display:flex}
.modal .box{
width:min(980px, 100%);
background:linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.03));
border:1px solid var(--line);
border-radius:18px;
box-shadow: 0 30px 70px rgba(0,0,0,.55);
overflow:hidden;
}
.modal .box .hd{
background:linear-gradient(180deg, rgba(255,204,102,.14), rgba(0,0,0,.0));
border-bottom:1px solid var(--line);
}
.scores{
display:grid; grid-template-columns:1fr 1fr; gap:12px;
}
@media (max-width:900px){ .scores{grid-template-columns:1fr} }
.scoreRow{display:flex; gap:10px; align-items:center; justify-content:space-between}
.scoreRow select{max-width:110px}
.callout{
padding:10px 12px; border-radius:14px; border:1px solid var(--line);
background:rgba(0,0,0,.18); color:var(--muted);
}
.callout strong{color:var(--text)}
.good{color:var(--good)} .warn{color:var(--warn)} .bad{color:var(--bad)}
.footerButtons{display:flex; justify-content:flex-end; gap:10px; flex-wrap:wrap}
.tinyBtn{padding:7px 10px; border-radius:10px; font-weight:800}
.pillSmall{
padding:5px 9px; border-radius:999px; border:1px solid var(--line);
background:rgba(0,0,0,.18); color:var(--muted); font-weight:900; font-size:12px;
}
.mono{font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;}
</style>
</head>
<body>
<header>
<h1>AI Adoption Arena — Team A vs Team B</h1>
<div class="sub">10 turns, alternating A/B. Each team finishes with <b>2 Challenges</b> + <b>2 Opportunities</b> + mitigations + first 30 days steps. Facilitator scores each turn (0–10) and manages Power Plays.</div>
</header>
<div class="wrap">
<div class="grid">
<!-- LEFT: Gameplay -->
<section class="card" id="gameCard">
<div class="hd">
<div class="kpi">
<span class="badge"><span class="dot turn"></span> Turn <strong id="turnNum">1</strong> / 10</span>
<span class="badge"><span class="dot a" id="teamDot"></span> Active: <strong id="activeTeam">Team A</strong></span>
<span class="badge"><span class="dot"></span> Type: <strong id="turnType">Warm Start Opportunity</strong></span>
</div>
<div class="actions">
<button class="ghost tinyBtn" id="btnHelp">Rules</button>
<button class="ghost tinyBtn" id="btnExport">Export</button>
<button class="danger tinyBtn" id="btnReset">Reset</button>
</div>
</div>
<div class="body">
<div class="split">
<div>
<h3 class="sectionTitle">Active Team Submission</h3>
<div class="callout" id="turnBrief"></div>
<div class="divider"></div>
<form id="turnForm">
<div class="row">
<div>
<label id="lbl1">Use case / workflow</label>
<textarea id="f1" required placeholder="Example: Customer support intake triage in ServiceNow; handoffs between Tier 1 and Tier 2"></textarea>
</div>
<div>
<label id="lbl2">Who benefits</label>
<textarea id="f2" required placeholder="Example: Tier 1 agents, supervisors, customers waiting on updates"></textarea>
</div>
</div>
<div class="row">
<div>
<label id="lbl3">Value / Impact (metric)</label>
<textarea id="f3" required placeholder="Example: reduce handle time by 20%; cut backlog by 15%; reduce compliance risk"></textarea>
</div>
<div>
<label id="lbl4">Feasibility / Root cause</label>
<textarea id="f4" required placeholder="Example: knowledge base is fragmented; access controls needed; data quality is inconsistent"></textarea>
</div>
</div>
<div>
<label id="lbl5">First 30 days</label>
<textarea id="f5" required placeholder="Example: define pilot scope, pick 1 queue, baseline cycle time, create guardrails, run a 2-week pilot"></textarea>
<div class="hint">Strict 5-line format is enforced in spirit: keep each field to 1–2 sentences.</div>
</div>
<div class="divider"></div>
<div class="inline">
<span class="pillSmall">Power Plays available (Active Team)</span>
<span class="pillSmall" id="ppActive">Steal: ✓ | Block: ✓</span>
</div>
<div class="divider"></div>
<div class="footerButtons">
<button type="submit" class="primary" id="btnSubmitTurn">Submit Turn → Review & Score</button>
</div>
</form>
</div>
<div>
<h3 class="sectionTitle">Scoreboard</h3>
<div class="callout">
<div class="kpi" style="gap:8px">
<span class="pill"><span class="dot a"></span> Team A: <strong id="scoreA">0</strong></span>
<span class="pill"><span class="dot b"></span> Team B: <strong id="scoreB">0</strong></span>
<span class="pill"><span class="dot turn"></span> Lead: <strong id="lead"></strong></span>
</div>
<div class="divider"></div>
<div class="mini">
Progress to finish:
<div class="bar" style="margin-top:8px"><div id="progress"></div></div>
</div>
</div>
<div class="divider"></div>
<h3 class="sectionTitle">Turn Log</h3>
<div class="log" id="log"></div>
<div class="divider"></div>
<button class="primary" id="btnSummary" style="width:100%" disabled>Generate Final Summary & Pitch</button>
</div>
</div>
</div>
</section>
<!-- RIGHT: Quick Reference -->
<aside class="card">
<div class="hd">
<span class="badge"><span class="dot"></span> Quick Reference</span>
<span class="badge mono">A/B alternate</span>
</div>
<div class="body">
<div class="callout">
<strong>Turn Types (fixed sequence)</strong><br/>
1 A: Opportunity #1 · 2 B: Opportunity #1 · 3 A: Challenge #1 · 4 B: Challenge #1 ·
5 A: Risk & Reality · 6 B: Risk & Reality · 7 A: Opportunity #2 · 8 B: Opportunity #2 ·
9 A: Challenge #2 · 10 B: Challenge #2
</div>
<div class="divider"></div>
<div class="callout">
<strong>Scoring (0–10 per turn)</strong><br/>
Specificity (0–2) · Value/Impact (0–2) · Root cause/Feasibility (0–2) · Actionability (0–2) · Risk Awareness (0–2)<br/>
Optional <span class="good">+1 bonus</span> for a proof signal (ticket volume, cycle time, etc.)
</div>
<div class="divider"></div>
<div class="callout">
<strong>Power Plays (each team: 1 Steal + 1 Block total)</strong><br/>
<span class="good">Steal:</span> if opponent is generic, refine it (workflow + metric + 30-day step) → <span class="good">+3</span> to stealer, <span class="bad">-2</span> to opponent (facilitator confirms).<br/>
<span class="warn">Block:</span> force one hard question. If opponent fails → <span class="bad">-3</span>. If they answer well → <span class="good">+2</span>.
</div>
<div class="divider"></div>
<div class="callout">
<strong>Challenge Bank (for Blocks)</strong>
<ol class="mini" style="margin:8px 0 0 18px; padding:0">
<li>Name the exact workflow step where this breaks.</li>
<li>What metric proves it’s real (hours/week, defects/month)?</li>
<li>Which system/data source is involved?</li>
<li>Who owns the process today?</li>
<li>What fails in production (accuracy, latency, access, policy, adoption)?</li>
<li>What pilot can you run in 30 days without new tooling?</li>
</ol>
</div>
</div>
</aside>
</div>
</div>
<!-- MODAL: Review & Score -->
<div class="modal" id="scoreModal" aria-hidden="true">
<div class="box">
<div class="hd" style="padding:14px 14px 10px; display:flex; justify-content:space-between; gap:10px; flex-wrap:wrap;">
<div class="kpi">
<span class="badge"><span class="dot turn"></span> Review Turn <strong id="mTurn">1</strong></span>
<span class="badge"><span class="dot a" id="mTeamDot"></span> Submitted by <strong id="mTeam">Team A</strong></span>
<span class="badge"><span class="dot"></span> Type <strong id="mType"></strong></span>
</div>
<button class="ghost tinyBtn" id="btnCloseModal">Close</button>
</div>
<div class="body">
<div class="scores">
<div>
<h3 class="sectionTitle">Submission (read aloud)</h3>
<div class="entry">
<div class="meta">
<div class="t" id="mTitle"></div>
<div class="s" id="mWhen"></div>
</div>
<pre id="mText"></pre>
</div>
<div class="divider"></div>
<h3 class="sectionTitle">Opposition Challenge + Power Plays</h3>
<div class="callout">
<div class="mini">Opposing team may ask one hard question or use a power play. Facilitator captures it here.</div>
<div class="divider"></div>
<div class="row">
<div>
<label>Opposing action</label>
<select id="oppAction">
<option value="none">No challenge</option>
<option value="question">Ask a hard question</option>
<option value="steal">Use STEAL</option>
<option value="block">Use BLOCK</option>
</select>
<div class="hint">STEAL and BLOCK are limited per team (tracked automatically).</div>
</div>
<div>
<label>Hard question (if applicable)</label>
<select id="hardQ">
<option value="">— Select a question —</option>
<option>Name the exact workflow step where this breaks.</option>
<option>What metric proves it’s real (hours/week, defects/month)?</option>
<option>Which system/data source is involved?</option>
<option>Who owns the process today?</option>
<option>What fails in production (accuracy, latency, access, policy, adoption)?</option>
<option>What pilot can you run in 30 days without new tooling?</option>
</select>
</div>
</div>
<div class="row" style="margin-top:10px">
<div>
<label>Facilitator notes</label>
<textarea id="oppNotes" placeholder="Capture the question, the team’s response, and any key clarifications."></textarea>
</div>
<div>
<label>Outcome toggles</label>
<div class="toggle"><input type="checkbox" id="bonusProof" /> <span>+1 Bonus: “proof signal” included</span></div>
<div class="toggle"><input type="checkbox" id="stealSuccess" /> <span>STEAL successful (apply +3 / -2)</span></div>
<div class="toggle"><input type="checkbox" id="blockFailed" /> <span>BLOCK failed (apply -3 to submitted team)</span></div>
<div class="toggle"><input type="checkbox" id="blockAnsweredWell" /> <span>BLOCK answered well (apply +2 to submitted team)</span></div>
<div class="hint">BLOCK: choose either “failed” or “answered well” (or neither).</div>
</div>
</div>
</div>
</div>
<div>
<h3 class="sectionTitle">Facilitator Scoring (0–10)</h3>
<div class="callout">
<div class="scoreRow"><span><strong>Specificity</strong> (0–2)</span>
<select class="sc" data-k="spec"><option>0</option><option>1</option><option>2</option></select>
</div>
<div class="scoreRow"><span><strong>Business Impact / Value</strong> (0–2)</span>
<select class="sc" data-k="value"><option>0</option><option>1</option><option>2</option></select>
</div>
<div class="scoreRow"><span><strong>Root cause / Feasibility</strong> (0–2)</span>
<select class="sc" data-k="clarity"><option>0</option><option>1</option><option>2</option></select>
</div>
<div class="scoreRow"><span><strong>Actionability</strong> (0–2)</span>
<select class="sc" data-k="action"><option>0</option><option>1</option><option>2</option></select>
</div>
<div class="scoreRow"><span><strong>Risk awareness</strong> (0–2)</span>
<select class="sc" data-k="risk"><option>0</option><option>1</option><option>2</option></select>
</div>
<div class="divider"></div>
<div class="callout" style="display:flex; justify-content:space-between; align-items:center; gap:12px; flex-wrap:wrap;">
<div>
<div class="mini">Turn total</div>
<div style="font-size:22px; font-weight:950">
<span id="turnTotal">0</span>
<span class="mini">/ 11 max (with bonus)</span>
</div>
</div>
<div class="footerButtons">
<button class="danger" id="btnCancelScore">Cancel</button>
<button class="primary" id="btnApplyScore">Apply Score & Advance Turn</button>
</div>
</div>
<div class="hint">Tip: if a team is too generic, use STEAL against them or hit them with a hard question.</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- MODAL: Help -->
<div class="modal" id="helpModal" aria-hidden="true">
<div class="box">
<div class="hd" style="padding:14px 14px 10px; display:flex; justify-content:space-between; gap:10px; flex-wrap:wrap;">
<div class="kpi">
<span class="badge"><span class="dot"></span> Rules (Quick)</span>
</div>
<button class="ghost tinyBtn" id="btnCloseHelp">Close</button>
</div>
<div class="body">
<div class="callout">
<strong>How to run it live</strong>
<ol style="margin:10px 0 0 18px; padding:0; color:var(--muted)">
<li>Turn alternates A/B automatically for 10 turns.</li>
<li>Active team enters a 5-field submission (keep each field 1–2 sentences).</li>
<li>On “Review & Score”, opposition can challenge or power-play (facilitator captures it).</li>
<li>Facilitator scores 0–10 (+1 bonus optional), applies any power-play effects, advances.</li>
<li>After Turn 10, click “Generate Final Summary & Pitch” for 2–3 minute pitch bullets.</li>
</ol>
</div>
<div class="divider"></div>
<div class="callout">
<strong>Power Plays</strong><br/>
<span class="good">STEAL</span>: opponent is generic; refines into workflow + metric + 30-day step. Facilitator checks “STEAL successful” → stealer <span class="good">+3</span>, submitted team <span class="bad">-2</span>.<br/>
<span class="warn">BLOCK</span>: hard question. If submitted team fails → <span class="bad">-3</span>. If they answer well → <span class="good">+2</span> (facilitator selects outcome).
</div>
</div>
</div>
</div>
<script>
/**
* AI Adoption Arena — single-file app
* - 10 turns alternating A/B
* - Facilitator scoring + power plays
* - Final summary + pitch generator
*/
const TURN_PLAN = [
{ team: "A", kind: "opportunity", title: "Warm Start Opportunity", brief: "Deliver Opportunity #1 (draft): workflow + users + value hypothesis + feasibility + first 30 days." },
{ team: "B", kind: "opportunity", title: "Warm Start Opportunity", brief: "Deliver Opportunity #1 (draft): workflow + users + value hypothesis + feasibility + first 30 days." },
{ team: "A", kind: "challenge", title: "Pain Point Challenge", brief: "Deliver Challenge #1 (draft): what's happening + root cause + impact metric + mitigation + first 30 days." },
{ team: "B", kind: "challenge", title: "Pain Point Challenge", brief: "Deliver Challenge #1 (draft): what's happening + root cause + impact metric + mitigation + first 30 days." },
{ team: "A", kind: "risk", title: "Risk & Reality Check", brief: "Name one derailment risk (data/security/compliance/change) impacting your items, and how you'd handle it in 30 days." },
{ team: "B", kind: "risk", title: "Risk & Reality Check", brief: "Name one derailment risk (data/security/compliance/change) impacting your items, and how you'd handle it in 30 days." },
{ team: "A", kind: "opportunity", title: "Second Opportunity with Differentiation", brief: "Deliver Opportunity #2: must differ from Opportunity #1 (different workflow or user group)." },
{ team: "B", kind: "opportunity", title: "Second Opportunity with Differentiation", brief: "Deliver Opportunity #2: must differ from Opportunity #1 (different workflow or user group)." },
{ team: "A", kind: "challenge", title: "Second Challenge + Mitigation", brief: "Deliver Challenge #2 plus a mitigation that can start in 30 days." },
{ team: "B", kind: "challenge", title: "Second Challenge + Mitigation", brief: "Deliver Challenge #2 plus a mitigation that can start in 30 days." }
];
const els = {
turnNum: document.getElementById("turnNum"),
activeTeam: document.getElementById("activeTeam"),
teamDot: document.getElementById("teamDot"),
turnType: document.getElementById("turnType"),
turnBrief: document.getElementById("turnBrief"),
lbl1: document.getElementById("lbl1"),
lbl2: document.getElementById("lbl2"),
lbl3: document.getElementById("lbl3"),
lbl4: document.getElementById("lbl4"),
lbl5: document.getElementById("lbl5"),
f1: document.getElementById("f1"),
f2: document.getElementById("f2"),
f3: document.getElementById("f3"),
f4: document.getElementById("f4"),
f5: document.getElementById("f5"),
scoreA: document.getElementById("scoreA"),
scoreB: document.getElementById("scoreB"),
lead: document.getElementById("lead"),
progress: document.getElementById("progress"),
log: document.getElementById("log"),
btnSummary: document.getElementById("btnSummary"),
btnReset: document.getElementById("btnReset"),
btnExport: document.getElementById("btnExport"),
btnHelp: document.getElementById("btnHelp"),
ppActive: document.getElementById("ppActive"),
// Score modal
scoreModal: document.getElementById("scoreModal"),
btnCloseModal: document.getElementById("btnCloseModal"),
btnCancelScore: document.getElementById("btnCancelScore"),
btnApplyScore: document.getElementById("btnApplyScore"),
mTurn: document.getElementById("mTurn"),
mTeam: document.getElementById("mTeam"),
mTeamDot: document.getElementById("mTeamDot"),
mType: document.getElementById("mType"),
mTitle: document.getElementById("mTitle"),
mWhen: document.getElementById("mWhen"),
mText: document.getElementById("mText"),
oppAction: document.getElementById("oppAction"),
hardQ: document.getElementById("hardQ"),
oppNotes: document.getElementById("oppNotes"),
bonusProof: document.getElementById("bonusProof"),
stealSuccess: document.getElementById("stealSuccess"),
blockFailed: document.getElementById("blockFailed"),
blockAnsweredWell: document.getElementById("blockAnsweredWell"),
turnTotal: document.getElementById("turnTotal"),
// Help modal
helpModal: document.getElementById("helpModal"),
btnCloseHelp: document.getElementById("btnCloseHelp"),
};
const scoreSelects = Array.from(document.querySelectorAll(".sc"));
let state = {
turnIndex: 0, // 0..9
scores: { A: 0, B: 0 },
powerPlays: {
A: { stealUsed: false, blockUsed: false },
B: { stealUsed: false, blockUsed: false }
},
turns: [] // each: {turn, team, kind, fields, scoring, opp, totalDelta}
};
function nowStamp(){
return new Date().toLocaleString();
}
function activePlan(){
return TURN_PLAN[state.turnIndex];
}
function opponentOf(team){
return team === "A" ? "B" : "A";
}
function updateHeader(){
const p = activePlan();
els.turnNum.textContent = String(state.turnIndex + 1);
els.activeTeam.textContent = `Team ${p.team}`;
els.turnType.textContent = p.title;
els.turnBrief.innerHTML = `<strong>Turn brief:</strong> ${p.brief}`;
els.teamDot.className = "dot " + (p.team === "A" ? "a" : "b");
// progress bar
const pct = ((state.turnIndex) / 10) * 100;
els.progress.style.width = pct + "%";
// power play availability for active team
const pp = state.powerPlays[p.team];
els.ppActive.textContent =
`Steal: ${pp.stealUsed ? "—" : "✓"} | Block: ${pp.blockUsed ? "—" : "✓"}`;
// update form labels by kind
setFormForKind(p.kind);
}
function setFormForKind(kind){
if(kind === "opportunity"){
els.lbl1.textContent = "Use case / workflow";
els.lbl2.textContent = "Who benefits";
els.lbl3.textContent = "Value hypothesis (metric)";
els.lbl4.textContent = "Feasibility assumptions";
els.lbl5.textContent = "First 30 days";
setPlaceholders({
f1:"Example: Sales enablement content creation; proposal drafting; call summary workflow",
f2:"Example: Account executives, sales ops, customers reviewing proposals",
f3:"Example: reduce proposal cycle time by 30%; increase win rate by 3–5%",
f4:"Example: data access to CRM; approved content sources; review workflow needed",
f5:"Example: select 1 region; baseline cycle time; pilot prompt+review; measure outcomes"
});
} else if(kind === "challenge"){
els.lbl1.textContent = "What’s happening (where in workflow)";
els.lbl2.textContent = "Root cause";
els.lbl3.textContent = "Business impact (metric)";
els.lbl4.textContent = "Mitigation";
els.lbl5.textContent = "First 30 days";
setPlaceholders({
f1:"Example: Agents spend 10+ minutes searching across 4 KBs; inconsistent answers",
f2:"Example: knowledge is fragmented; access is inconsistent; no governance",
f3:"Example: +15% handle time; escalations rising; SLA misses weekly",
f4:"Example: consolidate KB sources; add access controls; establish review cadence",
f5:"Example: choose 1 queue; define KB scope; baseline; pilot; run weekly calibration"
});
} else { // risk
els.lbl1.textContent = "Derailment risk (data/security/compliance/change)";
els.lbl2.textContent = "Which item is impacted (challenge/opportunity)";
els.lbl3.textContent = "Failure mode (what goes wrong)";
els.lbl4.textContent = "Mitigation/guardrail";
els.lbl5.textContent = "First 30 days";
setPlaceholders({
f1:"Example: PII exposure risk; model hallucination risk; access control gaps",
f2:"Example: Impacts Opportunity #1 (support triage) and Challenge #1 (KB fragmentation)",
f3:"Example: wrong disclosure; policy violation; low trust; adoption stalls",
f4:"Example: redaction, role-based access, human review, allowed sources only",
f5:"Example: define policy; implement access; add eval set; create escalation playbook"
});
}
}
function setPlaceholders(p){
els.f1.placeholder = p.f1;
els.f2.placeholder = p.f2;
els.f3.placeholder = p.f3;
els.f4.placeholder = p.f4;
els.f5.placeholder = p.f5;
}
function updateScoreboard(){
els.scoreA.textContent = String(state.scores.A);
els.scoreB.textContent = String(state.scores.B);
let lead = "Tie";
if(state.scores.A > state.scores.B) lead = `Team A (+${state.scores.A - state.scores.B})`;
if(state.scores.B > state.scores.A) lead = `Team B (+${state.scores.B - state.scores.A})`;
els.lead.textContent = lead;
// enable summary if finished
els.btnSummary.disabled = state.turnIndex < 10;
els.progress.style.width = Math.min((state.turnIndex/10)*100, 100) + "%";
}
function clearForm(){
els.f1.value = "";
els.f2.value = "";
els.f3.value = "";
els.f4.value = "";
els.f5.value = "";
}
function openModal(){
els.scoreModal.classList.add("show");
els.scoreModal.setAttribute("aria-hidden","false");
}
function closeModal(){
els.scoreModal.classList.remove("show");
els.scoreModal.setAttribute("aria-hidden","true");
}
function openHelp(){
els.helpModal.classList.add("show");
els.helpModal.setAttribute("aria-hidden","false");
}
function closeHelp(){
els.helpModal.classList.remove("show");
els.helpModal.setAttribute("aria-hidden","true");
}
function computeTurnScore(){
const base = scoreSelects.reduce((sum, sel) => sum + Number(sel.value), 0);
const bonus = els.bonusProof.checked ? 1 : 0;
return base + bonus;
}
function updateTurnTotalUI(){
els.turnTotal.textContent = String(computeTurnScore());
}
function formatSubmission(plan, fields){
const lines = [];
if(plan.kind === "opportunity"){
lines.push(`1) Use case / workflow: ${fields.f1}`);
lines.push(`2) Who benefits: ${fields.f2}`);
lines.push(`3) Value hypothesis (metric): ${fields.f3}`);
lines.push(`4) Feasibility assumptions: ${fields.f4}`);
lines.push(`5) First 30 days: ${fields.f5}`);
} else if(plan.kind === "challenge"){
lines.push(`1) What’s happening: ${fields.f1}`);
lines.push(`2) Root cause: ${fields.f2}`);
lines.push(`3) Business impact (metric): ${fields.f3}`);
lines.push(`4) Mitigation: ${fields.f4}`);
lines.push(`5) First 30 days: ${fields.f5}`);
} else {
lines.push(`1) Derailment risk: ${fields.f1}`);
lines.push(`2) Item impacted: ${fields.f2}`);
lines.push(`3) Failure mode: ${fields.f3}`);
lines.push(`4) Mitigation/guardrail: ${fields.f4}`);
lines.push(`5) First 30 days: ${fields.f5}`);
}
return lines.join("\n");
}
function renderLog(){
els.log.innerHTML = "";
for(const t of state.turns){
const div = document.createElement("div");
div.className = "entry";
const isA = t.team === "A";
const teamLabel = `Team ${t.team}`;
const typeLabel = t.plan.title;
const delta = t.deltaTotal ?? 0;
div.innerHTML = `
<div class="meta">
<div class="t">${teamLabel} — Turn ${t.turn}: ${typeLabel}</div>
<div class="s">${t.when}</div>
</div>
<div class="mini">
Score: <b>${t.scoreBase}</b>${t.bonus ? " +1 bonus" : ""} = <b>${t.scoreTotal}</b>
${t.powerPlaySummary ? ` · <span class="warn">${t.powerPlaySummary}</span>` : ""}
${delta !== 0 ? ` · Net delta: <b>${delta>0?"+":""}${delta}</b>` : ""}
</div>
<div class="divider"></div>
<pre>${t.text}</pre>
${t.opp && (t.opp.action !== "none" || t.opp.notes) ? `
<div class="divider"></div>
<div class="mini"><b>Opposition:</b> ${t.opp.action}${t.opp.question ? " — " + t.opp.question : ""}</div>
${t.opp.notes ? `<pre style="color:#cbd6ff; margin-top:6px">${t.opp.notes}</pre>` : ""}
` : ""}
`;
els.log.appendChild(div);
}
}
function resetScoreModal(){
scoreSelects.forEach(s => s.value = "0");
els.oppAction.value = "none";
els.hardQ.value = "";
els.oppNotes.value = "";
els.bonusProof.checked = false;
els.stealSuccess.checked = false;
els.blockFailed.checked = false;
els.blockAnsweredWell.checked = false;
updateTurnTotalUI();
}
function clampNonNegative(){
state.scores.A = Math.max(0, state.scores.A);
state.scores.B = Math.max(0, state.scores.B);
}
/* ---------- Event wiring ---------- */
document.getElementById("turnForm").addEventListener("submit", (e) => {
e.preventDefault();
// build pending turn record
const plan = activePlan();
const fields = {
f1: els.f1.value.trim(),
f2: els.f2.value.trim(),
f3: els.f3.value.trim(),
f4: els.f4.value.trim(),
f5: els.f5.value.trim()
};
// Basic guardrail: keep it non-empty
for(const k of Object.keys(fields)){
if(!fields[k]){ alert("Please fill all fields."); return; }
}
// open scoring modal with data
resetScoreModal();
els.mTurn.textContent = String(state.turnIndex + 1);
els.mTeam.textContent = `Team ${plan.team}`;
els.mTeamDot.className = "dot " + (plan.team === "A" ? "a" : "b");
els.mType.textContent = plan.title;
els.mTitle.textContent = (plan.kind === "opportunity" ? "Opportunity submission" :
plan.kind === "challenge" ? "Challenge submission" : "Risk & reality submission");
els.mWhen.textContent = nowStamp();
els.mText.textContent = formatSubmission(plan, fields);
// Store pending data on modal element
els.scoreModal._pending = { plan, fields, text: els.mText.textContent };
// Ensure opposition actions respect availability
// (We'll validate on Apply.)
openModal();
});
els.btnCloseModal.addEventListener("click", closeModal);
els.btnCancelScore.addEventListener("click", () => { closeModal(); });
scoreSelects.forEach(sel => sel.addEventListener("change", updateTurnTotalUI));
els.bonusProof.addEventListener("change", updateTurnTotalUI);
els.stealSuccess.addEventListener("change", () => {
// if stealSuccess set, ensure action is steal
if(els.stealSuccess.checked) els.oppAction.value = "steal";
});
els.blockFailed.addEventListener("change", () => {
if(els.blockFailed.checked) {
els.blockAnsweredWell.checked = false;
els.oppAction.value = "block";
}
});
els.blockAnsweredWell.addEventListener("change", () => {
if(els.blockAnsweredWell.checked) {
els.blockFailed.checked = false;
els.oppAction.value = "block";
}
});
els.btnApplyScore.addEventListener("click", () => {
const pending = els.scoreModal._pending;
if(!pending) return;
const { plan, fields, text } = pending;
const submittedTeam = plan.team;
const oppTeam = opponentOf(submittedTeam);
// Validate power play usage and apply effects
const action = els.oppAction.value;
const oppPP = state.powerPlays[oppTeam];
// Enforce availability
if(action === "steal" && oppPP.stealUsed){
alert(`Team ${oppTeam} already used STEAL. Choose a different opposing action.`);
return;
}
if(action === "block" && oppPP.blockUsed){
alert(`Team ${oppTeam} already used BLOCK. Choose a different opposing action.`);
return;
}
// Determine base score
const base = scoreSelects.reduce((sum, sel) => sum + Number(sel.value), 0);
const bonus = els.bonusProof.checked ? 1 : 0;
const scoreTotal = base + bonus;
// Apply base score to submitted team
state.scores[submittedTeam] += scoreTotal;
// Apply opposition effects (if any)
let powerPlaySummary = "";
let deltaTotal = scoreTotal; // net for submitted team before PP adjustments
// Capture opposition info
const oppInfo = {
action,
question: (action === "question" || action === "block") ? els.hardQ.value : "",
notes: els.oppNotes.value.trim()
};
if(action === "question"){
powerPlaySummary = "Hard question asked";
// No automatic scoring change; facilitator can reflect in the 0–10 score.
}
if(action === "steal"){
// Mark use
oppPP.stealUsed = true;
// If facilitator confirms success, apply +3 to opp, -2 to submitted
if(els.stealSuccess.checked){
state.scores[oppTeam] += 3;
state.scores[submittedTeam] -= 2;
powerPlaySummary = `STEAL successful: Team ${oppTeam} +3, Team ${submittedTeam} -2`;
deltaTotal = scoreTotal - 2; // submitted net after penalty
} else {
powerPlaySummary = `STEAL attempted (not successful)`;
}
}
if(action === "block"){
oppPP.blockUsed = true;
if(els.blockFailed.checked){
state.scores[submittedTeam] -= 3;
powerPlaySummary = `BLOCK failed: Team ${submittedTeam} -3`;
deltaTotal = scoreTotal - 3;
} else if(els.blockAnsweredWell.checked){
state.scores[submittedTeam] += 2;
powerPlaySummary = `BLOCK answered well: Team ${submittedTeam} +2`;
deltaTotal = scoreTotal + 2;
} else {
powerPlaySummary = `BLOCK used (no outcome selected)`;
}
}
clampNonNegative();
// Save turn record
state.turns.push({
turn: state.turnIndex + 1,
team: submittedTeam,
plan,
fields,
text,
when: els.mWhen.textContent,
scoreBase: base,
bonus,
scoreTotal,
opp: oppInfo,
powerPlaySummary,
deltaTotal
});
// Advance turn
state.turnIndex += 1;
// Close modal, update UI
closeModal();
clearForm();
renderLog();
updateScoreboard();
if(state.turnIndex >= 10){
// finished
els.progress.style.width = "100%";
els.turnNum.textContent = "10";
document.getElementById("activeTeam").textContent = "—";
document.getElementById("turnType").textContent = "Game complete";
document.getElementById("turnBrief").innerHTML = `<strong>Game complete:</strong> Click “Generate Final Summary & Pitch” to get each team’s 2 Challenges + 2 Opportunities and a 2–3 minute script.`;
document.getElementById("turnForm").querySelectorAll("textarea,button,select,input").forEach(x => x.disabled = true);
} else {
updateHeader();
}
});
els.btnSummary.addEventListener("click", () => {
const summary = buildFinalSummary();
// Show in a quick modal-like alert (but more readable): open a new window/tab
const w = window.open("", "_blank");
if(!w){ alert("Popup blocked. Use Export instead."); return; }
w.document.write(`<pre style="white-space:pre-wrap; font:14px/1.4 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; padding:18px">${escapeHtml(summary)}</pre>`);
w.document.close();
});
els.btnReset.addEventListener("click", () => {
if(!confirm("Reset the game? This clears turns and scores.")) return;
state = {
turnIndex: 0,
scores: { A: 0, B: 0 },
powerPlays: {
A: { stealUsed: false, blockUsed: false },
B: { stealUsed: false, blockUsed: false }
},
turns: []
};
// re-enable form
document.getElementById("turnForm").querySelectorAll("textarea,button,select,input").forEach(x => x.disabled = false);
clearForm();
renderLog();
updateHeader();
updateScoreboard();
});
els.btnExport.addEventListener("click", () => {
const payload = {
meta: {
app: "AI Adoption Arena",
exportedAt: new Date().toISOString(),
version: "1.0"
},
state
};
const text = JSON.stringify(payload, null, 2);
// copy to clipboard
navigator.clipboard?.writeText(text).then(() => {
alert("Export JSON copied to clipboard.");
}).catch(() => {
// fallback download
const blob = new Blob([text], {type:"application/json"});
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "ai-adoption-arena-export.json";
a.click();
URL.revokeObjectURL(a.href);
});
});
els.btnHelp.addEventListener("click", openHelp);
els.btnCloseHelp.addEventListener("click", closeHelp);
// Modal click outside to close (optional)
els.scoreModal.addEventListener("click", (e) => { if(e.target === els.scoreModal) closeModal(); });
els.helpModal.addEventListener("click", (e) => { if(e.target === els.helpModal) closeHelp(); });
/* ---------- Summary builder ---------- */
function buildFinalSummary(){
const byTeam = { A: { opp: [], chal: [], risk: [] }, B: { opp: [], chal: [], risk: [] } };
for(const t of state.turns){
const kind = t.plan.kind;
if(kind === "opportunity") byTeam[t.team].opp.push(t);
if(kind === "challenge") byTeam[t.team].chal.push(t);
if(kind === "risk") byTeam[t.team].risk.push(t);
}
function pickTopTwo(list){
// If facilitator scored, sort by scoreTotal descending, else keep order.
return [...list].sort((a,b) => (b.scoreTotal ?? 0) - (a.scoreTotal ?? 0)).slice(0,2);
}
const Aopp = pickTopTwo(byTeam.A.opp);
const Achal = pickTopTwo(byTeam.A.chal);
const Bopp = pickTopTwo(byTeam.B.opp);
const Bchal = pickTopTwo(byTeam.B.chal);
const lines = [];
lines.push("AI ADOPTION ARENA — FINAL OUTPUT");
lines.push("============================================================");
lines.push(`Scores: Team A = ${state.scores.A} | Team B = ${state.scores.B} | Lead: ${state.scores.A===state.scores.B?"Tie":(state.scores.A>state.scores.B?"Team A":"Team B")}`);
lines.push("");
lines.push(renderTeamSection("A", Achal, Aopp, byTeam.A.risk));
lines.push("");
lines.push(renderTeamSection("B", Bchal, Bopp, byTeam.B.risk));
lines.push("");
lines.push("PITCH SCRIPTS (2–3 MINUTES EACH)");
lines.push("------------------------------------------------------------");
lines.push(renderPitch("A", Achal, Aopp));
lines.push("");
lines.push(renderPitch("B", Bchal, Bopp));
return lines.join("\n");
}
function renderTeamSection(team, challenges, opportunities, risks){
const lines = [];
lines.push(`TEAM ${team} — PORTFOLIO (2 Challenges + 2 Opportunities)`);
lines.push("------------------------------------------------------------");
lines.push("Challenges:");
if(challenges.length === 0) lines.push(" (none captured)");
challenges.forEach((t, idx) => {
lines.push(` Challenge ${idx+1}:`);
lines.push(" " + indentBlock(formatSubmission(t.plan, t.fields), 2).trimEnd());
lines.push(` Score: ${t.scoreTotal}${t.bonus ? " (incl. bonus)" : ""}`);
});
lines.push("");
lines.push("Opportunities:");
if(opportunities.length === 0) lines.push(" (none captured)");
opportunities.forEach((t, idx) => {
lines.push(` Opportunity ${idx+1}:`);
lines.push(" " + indentBlock(formatSubmission(t.plan, t.fields), 2).trimEnd());
lines.push(` Score: ${t.scoreTotal}${t.bonus ? " (incl. bonus)" : ""}`);
});
if(risks.length){
lines.push("");
lines.push("Risk & Reality Notes:");
risks.forEach((t, idx) => {
lines.push(` Risk ${idx+1}:`);
lines.push(" " + indentBlock(formatSubmission(t.plan, t.fields), 2).trimEnd());
});
}
return lines.join("\n");
}
function renderPitch(team, challenges, opportunities){
const lines = [];
lines.push(`TEAM ${team} — 2–3 MINUTE PITCH (bullets)`);
lines.push(`- One-sentence outcome: We are targeting improved AI adoption by addressing two blockers and delivering two high-value use cases.`);
lines.push(`- Challenge 1 (20 sec): ${shorten(challenges[0])}`);
lines.push(`- Challenge 2 (20 sec): ${shorten(challenges[1])}`);
lines.push(`- Opportunity 1 (30 sec): ${shorten(opportunities[0])}`);
lines.push(`- Opportunity 2 (30 sec): ${shorten(opportunities[1])}`);
lines.push(`- First 30 days plan (20 sec): Pilot one opportunity, baseline metrics, enforce guardrails, and establish a governance cadence.`);
return lines.join("\n");
}
function shorten(turn){
if(!turn) return "(not captured)";
const p = turn.plan.kind;
const f = turn.fields;
if(p === "challenge"){
return `${f.f1} | Impact: ${f.f3} | Mitigation: ${f.f4} | 30 days: ${f.f5}`;
}
if(p === "opportunity"){
return `${f.f1} | Value: ${f.f3} | Feasibility: ${f.f4} | 30 days: ${f.f5}`;
}
return `${f.f1} | Mitigation: ${f.f4} | 30 days: ${f.f5}`;
}
function indentBlock(text, spaces){
const pad = " ".repeat(spaces);
return text.split("\n").map(l => pad + l).join("\n");
}
function escapeHtml(s){
return s.replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
}
/* ---------- Init ---------- */
updateHeader();
updateScoreboard();
renderLog();
updateTurnTotalUI();
</script>
</body>
</html>