| <!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"> |
| |
| <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> |
|
|
| |
| <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> |
|
|
| |
| <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> |
|
|
| |
| <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> |
| |
| |
| |
| |
| |
| |
| |
| 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"), |
| |
| |
| 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"), |
| |
| |
| helpModal: document.getElementById("helpModal"), |
| btnCloseHelp: document.getElementById("btnCloseHelp"), |
| }; |
| |
| const scoreSelects = Array.from(document.querySelectorAll(".sc")); |
| |
| let state = { |
| turnIndex: 0, |
| scores: { A: 0, B: 0 }, |
| powerPlays: { |
| A: { stealUsed: false, blockUsed: false }, |
| B: { stealUsed: false, blockUsed: false } |
| }, |
| turns: [] |
| }; |
| |
| 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"); |
| |
| |
| const pct = ((state.turnIndex) / 10) * 100; |
| els.progress.style.width = pct + "%"; |
| |
| |
| const pp = state.powerPlays[p.team]; |
| els.ppActive.textContent = |
| `Steal: ${pp.stealUsed ? "—" : "✓"} | Block: ${pp.blockUsed ? "—" : "✓"}`; |
| |
| |
| 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 { |
| 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; |
| |
| |
| 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); |
| } |
| |
| |
| |
| document.getElementById("turnForm").addEventListener("submit", (e) => { |
| e.preventDefault(); |
| |
| |
| 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() |
| }; |
| |
| |
| for(const k of Object.keys(fields)){ |
| if(!fields[k]){ alert("Please fill all fields."); return; } |
| } |
| |
| |
| 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); |
| |
| |
| els.scoreModal._pending = { plan, fields, text: els.mText.textContent }; |
| |
| |
| |
| 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(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); |
| |
| |
| const action = els.oppAction.value; |
| const oppPP = state.powerPlays[oppTeam]; |
| |
| |
| 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; |
| } |
| |
| |
| const base = scoreSelects.reduce((sum, sel) => sum + Number(sel.value), 0); |
| const bonus = els.bonusProof.checked ? 1 : 0; |
| const scoreTotal = base + bonus; |
| |
| |
| state.scores[submittedTeam] += scoreTotal; |
| |
| |
| let powerPlaySummary = ""; |
| let deltaTotal = scoreTotal; |
| |
| |
| const oppInfo = { |
| action, |
| question: (action === "question" || action === "block") ? els.hardQ.value : "", |
| notes: els.oppNotes.value.trim() |
| }; |
| |
| if(action === "question"){ |
| powerPlaySummary = "Hard question asked"; |
| |
| } |
| |
| if(action === "steal"){ |
| |
| oppPP.stealUsed = true; |
| |
| if(els.stealSuccess.checked){ |
| state.scores[oppTeam] += 3; |
| state.scores[submittedTeam] -= 2; |
| powerPlaySummary = `STEAL successful: Team ${oppTeam} +3, Team ${submittedTeam} -2`; |
| deltaTotal = scoreTotal - 2; |
| } 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(); |
| |
| |
| state.turns.push({ |
| turn: state.turnIndex + 1, |
| team: submittedTeam, |
| plan, |
| fields, |
| text, |
| when: els.mWhen.textContent, |
| scoreBase: base, |
| bonus, |
| scoreTotal, |
| opp: oppInfo, |
| powerPlaySummary, |
| deltaTotal |
| }); |
| |
| |
| state.turnIndex += 1; |
| |
| |
| closeModal(); |
| clearForm(); |
| renderLog(); |
| updateScoreboard(); |
| |
| if(state.turnIndex >= 10){ |
| |
| 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(); |
| |
| 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: [] |
| }; |
| |
| 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); |
| |
| navigator.clipboard?.writeText(text).then(() => { |
| alert("Export JSON copied to clipboard."); |
| }).catch(() => { |
| |
| 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); |
| |
| |
| els.scoreModal.addEventListener("click", (e) => { if(e.target === els.scoreModal) closeModal(); }); |
| els.helpModal.addEventListener("click", (e) => { if(e.target === els.helpModal) closeHelp(); }); |
| |
| |
| |
| 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){ |
| |
| 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 => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); |
| } |
| |
| |
| updateHeader(); |
| updateScoreboard(); |
| renderLog(); |
| updateTurnTotalUI(); |
| </script> |
| </body> |
| </html> |
|
|