// === Module 3 - Simulator UI ===

// Minimal markdown-light: **bold**, *italic*, numbered leads
function renderMarkdownLight(text) {
  if (!text) return null;
  const paragraphs = text.split(/\n\s*\n+|\n/).map(s => s.trim()).filter(Boolean);
  const renderInline = (s, baseKey) => {
    const out = [];
    let remaining = s;
    let i = 0;
    while (remaining.length) {
      const bm = remaining.match(/\*\*([^*]+)\*\*/);
      if (bm && bm.index >= 0) {
        if (bm.index > 0) out.push(remaining.slice(0, bm.index));
        out.push(React.createElement('strong', { key: `${baseKey}-b-${i++}` }, bm[1]));
        remaining = remaining.slice(bm.index + bm[0].length);
        continue;
      }
      const im = remaining.match(/\*([^*\s][^*]*)\*/);
      if (im && im.index >= 0) {
        if (im.index > 0) out.push(remaining.slice(0, im.index));
        out.push(React.createElement('em', { key: `${baseKey}-i-${i++}` }, im[1]));
        remaining = remaining.slice(im.index + im[0].length);
        continue;
      }
      out.push(remaining);
      remaining = '';
    }
    return out;
  };
  return paragraphs.map((p, idx) => {
    const numMatch = p.match(/^(\d+)\.\s+(.*)$/);
    if (numMatch) {
      return React.createElement('p', { key: idx, className: 'md-numbered' },
        React.createElement('span', { className: 'md-num' }, numMatch[1]),
        React.createElement('span', null, renderInline(numMatch[2], `p${idx}`))
      );
    }
    return React.createElement('p', { key: idx }, renderInline(p, `p${idx}`));
  });
}

function M3OverviewSection({ state, update, go }) {
  const sim = state.m3 || {};
  const inProgress = sim.scenarioId && !sim.finished;
  const lastScenario = SCENARIOS.find((s) => s.id === sim.scenarioId);

  const start = (scenarioId) => {
    const sc = SCENARIOS.find((s) => s.id === scenarioId);
    update((s) => ({
      ...s,
      m3: {
        scenarioId,
        state: {
          eventIdx: 0,
          budget: sc.initialBudget,
          budgetSpent: 0,
          days: 0,
          daysLimit: sc.initialDays,
          morale: sc.initialMorale,
          quality: sc.initialQuality,
          history: [],
          startedAt: new Date().toISOString()  // for sim_runs.started_at
        },
        finished: false,
        finalScore: null,
        aiReport: null
      }
    }));
    go("m3-sim");
  };

  const resume = () => go("m3-sim");
  const review = () => go("m3-report");

  return (
    <div>
      <div className="main-head">
        <div className="crumb">Modul 3 · Simulator de proiect</div>
        <h1 className="section-title">Conduci proiectul. Decizia ta. Consecințele tale.</h1>
        <p className="section-lede">
          Alegi un scenariu, primești 8 decizii care contează. Fiecare alegere mută bugetul, calendarul, moralul și calitatea. La final, scor + raport AI care-ți spune unde ai excelat și unde ai pierdut.
        </p>
        <div className="section-meta">
          <span><Pill kind="info">3 scenarii</Pill></span>
          <span className="dot"></span>
          <span>~10 min per simulare · feedback AI</span>
        </div>
      </div>

      {inProgress &&
      <div className="m3-resume-banner">
          <div>
            <div className="eyebrow" style={{ color: "var(--accent-2)", marginBottom: 4 }}>Simulare în desfășurare</div>
            <div style={{ fontFamily: "var(--display)", fontSize: 20, fontWeight: 600, letterSpacing: "-0.015em" }}>{lastScenario?.title}</div>
            <div className="muted" style={{ fontSize: 13, marginTop: 4 }}>
              Eveniment {sim.state.eventIdx + 1} / {lastScenario?.events.length} · zi {sim.state.days} / {sim.state.daysLimit}
            </div>
          </div>
          <button className="btn primary" onClick={resume}>Continuă →</button>
        </div>
      }

      {sim.finished && sim.finalScore !== null &&
      <div className="m3-resume-banner" style={{ background: "linear-gradient(135deg, var(--good-soft) 0%, var(--bg-card) 100%)", borderColor: "rgba(16, 185, 129, 0.3)" }}>
          <div>
            <div className="eyebrow" style={{ color: "var(--good)", marginBottom: 4 }}>Simulare finalizată</div>
            <div style={{ fontFamily: "var(--display)", fontSize: 24, fontWeight: 700 }}>Scor: {sim.finalScore}/100</div>
            <div className="muted" style={{ fontSize: 13, marginTop: 4 }}>{lastScenario?.title}</div>
          </div>
          <button className="btn" onClick={review}>Vezi raport →</button>
        </div>
      }

      <div className="scenarios-grid">
        {SCENARIOS.map((sc) => {
          const isCurrent = sim.scenarioId === sc.id;
          return (
            <div key={sc.id} className={`scenario-card scenario-${sc.color}`}>
              <div className="scenario-icon">{sc.icon}</div>
              <div className="scenario-difficulty">
                {Array.from({ length: 5 }).map((_, i) =>
                <span key={i} className={`diff-dot ${i < sc.difficulty ? "on" : ""}`}></span>
                )}
                <span style={{ fontFamily: "var(--mono)", fontSize: 10, marginLeft: 6, color: "var(--ink-3)" }}>Dificultate</span>
              </div>
              <h3 className="scenario-title">{sc.title}</h3>
              <div className="scenario-sub">{sc.subtitle}</div>
              <p className="scenario-blurb">{sc.blurb}</p>
              <div className="scenario-stats">
                <div><strong>{(sc.initialBudget / 1000).toLocaleString("ro-RO")}K</strong><span>buget RON</span></div>
                <div><strong>{sc.initialDays}</strong><span>zile</span></div>
                <div><strong>{sc.teamSize}</strong><span>echipă</span></div>
                <div><strong>{sc.events.length}</strong><span>decizii</span></div>
              </div>
              <button className="btn primary scenario-cta" onClick={() => start(sc.id)}>
                {isCurrent ? "↻ Restart " : "Începe "} {sc.icon}
              </button>
            </div>);

        })}
      </div>

      {/* Team Simulation Card */}
      <div style={{ marginTop: 28, padding: "22px 24px", background: "linear-gradient(135deg, var(--bg-card) 0%, rgba(20,184,166,0.06) 100%)", border: "2px solid rgba(20,184,166,0.25)", borderRadius: 14, display: "grid", gridTemplateColumns: "1fr auto", gap: 24, alignItems: "center" }}>
        <div>
          <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 6 }}>
            <span style={{ fontSize: 22 }}>⬢</span>
            <span className="eyebrow" style={{ color: "teal" }}>Nou — Mod Echipă</span>
          </div>
          <div style={{ fontFamily: "var(--display)", fontSize: 20, fontWeight: 600, marginBottom: 6 }}>Simulare în echipă (2-4 jucători)</div>
          <p style={{ margin: 0, fontSize: 14, color: "var(--ink-2)", lineHeight: 1.55 }}>
            Fiecare jucător ia un rol diferit (PM, Tech Lead, Financial Controller, Risk Manager). Deciziile se iau pe rând — coordonarea face diferența. Sinergii și conflicte între roluri.
          </p>
          {state.m3team?.finished && state.m3team?.teamScore !== null && (
            <div style={{ marginTop: 8, fontSize: 13, color: "var(--muted)" }}>
              Ultimul scor de echipă: <strong>{state.m3team.teamScore}/100</strong> · Coordonare: {state.m3team.coordinationScore}%
            </div>
          )}
        </div>
        <button className="btn primary" onClick={() => go("m3-team-setup")}>
          {state.m3team?.finished ? "Joacă din nou →" : "Configurează echipa →"}
        </button>
      </div>

      <div style={{ marginTop: 28, padding: "20px 22px", background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 14 }}>
        <div className="eyebrow" style={{ marginBottom: 8 }}>Cum se joacă</div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14, fontSize: 13, color: "var(--ink-2)" }}>
          <div>
            <div style={{ fontFamily: "var(--display)", fontSize: 22, fontWeight: 700, color: "var(--accent)", marginBottom: 4 }}>01</div>
            <strong>Alegi scenariu</strong> și primești context: buget, durată, echipă.
          </div>
          <div>
            <div style={{ fontFamily: "var(--display)", fontSize: 22, fontWeight: 700, color: "var(--accent)", marginBottom: 4 }}>02</div>
            <strong>8 decizii</strong> apar pe parcurs — fiecare cu 3 opțiuni distincte.
          </div>
          <div>
            <div style={{ fontFamily: "var(--display)", fontSize: 22, fontWeight: 700, color: "var(--accent)", marginBottom: 4 }}>03</div>
            <strong>Fiecare alegere</strong> mută 4 indicatori: buget, zile, moral, calitate.
          </div>
          <div>
            <div style={{ fontFamily: "var(--display)", fontSize: 22, fontWeight: 700, color: "var(--accent)", marginBottom: 4 }}>04</div>
            <strong>Scor final + raport AI</strong> îți explică unde ai excelat.
          </div>
        </div>
      </div>
    </div>);

}

function StatBar({ label, value, max, color, prefix, suffix, danger, inverse }) {
  const pct = Math.max(0, Math.min(100, value / max * 100));
  const isLow = inverse ? value > max * 0.8 : value < max * 0.4;
  return (
    <div className={`stat-bar ${danger || isLow ? "danger" : ""}`}>
      <div className="stat-bar-head">
        <span className="stat-bar-label">{label}</span>
        <span className="stat-bar-value">
          {prefix}{typeof value === "number" ? value.toLocaleString("ro-RO") : value}{suffix}
        </span>
      </div>
      <div className="stat-bar-track">
        <div className={`stat-bar-fill stat-${color}`} style={{ width: `${pct}%` }}></div>
      </div>
    </div>);

}

function SimulatorSection({ state, update, go }) {
  const sim = state.m3;
  const scenario = SCENARIOS.find((s) => s.id === sim?.scenarioId);

  if (!scenario || !sim) {
    return (
      <div className="main-head">
        <h1 className="section-title">Niciun scenariu selectat</h1>
        <p>Mergi la <a onClick={() => go("m3-overview")} style={{ cursor: "pointer", color: "var(--accent)" }}>prezentare M3</a> și alege un scenariu.</p>
      </div>);

  }

  if (sim.finished) {
    React.useEffect(() => {go("m3-report");}, []);
    return null;
  }

  const event = scenario.events[sim.state.eventIdx];
  const [selectedChoice, setSelectedChoice] = React.useState(null);
  const [showFeedback, setShowFeedback] = React.useState(false);

  React.useEffect(() => {
    setSelectedChoice(null);
    setShowFeedback(false);
  }, [sim.state.eventIdx]);

  const handleChoice = (choiceIdx) => {
    if (showFeedback) return;
    setSelectedChoice(choiceIdx);
    setShowFeedback(true);
  };

  const proceedToNext = () => {
    const choice = event.choices[selectedChoice];
    const effects = choice.effects;
    const newBudgetSpent = sim.state.budgetSpent + (effects.budget < 0 ? -effects.budget : 0);
    const newBudget = sim.state.budget + effects.budget;
    const newDays = sim.state.days + (effects.days || 0);
    const newMorale = Math.max(0, Math.min(100, sim.state.morale + (effects.morale || 0)));
    const newQuality = Math.max(0, Math.min(100, sim.state.quality + (effects.quality || 0)));
    const newIdx = sim.state.eventIdx + 1;
    const isLastEvent = newIdx >= scenario.events.length;

    const newHistory = [...sim.state.history, {
      eventId: event.id, eventTitle: event.title, choiceIdx: selectedChoice, choiceLabel: choice.label,
      effects, feedback: choice.feedback,
      stateAfter: { budget: newBudget, budgetSpent: newBudgetSpent, days: newDays, morale: newMorale, quality: newQuality }
    }];

    if (isLastEvent) {
      // Calculate final score
      const budgetScore = Math.max(0, newBudget / scenario.initialBudget * 100); // % remaining
      const timeScore = Math.max(0, (scenario.initialDays - newDays) / scenario.initialDays * 100);
      const finalScore = Math.round(
        budgetScore * 0.25 + timeScore * 0.25 + newMorale * 0.25 + newQuality * 0.25
      );

      const finishedAt = new Date().toISOString();
      const finalState = {
        budget: newBudget, budgetSpent: newBudgetSpent,
        days: newDays, morale: newMorale, quality: newQuality
      };

      update((s) => ({
        ...s,
        m3: {
          ...s.m3,
          state: {
            ...s.m3.state,
            eventIdx: newIdx,
            ...finalState,
            history: newHistory
          },
          finished: true,
          finalScore
        }
      }));

      // Persist the completed run to Supabase
      if (window.Storage?.recordSimRun) {
        window.Storage.recordSimRun({
          scenarioId: scenario.id,
          finalState,
          history: newHistory,
          finalScore,
          aiReport: null,  // populated later when AI report is generated
          startedAt: sim.state.startedAt || finishedAt,
          finishedAt
        }).catch(() => {});
      }

      go("m3-report");
    } else {
      update((s) => ({
        ...s,
        m3: {
          ...s.m3,
          state: {
            ...s.m3.state,
            eventIdx: newIdx,
            budget: newBudget, budgetSpent: newBudgetSpent,
            days: newDays, morale: newMorale, quality: newQuality,
            history: newHistory
          }
        }
      }));
    }
  };

  const exitToOverview = () => {
    if (confirm("Sigur abandonezi simularea? Progresul va fi pierdut.")) {
      update((s) => ({ ...s, m3: { ...s.m3, scenarioId: null, finished: false, finalScore: null } }));
      go("m3-overview");
    }
  };

  const s = sim.state;
  const budgetPct = s.budget / scenario.initialBudget * 100;
  const daysLeft = scenario.initialDays - s.days;
  const daysPct = daysLeft / scenario.initialDays * 100;

  return (
    <div>
      <div className="main-head" style={{ paddingBottom: 16, marginBottom: 20 }}>
        <div className="crumb">M3 · {scenario.title}</div>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 16 }}>
          <h1 className="section-title" style={{ fontSize: 28, margin: "4px 0" }}>{scenario.title}</h1>
          <button className="btn ghost small" onClick={exitToOverview}>← Abandonează</button>
        </div>
        <div className="section-meta">
          <span><Pill kind="info">Eveniment {s.eventIdx + 1} / {scenario.events.length}</Pill></span>
        </div>
      </div>

      {/* KPI Dashboard */}
      <div className="sim-dashboard">
        <StatBar label="Buget rămas" value={s.budget} max={scenario.initialBudget} color="indigo" suffix=" RON" danger={budgetPct < 20} />
        <StatBar label="Zile rămase" value={daysLeft} max={scenario.initialDays} color="coral" suffix=" zile" danger={daysLeft < 30} />
        <StatBar label="Moral echipă" value={s.morale} max={100} color="good" suffix=" / 100" danger={s.morale < 40} />
        <StatBar label="Calitate" value={s.quality} max={100} color="purple" suffix=" / 100" danger={s.quality < 40} />
      </div>

      {/* Event */}
      <div className="sim-event">
        <div className="sim-event-head">
          <div className="sim-event-day">Ziua {s.days}</div>
          <h2 className="sim-event-title">{event.title}</h2>
        </div>
        <p className="sim-event-context">{event.context}</p>

        <div className="sim-choices">
          {event.choices.map((choice, i) => {
            const isSelected = selectedChoice === i;
            return (
              <button key={i}
              className={`sim-choice ${isSelected ? "selected" : ""} ${showFeedback && !isSelected ? "dimmed" : ""}`}
              onClick={() => handleChoice(i)}
              disabled={showFeedback}>
                <div className="sim-choice-letter">{String.fromCharCode(65 + i)}</div>
                <div className="sim-choice-body">
                  <div className="sim-choice-label">{choice.label}</div>
                  <div className="sim-choice-blurb">{choice.blurb}</div>
                  {showFeedback && isSelected &&
                  <div className="sim-choice-effects">
                      {choice.effects.budget !== 0 && <span className={`fx ${choice.effects.budget < 0 ? "bad" : "good"}`}>{choice.effects.budget > 0 ? "+" : ""}{choice.effects.budget.toLocaleString("ro-RO")} RON</span>}
                      {choice.effects.days !== 0 && <span className={`fx ${choice.effects.days > 0 ? "bad" : "good"}`}>{choice.effects.days > 0 ? "+" : ""}{choice.effects.days} zile</span>}
                      {choice.effects.morale !== 0 && <span className={`fx ${choice.effects.morale < 0 ? "bad" : "good"}`}>{choice.effects.morale > 0 ? "+" : ""}{choice.effects.morale} moral</span>}
                      {choice.effects.quality !== 0 && <span className={`fx ${choice.effects.quality < 0 ? "bad" : "good"}`}>{choice.effects.quality > 0 ? "+" : ""}{choice.effects.quality} calitate</span>}
                    </div>
                  }
                </div>
              </button>);

          })}
        </div>

        {showFeedback && selectedChoice !== null &&
        <div className="sim-feedback">
            <div className="sim-feedback-label">Feedback PM coach</div>
            <p className="sim-feedback-text">{event.choices[selectedChoice].feedback}</p>
            <button className="btn primary" onClick={proceedToNext}>
              {sim.state.eventIdx + 1 >= scenario.events.length ? "Finalizează simularea →" : "Continuă →"}
            </button>
          </div>
        }
      </div>

      {/* History sidebar */}
      {s.history.length > 0 &&
      <details className="sim-history">
          <summary>Istoric decizii ({s.history.length})</summary>
          <div className="sim-history-list">
            {s.history.map((h, i) =>
          <div key={i} className="sim-history-item">
                <div className="sim-history-num">{String(i + 1).padStart(2, "0")}</div>
                <div>
                  <div className="sim-history-title">{h.eventTitle}</div>
                  <div className="sim-history-choice">→ {h.choiceLabel}</div>
                </div>
              </div>
          )}
          </div>
        </details>
      }
    </div>);

}

function ReportSection({ state, update, go }) {
  const sim = state.m3;
  const scenario = SCENARIOS.find((s) => s.id === sim?.scenarioId);

  if (!sim || !sim.finished || !scenario) {
    return (
      <div>
        <div className="main-head">
          <h1 className="section-title">Niciun raport disponibil</h1>
        </div>
        <button className="btn" onClick={() => go("m3-overview")}>Înapoi la simulator</button>
      </div>);

  }

  const score = sim.finalScore;
  const grade = score >= 85 ? "A · Excelent" : score >= 70 ? "B · Bun" : score >= 55 ? "C · Acceptabil" : score >= 40 ? "D · Slab" : "F · Eșec";
  const gradeColor = score >= 70 ? "good" : score >= 55 ? "info" : score >= 40 ? "warn" : "bad";

  const [aiLoading, setAiLoading] = React.useState(false);
  const [aiError, setAiError] = React.useState(null);

  const generateAIReport = async () => {
    // Guard: AI tutor not yet enabled (no Claude API integration in Phase 0)
    if (!window.claude || typeof window.claude.complete !== "function") {
      setAiError("Raportul AI nu e disponibil încă. Această funcție va fi activată într-o versiune viitoare.");
      return;
    }
    setAiLoading(true);
    setAiError(null);
    try {
      const historySummary = sim.state.history.map((h, i) =>
      `${i + 1}. "${h.eventTitle}" — am ales: "${h.choiceLabel}". Coach: ${h.feedback}`
      ).join("\n");

      const prompt = `Ești un coach de management de proiect. Tocmai am terminat o simulare în care am condus proiectul "${scenario.title}" (${scenario.subtitle}). Rezultate finale:
- Scor: ${score}/100 (${grade})
- Buget rămas: ${sim.state.budget.toLocaleString("ro-RO")} RON din ${scenario.initialBudget.toLocaleString("ro-RO")} RON
- Zile folosite: ${sim.state.days} din ${scenario.initialDays}
- Moral echipă: ${sim.state.morale}/100
- Calitate livrabil: ${sim.state.quality}/100

Deciziile mele:
${historySummary}

Scrie un raport scurt (3-4 paragrafe, max 250 cuvinte) în limba română, ca un coach prietenos dar direct:
1. O analiză a punctelor mele forte (1 paragraf)
2. Cele 2 greșeli/zone unde puteam face mai bine (1 paragraf)
3. Un sfat concret pentru data viitoare (1 paragraf)
4. Un închidere motivantă (1-2 propoziții)

Stil: direct, fără jargon, ca un mentor cu experiență. Nu repeta scorul.`;

      const response = await window.claude.complete(prompt);
      update((s) => ({ ...s, m3: { ...s.m3, aiReport: response } }));
    } catch (e) {
      setAiError("Nu am putut genera raportul AI. Încearcă din nou.");
      console.error(e);
    } finally {
      setAiLoading(false);
    }
  };

  const retry = () => {
    update((s) => ({ ...s, m3: { ...s.m3, scenarioId: null, finished: false, finalScore: null, aiReport: null } }));
    go("m3-overview");
  };

  const budgetPct = Math.round(sim.state.budget / scenario.initialBudget * 100);
  const timePct = Math.round((scenario.initialDays - sim.state.days) / scenario.initialDays * 100);

  return (
    <div>
      <div className="main-head">
        <div className="crumb">Raport · {scenario.title}</div>
        <h1 className="section-title">Simulare finalizată</h1>
        <p className="section-lede">
          Iată rezultatul deciziilor tale. Scorul e calculat pe 4 dimensiuni: încadrare în buget, în timp, moralul echipei, calitatea livrabilului.
        </p>
      </div>

      <div className={`report-header report-${gradeColor}`}>
        <div className="report-score">
          <div className="report-score-num">{score}</div>
          <div className="report-score-max">/ 100</div>
        </div>
        <div className="report-grade">
          <div className="report-grade-label">Nota</div>
          <div className="report-grade-val">{grade}</div>
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          <button className="btn ghost" onClick={retry}>↻ Joacă din nou</button>
        </div>
      </div>

      <div className="report-stats">
        <div className="report-stat">
          <div className="report-stat-label">Buget rămas</div>
          <div className="report-stat-val">{budgetPct}%</div>
          <div className="report-stat-sub">{sim.state.budget.toLocaleString("ro-RO")} RON</div>
        </div>
        <div className="report-stat">
          <div className="report-stat-label">Timp economisit</div>
          <div className="report-stat-val">{timePct}%</div>
          <div className="report-stat-sub">{sim.state.days} / {scenario.initialDays} zile</div>
        </div>
        <div className="report-stat">
          <div className="report-stat-label">Moral echipă</div>
          <div className="report-stat-val">{sim.state.morale}</div>
          <div className="report-stat-sub">din 100</div>
        </div>
        <div className="report-stat">
          <div className="report-stat-label">Calitate</div>
          <div className="report-stat-val">{sim.state.quality}</div>
          <div className="report-stat-sub">din 100</div>
        </div>
      </div>

      {window.APP_CONFIG?.features?.aiTutor && <Card title="Raport AI personalizat" sub="POWERED BY CLAUDE"
        action={
          <div style={{ display: "flex", gap: 6 }}>
            {sim.aiReport && !aiLoading && (
              <>
                <button className="btn icon" title="Copiază raport" onClick={() => { navigator.clipboard?.writeText(sim.aiReport); }}>
                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
                </button>
                <button className="btn ghost small" onClick={generateAIReport}>↻ Regenerează</button>
              </>
            )}
            {!sim.aiReport && !aiLoading && (
              <button className="btn primary small" onClick={generateAIReport}>Generează raport →</button>
            )}
          </div>
        }>
        {!sim.aiReport && !aiLoading && !aiError &&
        <div style={{ padding: "24px 0", textAlign: "center", color: "var(--ink-3)" }}>
          <div style={{ fontSize: 32, marginBottom: 10 }}>✨</div>
          <p style={{ margin: "0 0 6px", fontWeight: 600, color: "var(--ink-2)" }}>Apasă „Generează raport” pentru analiză personalizată.</p>
          <p className="muted" style={{ fontSize: 12, margin: 0 }}>Claude analizează alegerile tale, identifică tipare și propune lecții personalizate.</p>
        </div>
        }
        {aiLoading &&
        <div className="ai-loading">
          <div className="ai-spinner"></div>
          <p>Analizez deciziile tale...</p>
        </div>
        }
        {aiError &&
        <div className="banner-warn">{aiError}</div>
        }
        {sim.aiReport &&
        <div className="ai-report" data-comment-anchor="99dd011cb9-div-467-11">
          {renderMarkdownLight(sim.aiReport)}
        </div>
        }
      </Card>}

      <Card title="Istoric decizii" sub={`${sim.state.history.length} decizii luate`}>
        <div className="report-history">
          {sim.state.history.map((h, i) =>
          <div key={i} className="report-history-item">
              <div className="report-history-num">{String(i + 1).padStart(2, "0")}</div>
              <div className="report-history-body">
                <div className="report-history-event">{h.eventTitle}</div>
                <div className="report-history-choice">→ {h.choiceLabel}</div>
                <div className="report-history-feedback">{h.feedback}</div>
                <div className="report-history-fx">
                  {h.effects.budget !== 0 && <span className={`fx ${h.effects.budget < 0 ? "bad" : "good"}`}>{h.effects.budget > 0 ? "+" : ""}{h.effects.budget.toLocaleString("ro-RO")} RON</span>}
                  {h.effects.days !== 0 && <span className={`fx ${h.effects.days > 0 ? "bad" : "good"}`}>{h.effects.days > 0 ? "+" : ""}{h.effects.days}z</span>}
                  {h.effects.morale !== 0 && <span className={`fx ${h.effects.morale < 0 ? "bad" : "good"}`}>{h.effects.morale > 0 ? "+" : ""}{h.effects.morale} moral</span>}
                  {h.effects.quality !== 0 && <span className={`fx ${h.effects.quality < 0 ? "bad" : "good"}`}>{h.effects.quality > 0 ? "+" : ""}{h.effects.quality} cal</span>}
                </div>
              </div>
            </div>
          )}
        </div>
      </Card>

      <div className="foot-actions">
        <button className="btn ghost" onClick={() => go("m3-overview")}>← Alte scenarii</button>
        <button className="btn primary" onClick={() => go("m4")}>Mergi la Modul 4 →</button>
      </div>
    </div>);

}

// === Module 3 — Team Simulation (pass-and-play, role-based) ===

const TEAM_ROLES = [
  { id: "pm", name: "Project Manager", short: "PM", icon: "◆", desc: "Decizii de scope, timeline și coordonare generală." },
  { id: "tech", name: "Technical Lead", short: "Tech", icon: "⬡", desc: "Decizii tehnice, calitate și arhitectură." },
  { id: "finance", name: "Financial Controller", short: "Fin", icon: "◈", desc: "Decizii de buget, achiziții și resurse financiare." },
  { id: "risk", name: "Risk Manager", short: "Risk", icon: "▲", desc: "Identificare riscuri, mitigare și planuri de contingență." }
];

const TEAM_SCENARIOS = [
  {
    id: "team-digital",
    title: "Transformare Digitală — Mod Echipă",
    subtitle: "Companie medie · modernizare infrastructură IT",
    blurb: "O companie cu 200 de angajați vrea să-și digitalizeze procesele interne: ERP nou, migrare cloud, training angajați. Buget 400.000 RON, 9 luni, echipă de 8. Fiecare rol ia decizii din perspectiva sa — coordonarea face diferența.",
    color: "teal",
    icon: "⬢",
    difficulty: 4,
    initialBudget: 400000,
    initialDays: 270,
    initialMorale: 70,
    initialQuality: 70,
    teamSize: 8,
    events: [
      {
        id: "t-kickoff",
        day: 0,
        title: "Kick-off și aliniere echipă",
        context: "Prima săptămână. Sponsorul cere rezultate vizibile în 60 de zile. Echipa e nouă — unii nu s-au mai întâlnit. Departamentul IT intern e sceptic față de schimbare.",
        teamChoices: {
          pm: [
            { label: "Workshop intensiv de 3 zile cu toți stakeholderii", effects: { budget: -15000, days: 5, morale: 12, quality: 10 }, feedback: "Investiție excelentă — aliniere completă din start. Toți știu ce au de făcut." },
            { label: "Ședință de kick-off de 2 ore + plan în email", effects: { budget: 0, days: 1, morale: -2, quality: -5 }, feedback: "Rapid, dar superficial. Oamenii vor avea întrebări fără răspuns în săptămânile următoare." },
            { label: "Începem direct cu execuția, ajustăm pe parcurs", effects: { budget: 0, days: 0, morale: -8, quality: -12 }, feedback: "Risc major. Fără aliniere, fiecare interpretează scope-ul diferit." }
          ],
          tech: [
            { label: "Audit tehnic complet al sistemelor existente (2 săpt.)", effects: { budget: -20000, days: 10, morale: 3, quality: 15 }, feedback: "Audit excelent — cunoști exact ce ai. Migrarea va fi mult mai sigură." },
            { label: "Evaluare rapidă bazată pe documentația existentă", effects: { budget: -5000, days: 3, morale: 0, quality: 2 }, feedback: "Documentația e incompletă. Vei descoperi surprize în faza de migrare." },
            { label: "Presupunem că sistemele sunt standard, mergem direct", effects: { budget: 0, days: 0, morale: -3, quality: -10 }, feedback: "Asumpții periculoase. Fiecare sistem legacy are particularități ascunse." }
          ],
          finance: [
            { label: "Buget detaliat pe work packages + rezervă 10%", effects: { budget: -8000, days: 3, morale: 5, quality: 5 }, feedback: "Planificare financiară solidă. Echipa are claritate pe ce poate cheltui." },
            { label: "Buget estimativ pe module mari", effects: { budget: -2000, days: 1, morale: 0, quality: 0 }, feedback: "Funcționează pe termen scurt, dar redistribuirile vor crea tensiuni." },
            { label: "Stabilim pe parcurs, în funcție de nevoi", effects: { budget: 0, days: 0, morale: -5, quality: -3 }, feedback: "Fără buget clar, fiecare cerere devine o negociere. Moral scade." }
          ],
          risk: [
            { label: "Workshop de identificare riscuri + registru complet", effects: { budget: -8000, days: 4, morale: 5, quality: 8 }, feedback: "Registrul de riscuri e prima linie de apărare. Echipa se simte pregătită." },
            { label: "Listez top 5 riscuri evidente și monitorizez", effects: { budget: -2000, days: 1, morale: 2, quality: 3 }, feedback: "Top 5 e un start, dar riscurile mai subtile (rezistența la schimbare, dependențe tehnice) rămân neacoperite." },
            { label: "Riscurile le tratăm când apar", effects: { budget: 0, days: 0, morale: -4, quality: -8 }, feedback: "Abordare reactivă. Când riscul se materializează, costul de rezolvare e de 5-10× mai mare." }
          ]
        },
        synergy: [
          { match: { pm: 0, tech: 0 }, bonus: { morale: 5, quality: 3 }, reason: "PM și Tech au investit amândoi în pregătire — sinergie excelentă." },
          { match: { pm: 2, risk: 0 }, penalty: { morale: -6 }, reason: "PM sare peste planificare, dar Risk Manager cere proces — tensiune în echipă." },
          { match: { finance: 0, pm: 0 }, bonus: { morale: 3 }, reason: "Buget detaliat + workshop = echipa știe exact resursele disponibile." },
          { match: { pm: 0, tech: 0, finance: 0, risk: 0 }, bonus: { morale: 8, quality: 5 }, reason: "Aliniere totală! Toți au ales investiția în pregătire." }
        ]
      },
      {
        id: "t-vendor",
        day: 30,
        title: "Selecția furnizorului ERP",
        context: "3 furnizori în shortlist. Cel mai ieftin are recenzii mixte. Cel mai scump are reputație excelentă. Al treilea e mid-range dar cere personalizare semnificativă. Deadline: decizie în 5 zile.",
        teamChoices: {
          pm: [
            { label: "Organizez demo-uri cu toți 3 + evaluare structurată", effects: { budget: -5000, days: 8, morale: 5, quality: 8 }, feedback: "Proces transparent. Echipa și stakeholderii au încredere în decizie." },
            { label: "Aleg furnizorul recomandat de sponsor (cel scump)", effects: { budget: -30000, days: 2, morale: -3, quality: 5 }, feedback: "Decizie politică, nu bazată pe merit. Echipa tech e frustrată că nu a fost consultată." },
            { label: "Mergem pe cel mai ieftin — economisim buget", effects: { budget: 15000, days: 3, morale: -5, quality: -10 }, feedback: "Ieftin acum, scump mai târziu. Suportul tehnic slab va genera re-work." }
          ],
          tech: [
            { label: "PoC (proof of concept) tehnic cu top 2 furnizori", effects: { budget: -12000, days: 10, morale: 5, quality: 12 }, feedback: "PoC-ul revelă probleme ascunse. Decizia e informată tehnic." },
            { label: "Evaluare pe baza specificațiilor tehnice", effects: { budget: -3000, days: 4, morale: 2, quality: 5 }, feedback: "Analiza pe hârtie e utilă, dar nu înlocuiește testarea reală." },
            { label: "Accept orice furnizor decide PM-ul", effects: { budget: 0, days: 0, morale: -5, quality: -8 }, feedback: "Tech Lead-ul trebuie să aibă voce în decizii tehnice. Abdicarea creează probleme." }
          ],
          finance: [
            { label: "Analiză TCO (Total Cost of Ownership) pe 3 ani", effects: { budget: -5000, days: 5, morale: 3, quality: 5 }, feedback: "TCO arată costul real: licențe + mentenanță + training + upgrade-uri. Decizie înțeleaptă." },
            { label: "Compar doar prețul licenței inițiale", effects: { budget: 0, days: 1, morale: 0, quality: -3 }, feedback: "Prețul inițial e doar vârful icebergului. Costurile ascunse vor apărea." },
            { label: "Negociez agresiv cu furnizorul cel mai ieftin", effects: { budget: 10000, days: 3, morale: -3, quality: -5 }, feedback: "Negociere agresivă poate deteriora relația cu furnizorul. Suportul post-vânzare va fi minim." }
          ],
          risk: [
            { label: "Due diligence: referințe, SLA-uri, plan de exit", effects: { budget: -5000, days: 5, morale: 4, quality: 8 }, feedback: "Due diligence protejează proiectul. SLA clar = așteptări gestionate." },
            { label: "Verific doar referințele de la furnizor", effects: { budget: -1000, days: 2, morale: 0, quality: 2 }, feedback: "Referințele date de furnizor sunt mereu pozitive. Caută referințe independente." },
            { label: "Furnizorul mare e sigur, nu trebuie verificat", effects: { budget: 0, days: 0, morale: -2, quality: -5 }, feedback: "Reputația nu garantează potrivirea cu nevoile tale specifice." }
          ]
        },
        synergy: [
          { match: { pm: 0, tech: 0 }, bonus: { quality: 5 }, reason: "Demo-uri + PoC tehnic = decizie bazată pe fapte, nu pe presupuneri." },
          { match: { finance: 0, risk: 0 }, bonus: { morale: 3, quality: 3 }, reason: "TCO + due diligence = imagine completă a costurilor și riscurilor." },
          { match: { pm: 2, tech: 2 }, penalty: { quality: -8, morale: -5 }, reason: "PM și Tech au ales varianta low-effort — nimeni nu a evaluat serios." }
        ]
      },
      {
        id: "t-resistance",
        day: 60,
        title: "Rezistența la schimbare",
        context: "Departamentul de contabilitate refuză noul sistem. „Funcționează ce avem.” Managerii de departament cer excepții. 30% din angajați n-au completat training-ul obligatoriu. Sponsorul întreabă de ce progresul e lent.",
        teamChoices: {
          pm: [
            { label: "Sesiuni individuale cu managerii reticenți + plan de change management", effects: { budget: -10000, days: 8, morale: 10, quality: 5 }, feedback: "Ascultarea activă transformă adversarii în aliați. Change management e esențial." },
            { label: "Escalez la sponsor — să dea ordin de conformare", effects: { budget: 0, days: 2, morale: -10, quality: 0 }, feedback: "Ordinul de sus rezolvă pe termen scurt, dar distruge moralul pe termen lung." },
            { label: "Ignor rezistența — vor accepta când văd rezultate", effects: { budget: 0, days: 0, morale: -12, quality: -8 }, feedback: "Rezistența ignorată se transformă în sabotaj pasiv. Proiectul va suferi." }
          ],
          tech: [
            { label: "Mediu de test pentru departamentul reticent + support dedicat", effects: { budget: -8000, days: 5, morale: 8, quality: 8 }, feedback: "Hands-on experience reduce frica de necunoscut. Support dedicat arată respect." },
            { label: "Documentație detaliată + FAQ", effects: { budget: -3000, days: 3, morale: 2, quality: 3 }, feedback: "Documentația ajută, dar nu înlocuiește suportul uman în momente de frustrare." },
            { label: "Forțăm migrarea — nu acceptăm excepții", effects: { budget: 0, days: -5, morale: -15, quality: -5 }, feedback: "Big bang fără pregătire = dezastru. Productivitatea scade dramatic în primele săptămâni." }
          ],
          finance: [
            { label: "Buget pentru incentive: bonusuri early adopters", effects: { budget: -15000, days: 0, morale: 12, quality: 3 }, feedback: "Incentivele financiare accelerează adopția. Early adopters devin ambasadori." },
            { label: "Realoc buget din training spre implementare", effects: { budget: 5000, days: -3, morale: -8, quality: -5 }, feedback: "Economisești acum, dar angajații nepregătiți vor face greșeli costisitoare." },
            { label: "Nicio ajustare bugetară — rezistența nu e o problemă financiară", effects: { budget: 0, days: 0, morale: -3, quality: -2 }, feedback: "Rezistența la schimbare ARE cost financiar: productivitate scăzută, re-work, termene depășite." }
          ],
          risk: [
            { label: "Plan de escalare gradual: awareness → training → mentoring → go-live", effects: { budget: -8000, days: 6, morale: 10, quality: 6 }, feedback: "Abordarea graduală respectă ritmul oamenilor. Adoptarea e organică, nu forțată." },
            { label: "Identific „campionii” din fiecare departament ca agenți de schimbare", effects: { budget: -3000, days: 3, morale: 8, quality: 5 }, feedback: "Peer influence e puternică. Campionii interni sunt mai credibili decât consultanții externi." },
            { label: "Risc acceptat — merg mai departe cu procentul care adoptă", effects: { budget: 0, days: 0, morale: -8, quality: -6 }, feedback: "30% non-adopție = 30% din organizație lucrează ineficient. Costul e enorm pe termen lung." }
          ]
        },
        synergy: [
          { match: { pm: 0, tech: 0 }, bonus: { morale: 8, quality: 3 }, reason: "Change management + suport tehnic dedicat = tranziție lină." },
          { match: { pm: 0, risk: 1 }, bonus: { morale: 5 }, reason: "PM ascultă + campioni interni = schimbarea vine din interior." },
          { match: { pm: 1, tech: 2 }, penalty: { morale: -10 }, reason: "Ordine de sus + forțare tehnică = revoltă în echipă." },
          { match: { finance: 0, pm: 0 }, bonus: { morale: 5 }, reason: "Incentive + comunicare = oamenii se simt apreciați și înțeleși." }
        ]
      },
      {
        id: "t-scope-change",
        day: 90,
        title: "Cerere de schimbare majoră",
        context: "Directorul comercial cere integrarea cu platforma e-commerce — nu era în scope. Estimare: +45.000 RON, +30 zile. Sponsorul e tentat să accepte. Echipa e deja la 70% capacitate.",
        teamChoices: {
          pm: [
            { label: "Change request formal: impact analysis, CCB approval", effects: { budget: -5000, days: 5, morale: 5, quality: 5 }, feedback: "Proces corect. Change control board evaluează transparent. Decizia e informată." },
            { label: "Accept cererea — sponsorul vrea, fac", effects: { budget: -45000, days: 30, morale: -8, quality: -5 }, feedback: "Scope creep clasic. Echipa e supraîncărcată, calitatea scade, moralul la pământ." },
            { label: "Refuz categoric — nu e în contract", effects: { budget: 0, days: 0, morale: -5, quality: 0 }, feedback: "Refuzul fără alternativă deteriorează relația cu sponsorul. Oferă opțiuni, nu ziduri." }
          ],
          tech: [
            { label: "Analiza de fezabilitate: ce se poate face cu arhitectura curentă", effects: { budget: -5000, days: 5, morale: 3, quality: 5 }, feedback: "Analiza arată ce e posibil fără restructurare majoră. Bază solidă pentru decizie." },
            { label: "Propun API minimal — integrare de bază, extensibilă ulterior", effects: { budget: -15000, days: 10, morale: 2, quality: 3 }, feedback: "Soluție pragmatică: satisface nevoia de bază fără a compromite proiectul principal." },
            { label: "E imposibil acum — poate în faza 2", effects: { budget: 0, days: 0, morale: -3, quality: 0 }, feedback: "„Imposibil” fără analiză sună ca rezistență la schimbare. Argumentează tehnic." }
          ],
          finance: [
            { label: "Analiză cost-beneficiu: ROI al integrării e-commerce", effects: { budget: -3000, days: 3, morale: 3, quality: 3 }, feedback: "CBA arată dacă investiția se justifică. Decizia trece de la „vrem” la „merită”." },
            { label: "Propun buget separat (fază 2) pentru e-commerce", effects: { budget: -2000, days: 2, morale: 5, quality: 3 }, feedback: "Excelent: protejezi bugetul curent și oferi perspectivă pentru investiție viitoare." },
            { label: "Absorb costul din contingency reserve", effects: { budget: -45000, days: 0, morale: -3, quality: -5 }, feedback: "Contingency e pentru riscuri, nu pentru scope creep. Acum n-ai rezervă pentru probleme reale." }
          ],
          risk: [
            { label: "Evaluare impact: ce riscuri noi aduce integrarea?", effects: { budget: -3000, days: 3, morale: 3, quality: 5 }, feedback: "Noi dependențe = noi riscuri. Evaluarea e esențială înainte de decizie." },
            { label: "Condiționez: acceptăm doar cu extensie de deadline", effects: { budget: -2000, days: 2, morale: 5, quality: 3 }, feedback: "Negociere rațională. Scope se extinde? Timp trebuie să se extindă proporțional." },
            { label: "Nu e treaba mea — PM-ul decide", effects: { budget: 0, days: 0, morale: -5, quality: -3 }, feedback: "Risk Manager-ul TREBUIE să se implice în decizii de scope. Fiecare schimbare aduce riscuri noi." }
          ]
        },
        synergy: [
          { match: { pm: 0, finance: 1 }, bonus: { morale: 5, quality: 3 }, reason: "Change request formal + buget separat = scope protejat, relație menținută." },
          { match: { pm: 0, tech: 0, risk: 0 }, bonus: { quality: 5 }, reason: "Proces complet: change request + fezabilitate + evaluare riscuri." },
          { match: { pm: 1, finance: 2 }, penalty: { morale: -8, quality: -5 }, reason: "Acceptare fără proces + contingency consumat = proiect vulnerabil." }
        ]
      },
      {
        id: "t-crisis",
        day: 120,
        title: "Criză de securitate",
        context: "Audit de securitate descoperă vulnerabilități critice în modulul de plăți al ERP-ului. Furnizorul spune că patch-ul vine în 3 săptămâni. Directorul IT cere oprirea migrării până la rezolvare. Sponsorul cere soluție în 48 de ore.",
        teamChoices: {
          pm: [
            { label: "War room: echipă dedicată criză + comunicare transparentă cu sponsorul", effects: { budget: -10000, days: 5, morale: 5, quality: 8 }, feedback: "Transparența în criză construiește încredere. War room accelerează rezolvarea." },
            { label: "Minimizez problema în fața sponsorului, rezolv discret", effects: { budget: -5000, days: 3, morale: -5, quality: -3 }, feedback: "Dacă iese la iveală că ai ascuns o problemă de securitate, credibilitatea e zero." },
            { label: "Opresc totul până vine patch-ul de la furnizor", effects: { budget: -20000, days: 21, morale: -10, quality: 5 }, feedback: "3 săptămâni de pauză e o eternitate. Echipa se demobilizează. Costul de oportunitate e enorm." }
          ],
          tech: [
            { label: "Workaround tehnic: izolare modul + firewall dedicat până la patch", effects: { budget: -12000, days: 3, morale: 5, quality: 10 }, feedback: "Soluție elegantă: protejezi sistemul fără să oprești proiectul. Excelent tehnic." },
            { label: "Implementez patch-ul de la furnizor pe mediul de test", effects: { budget: -5000, days: 7, morale: 2, quality: 5 }, feedback: "Testare pe mediu izolat = abordare corectă, dar durează mai mult." },
            { label: "Așteptăm patch-ul oficial și continuăm cu restul", effects: { budget: 0, days: 15, morale: -8, quality: 0 }, feedback: "Inactivitate pe modulul critic blochează totul. Dependențele creează efect domino." }
          ],
          finance: [
            { label: "Buget de urgență din rezerva de contingency", effects: { budget: -20000, days: 0, morale: 5, quality: 5 }, feedback: "Exact pentru asta există contingency. Decizia rapidă de alocare permite acțiune imediată." },
            { label: "Negociez cu furnizorul: patch gratuit + SLA penalizat", effects: { budget: 5000, days: 5, morale: 3, quality: 3 }, feedback: "Negociere legitimă — furnizorul e responsabil pentru vulnerabilitate." },
            { label: "Nu aloc buget suplimentar — e problema furnizorului", effects: { budget: 0, days: 10, morale: -5, quality: -5 }, feedback: "Problema e și a ta — proiectul tău e în risc. Furnizorul rezolvă bug-ul, tu rezolvi impactul." }
          ],
          risk: [
            { label: "Activez planul de contingency + notific stakeholderii afectați", effects: { budget: -5000, days: 2, morale: 8, quality: 8 }, feedback: "Planul de contingency există exact pentru asta. Comunicare proactivă = stakeholderi liniștiți." },
            { label: "Evaluez impactul real — vulnerabilitatea e exploatabilă?", effects: { budget: -3000, days: 3, morale: 3, quality: 5 }, feedback: "Evaluarea calma a severității reale previne panica. Nu toate vulnerabilitățile sunt la fel." },
            { label: "Escalez la furnizor și aștept", effects: { budget: 0, days: 15, morale: -8, quality: -3 }, feedback: "Pasivitatea în criză e cea mai mare greșeală. Tu ești responsabil de proiect, nu furnizorul." }
          ]
        },
        synergy: [
          { match: { pm: 0, tech: 0, risk: 0 }, bonus: { morale: 8, quality: 5 }, reason: "War room + workaround tehnic + contingency activat = criză gestionată profesionist." },
          { match: { tech: 0, finance: 0 }, bonus: { quality: 5 }, reason: "Soluție tehnică + buget disponibil = execuție rapidă." },
          { match: { pm: 1, risk: 2 }, penalty: { morale: -8, quality: -5 }, reason: "PM ascunde problema, Risk Manager e pasiv = criză amplificată." }
        ]
      },
      {
        id: "t-resource",
        day: 150,
        title: "Pierderea unui membru cheie",
        context: "Senior developer-ul (cel mai experimentat din echipă) demisionează — a primit o ofertă cu 40% mai mult. Mai are 2 săptămâni de preaviz. Cunoștințele lui despre integrarea legacy nu sunt documentate.",
        teamChoices: {
          pm: [
            { label: "Knowledge transfer intensiv + recrutare urgentă", effects: { budget: -15000, days: 10, morale: -3, quality: 5 }, feedback: "2 săptămâni de transfer + recrutare rapidă. Pierzi ritm, dar păstrezi cunoștințele." },
            { label: "Redistribui sarcinile la echipa existentă", effects: { budget: 0, days: 5, morale: -10, quality: -5 }, feedback: "Echipa e deja la capacitate. Supraîncărcarea duce la burnout și greșeli." },
            { label: "Externalizez componenta legacy la un consultant", effects: { budget: -25000, days: 5, morale: 0, quality: 0 }, feedback: "Consultant extern = costisitor dar rapid. Riscul: nu cunoaște contextul." }
          ],
          tech: [
            { label: "Pair programming intensiv: transferă cunoștințele în 2 săptămâni", effects: { budget: -5000, days: 3, morale: 3, quality: 8 }, feedback: "Pair programming = cel mai eficient mod de transfer. Doi colegi preiau cunoștințele." },
            { label: "Documentare completă de la developer-ul care pleacă", effects: { budget: -3000, days: 5, morale: 0, quality: 3 }, feedback: "Documentarea ajută, dar nu captează tacit knowledge (decizii de design, workaround-uri)." },
            { label: "Vom descifra codul singuri după ce pleacă", effects: { budget: 0, days: 15, morale: -8, quality: -10 }, feedback: "Reverse engineering pe cod legacy = pierdere enormă de timp. Knowledge transfer e esențial." }
          ],
          finance: [
            { label: "Contra-ofertă salarială (retention bonus)", effects: { budget: -20000, days: 0, morale: 5, quality: 8 }, feedback: "Dacă rămâne, proiectul continuă fără perturbare. ROI excelent pe termen scurt." },
            { label: "Buget pentru recrutare + onboarding accelerat", effects: { budget: -12000, days: 8, morale: 0, quality: 0 }, feedback: "Recrutarea e necesară indiferent. Bugetul dedicat accelerează procesul." },
            { label: "Absorbim pierderea fără buget suplimentar", effects: { budget: 0, days: 0, morale: -8, quality: -8 }, feedback: "Fără investiție în înlocuire, echipa suportă povara. Burnout garantat." }
          ],
          risk: [
            { label: "Plan de succesiune: documentare + cross-training imediat", effects: { budget: -5000, days: 5, morale: 5, quality: 5 }, feedback: "Cross-training reduce single point of failure. Lecție: trebuia făcut mai devreme." },
            { label: "Identific alte dependențe pe persoane-cheie și mitighez", effects: { budget: -3000, days: 3, morale: 5, quality: 5 }, feedback: "Bus factor 1 = risc critic. Bine că extizi analiza la întreaga echipă." },
            { label: "E un risc acceptat — se întâmplă", effects: { budget: 0, days: 0, morale: -5, quality: -5 }, feedback: "Acceptarea pasivă a riscurilor materializate nu e management — e resemnare." }
          ]
        },
        synergy: [
          { match: { pm: 0, tech: 0 }, bonus: { quality: 5, morale: 3 }, reason: "Knowledge transfer + pair programming = cunoștințe distribuite." },
          { match: { finance: 0, pm: 0 }, bonus: { morale: 5 }, reason: "Contra-ofertă + KT plan = retenție + backup. Strategie completă." },
          { match: { pm: 1, tech: 2 }, penalty: { quality: -8 }, reason: "Redistribuire la echipă supraîncărcată + fără transfer = pierdere de cunoștințe." }
        ]
      },
      {
        id: "t-quality",
        day: 200,
        title: "Probleme de calitate la UAT",
        context: "User Acceptance Testing revelă 47 de bug-uri, 8 critice. Deadline-ul e în 70 zile. Userii raportează interfața „confuză”. Directorul operațional amenință că nu semnează acceptanța.",
        teamChoices: {
          pm: [
            { label: "Sprint de stabilizare: 2 săpt. dedicate exclusiv bug-fixing", effects: { budget: -10000, days: 14, morale: 5, quality: 12 }, feedback: "Focus pe calitate acum previne dezastru la go-live. Decizie matură." },
            { label: "Fix-ăm bug-urile critice, restul le lăsăm post-launch", effects: { budget: -5000, days: 5, morale: -3, quality: 3 }, feedback: "8 critice rezolvate, dar 39 de bug-uri minore irită userii zilnic." },
            { label: "Forțăm go-live-ul la timp — UAT e subiectiv", effects: { budget: 0, days: 0, morale: -12, quality: -15 }, feedback: "Go-live cu 47 bug-uri = credibilitate zero. Userii vor reveni la sistemul vechi." }
          ],
          tech: [
            { label: "Triage tehnic: clasificare, root cause analysis, fix sistematic", effects: { budget: -8000, days: 10, morale: 5, quality: 12 }, feedback: "Triage sistematic: 3 bug-uri au aceeași cauză rădăcină. Fix unic, 15 bug-uri rezolvate." },
            { label: "Hotfix-uri rapide pe bug-urile critice", effects: { budget: -3000, days: 5, morale: 0, quality: 5 }, feedback: "Hotfix-uri fără root cause analysis = plăci peste plăci. Bug-urile revin." },
            { label: "Userii exagerează — interfața e OK, doar trebuie training", effects: { budget: 0, days: 0, morale: -8, quality: -8 }, feedback: "Invalidarea feedback-ului de la useri e cea mai sigură cale de a pierde adopția." }
          ],
          finance: [
            { label: "Buget suplimentar: 2 QA testeri temporari pe 3 săptămâni", effects: { budget: -12000, days: 0, morale: 5, quality: 8 }, feedback: "QA suplimentar accelerează rezolvarea fără a supraîncărca echipa de dev." },
            { label: "Realoc buget de la training spre bug-fixing", effects: { budget: 0, days: 0, morale: -3, quality: 3 }, feedback: "Training redus = useri nepregătiți la go-live. Rezolvi o problemă, creezi alta." },
            { label: "Furnizorul trebuie să fixeze gratis — e în SLA", effects: { budget: 0, days: 10, morale: -3, quality: 2 }, feedback: "SLA acoperă bug-uri din produs, nu din customizare. Verifică contractul." }
          ],
          risk: [
            { label: "Go/No-Go checklist: criterii clare pentru lansare", effects: { budget: -2000, days: 2, morale: 8, quality: 8 }, feedback: "Criterii obiective elimină subiectivitatea. Toți știu ce trebuie rezolvat pentru go-live." },
            { label: "Plan de rollback: dacă go-live eșuează, revenire în 4 ore", effects: { budget: -5000, days: 3, morale: 5, quality: 5 }, feedback: "Rollback plan = plasă de siguranță. Echipa lansează cu încredere." },
            { label: "47 bug-uri e normal la UAT — mergem înainte", effects: { budget: 0, days: 0, morale: -5, quality: -8 }, feedback: "8 critice NU e normal. Minimizarea riscului la UAT e un red flag major." }
          ]
        },
        synergy: [
          { match: { pm: 0, tech: 0 }, bonus: { quality: 8 }, reason: "Sprint stabilizare + root cause analysis = rezolvare sistematică, nu patch-uri." },
          { match: { risk: 0 }, bonus: { morale: 5 }, reason: "Go/No-Go checklist = echipa lansează cu încredere." },
          { match: { pm: 2, tech: 2 }, penalty: { quality: -12, morale: -8 }, reason: "Forțare go-live + ignorare feedback = dezastru garantat." }
        ]
      },
      {
        id: "t-golive",
        day: 240,
        title: "Go-live și predare",
        context: "Ziua lansării. 80% din angajați au completat training-ul. Sistemul a trecut toate testele critice. Furnizorul e pe standby. Sponsorul organizează eveniment intern de lansare. Ultimele 30 de zile pentru stabilizare și hypercare.",
        teamChoices: {
          pm: [
            { label: "Go-live în faze: departament pilot → rollout gradual în 3 valuri", effects: { budget: -10000, days: 10, morale: 8, quality: 10 }, feedback: "Rollout gradual = fiecare val învață din precedentul. Riscul e distribuit." },
            { label: "Big bang: toată organizația migrează simultan", effects: { budget: -5000, days: 0, morale: -5, quality: -5 }, feedback: "Big bang e riscant dar rapid. Dacă pregătirea e solidă, poate funcționa. Dacă nu..." },
            { label: "Amân lansarea cu 2 săptămâni pentru „mai multe teste”", effects: { budget: -8000, days: 14, morale: -8, quality: 3 }, feedback: "Amânarea fără motiv concret semnalează lipsă de încredere. Echipa pierde avânt." }
          ],
          tech: [
            { label: "Hypercare: echipă dedicată support 24/7 prima săptămână", effects: { budget: -15000, days: 0, morale: 8, quality: 10 }, feedback: "Hypercare = diferența între lansare reușită și dezastru. Userii au ajutor imediat." },
            { label: "Support în program normal + canal Slack dedicat", effects: { budget: -3000, days: 0, morale: 3, quality: 5 }, feedback: "Slack ajută, dar problemele critice la 21:00 nu au cine le rezolva." },
            { label: "Documentația e suficientă — userii se descurcă", effects: { budget: 0, days: 0, morale: -8, quality: -8 }, feedback: "Primele zile sunt critice. Fără support, frustrarea transformă useri în sabotori." }
          ],
          finance: [
            { label: "Buget de hypercare + buget pentru post-stabilizare (30 zile)", effects: { budget: -15000, days: 0, morale: 5, quality: 8 }, feedback: "Bugetul post-launch e la fel de important ca cel de implementare. Proiecte bune eșuează la predare." },
            { label: "Ultimul buget merge pe evenimentul de lansare", effects: { budget: -5000, days: 0, morale: 3, quality: 0 }, feedback: "Evenimentul e plăcut, dar fără suport tehnic în spate, e doar un show." },
            { label: "Am terminat bugetul — improvizăm", effects: { budget: 0, days: 0, morale: -8, quality: -8 }, feedback: "Lansare fără buget de stabilizare = proiect abandonat după go-live." }
          ],
          risk: [
            { label: "Plan de monitorizare post-launch: KPI-uri zilnice prima lună", effects: { budget: -5000, days: 0, morale: 5, quality: 8 }, feedback: "KPI-uri zilnice detectează probleme devreme. Reacție rapidă = stabilizare rapidă." },
            { label: "Rollback plan testat + criteriile de rollback definite", effects: { budget: -5000, days: 2, morale: 5, quality: 5 }, feedback: "Rollback testat = ultima linie de apărare. Sperăm să nu fie nevoie, dar e acolo." },
            { label: "Dacă am ajuns la go-live, riscurile mari au trecut", effects: { budget: 0, days: 0, morale: -5, quality: -5 }, feedback: "Go-live e cel mai riscant moment. Complacerea acum e cea mai periculoasă atitudine." }
          ]
        },
        synergy: [
          { match: { pm: 0, tech: 0 }, bonus: { morale: 8, quality: 8 }, reason: "Rollout gradual + hypercare 24/7 = lansare model." },
          { match: { pm: 0, tech: 0, finance: 0, risk: 0 }, bonus: { morale: 10, quality: 10 }, reason: "Toate rolurile au investit maxim în succesul lansării. Proiect exemplar!" },
          { match: { pm: 1, tech: 2 }, penalty: { quality: -8, morale: -5 }, reason: "Big bang fără support = risc maxim concentrat într-o singură zi." }
        ]
      },
      {
        id: "t-closure",
        day: 260,
        title: "Închidere și lessons learned",
        context: "Proiectul se apropie de final. Sistemul rulează de 3 săptămâni. Sponsorul cere raport final. Echipa e obosită dar mândră. Mai sunt câteva bug-uri minore în backlog. Departamentul HR cere documentația de training actualizată.",
        teamChoices: {
          pm: [
            { label: "Retrospectivă structurată + raport complet + ceremonie de închidere", effects: { budget: -8000, days: 5, morale: 10, quality: 5 }, feedback: "Închiderea ceremonială recunoaște efortul echipei. Lessons learned ghidează proiecte viitoare." },
            { label: "Raport final rapid + handover documentație", effects: { budget: -2000, days: 2, morale: 3, quality: 3 }, feedback: "Funcțional, dar fără retrospectivă pierzi cele mai valoroase lecții." },
            { label: "Proiectul e gata, trec la următorul", effects: { budget: 0, days: 0, morale: -8, quality: -5 }, feedback: "Echipa se simte neapreciată. Organizația pierde lessons learned. Greșeli se vor repeta." }
          ],
          tech: [
            { label: "Documentație tehnică completă + runbook operațional", effects: { budget: -5000, days: 5, morale: 3, quality: 8 }, feedback: "Runbook-ul permite echipei de operațiuni să gestioneze sistemul fără depinzând de echipa de proiect." },
            { label: "Documentez doar părțile custom, restul e standard", effects: { budget: -2000, days: 2, morale: 0, quality: 3 }, feedback: "Documentația parțială e mai bună decât nimic, dar operațiunile vor avea întrebări." },
            { label: "Codul e documentat suficient prin comentarii", effects: { budget: 0, days: 0, morale: -3, quality: -5 }, feedback: "Comentarii în cod ≠ documentație operațională. Echipa de support nu citește codul." }
          ],
          finance: [
            { label: "Audit financiar complet + raport de buget final vs. planificat", effects: { budget: -5000, days: 3, morale: 5, quality: 5 }, feedback: "Transparența financiară totală. Sponsorul apreciază, organizația învață pentru proiecte viitoare." },
            { label: "Raport financiar sumar — cheltuieli vs. buget", effects: { budget: -1000, days: 1, morale: 2, quality: 2 }, feedback: "Sumar e acceptabil, dar fără detalii pierzi oportunitatea de a îmbunătăți estimările viitoare." },
            { label: "Cifrele sunt în sistem, cine vrea le consultă", effects: { budget: 0, days: 0, morale: -3, quality: -3 }, feedback: "Lipsă de transparență la final lasă impresia de „ceva de ascuns”. Chiar dacă nu e cazul." }
          ],
          risk: [
            { label: "Registru de riscuri final: ce s-a materializat, ce am învățat", effects: { budget: -2000, days: 2, morale: 5, quality: 5 }, feedback: "Analiza riscurilor materializate vs. planificate e cel mai valoros input pentru proiecte viitoare." },
            { label: "Recomandări de risc pentru operațiuni (top 5 riscuri post-proiect)", effects: { budget: -1000, days: 1, morale: 3, quality: 5 }, feedback: "Predare de riscuri = continuitate. Operațiunile știu la ce să fie atente." },
            { label: "Riscurile proiectului s-au încheiat odată cu proiectul", effects: { budget: 0, days: 0, morale: -3, quality: -5 }, feedback: "Riscurile operaționale sunt moștenite de la proiect. Fără tranziție, surprizele sunt garantate." }
          ]
        },
        synergy: [
          { match: { pm: 0, tech: 0, finance: 0, risk: 0 }, bonus: { morale: 10, quality: 8 }, reason: "Închidere exemplară pe toate dimensiunile. Proiect de referință!" },
          { match: { pm: 0, risk: 0 }, bonus: { morale: 5 }, reason: "Retrospectivă + analiza riscurilor = lessons learned complete." },
          { match: { pm: 2, tech: 2 }, penalty: { morale: -8, quality: -5 }, reason: "Abandonare fără documentație sau retrospectivă = oportunitate pierdută." }
        ]
      }
    ]
  }
];

// ── Team Setup Section ──────────────────────────────────

function TeamSetupSection({ state, update, go }) {
  const scenario = TEAM_SCENARIOS[0];
  const minPlayers = 2;
  const maxPlayers = 4;

  const [players, setPlayers] = React.useState(
    state.m3team?.players?.length
      ? state.m3team.players
      : [{ name: "", role: "pm" }, { name: "", role: "tech" }]
  );

  const addPlayer = () => {
    if (players.length >= maxPlayers) return;
    const usedRoles = players.map(p => p.role);
    const freeRole = TEAM_ROLES.find(r => !usedRoles.includes(r.id))?.id || "pm";
    setPlayers([...players, { name: "", role: freeRole }]);
  };

  const removePlayer = (idx) => {
    if (players.length <= minPlayers) return;
    setPlayers(players.filter((_, i) => i !== idx));
  };

  const updatePlayer = (idx, field, value) => {
    setPlayers(players.map((p, i) => i === idx ? { ...p, [field]: value } : p));
  };

  const usedRoles = players.map(p => p.role);
  const canStart = players.length >= minPlayers
    && players.every(p => p.name.trim().length >= 2)
    && new Set(usedRoles).size === players.length; // no duplicate roles

  const startGame = () => {
    update(s => ({
      ...s,
      m3team: {
        players,
        scenarioId: scenario.id,
        state: {
          eventIdx: 0,
          budget: scenario.initialBudget,
          budgetSpent: 0,
          days: 0,
          daysLimit: scenario.initialDays,
          morale: scenario.initialMorale,
          quality: scenario.initialQuality,
          currentRole: 0, // index into active players for current turn
          roleChoices: {}, // { roleId: choiceIdx } for current event
          history: []
        },
        finished: false,
        teamScore: null,
        roleScores: {},
        coordinationScore: null
      }
    }));
    go("m3-team-sim");
  };

  return (
    <div>
      <div className="main-head">
        <div className="crumb">Modul 3 · Simulare Echipă</div>
        <h1 className="section-title">Simulare în echipă — Configurare</h1>
        <p className="section-lede">
          {scenario.blurb}
        </p>
        <div className="section-meta">
          <span><Pill kind="info">{scenario.events.length} runde de decizii</Pill></span>
          <span className="dot"></span>
          <span>2-4 jucători · pass-and-play</span>
          <span className="dot"></span>
          <span>Dificultate: {"★".repeat(scenario.difficulty)}{"☆".repeat(5 - scenario.difficulty)}</span>
        </div>
      </div>

      <div style={{marginBottom: 24, padding: "20px 24px", background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 12}}>
        <div className="eyebrow" style={{marginBottom: 16}}>Cum funcționează</div>
        <div style={{display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))", gap: 16}}>
          <div style={{padding: "14px 16px", background: "var(--bg)", borderRadius: 8, border: "1px solid var(--line)"}}>
            <div style={{fontSize: 20, marginBottom: 6}}>1. Alegeți roluri</div>
            <div style={{fontSize: 13, color: "var(--muted)"}}>Fiecare jucător ia un rol diferit: PM, Tech Lead, Financial Controller sau Risk Manager.</div>
          </div>
          <div style={{padding: "14px 16px", background: "var(--bg)", borderRadius: 8, border: "1px solid var(--line)"}}>
            <div style={{fontSize: 20, marginBottom: 6}}>2. Decizii pe rol</div>
            <div style={{fontSize: 13, color: "var(--muted)"}}>La fiecare eveniment, fiecare rol primește opțiuni specifice. Transmiteți dispozitivul pe rând.</div>
          </div>
          <div style={{padding: "14px 16px", background: "var(--bg)", borderRadius: 8, border: "1px solid var(--line)"}}>
            <div style={{fontSize: 20, marginBottom: 6}}>3. Sinergie</div>
            <div style={{fontSize: 13, color: "var(--muted)"}}>Deciziile aliniate între roluri aduc bonusuri. Conflictele aduc penalizări. Coordonarea e cheia!</div>
          </div>
        </div>
      </div>

      <div style={{marginBottom: 24, padding: "20px 24px", background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 12}}>
        <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16}}>
          <div className="eyebrow">Jucători ({players.length}/{maxPlayers})</div>
          {players.length < maxPlayers && (
            <button className="btn ghost" onClick={addPlayer}>+ Adaugă jucător</button>
          )}
        </div>

        <div style={{display: "grid", gap: 12}}>
          {players.map((p, i) => {
            const role = TEAM_ROLES.find(r => r.id === p.role);
            return (
              <div key={i} style={{display: "grid", gridTemplateColumns: "1fr 1fr auto", gap: 12, padding: "14px 16px", background: "var(--bg)", borderRadius: 8, border: "1px solid var(--line)", alignItems: "center"}}>
                <div>
                  <label style={{fontSize: 12, fontWeight: 600, display: "block", marginBottom: 4, color: "var(--muted)"}}>Nume jucător</label>
                  <input
                    className="txt"
                    value={p.name}
                    onChange={e => updatePlayer(i, "name", e.target.value)}
                    placeholder={`Jucător ${i + 1}`}
                    style={{margin: 0}}
                  />
                </div>
                <div>
                  <label style={{fontSize: 12, fontWeight: 600, display: "block", marginBottom: 4, color: "var(--muted)"}}>Rol</label>
                  <select
                    className="txt"
                    value={p.role}
                    onChange={e => updatePlayer(i, "role", e.target.value)}
                    style={{margin: 0}}
                  >
                    {TEAM_ROLES.map(r => (
                      <option key={r.id} value={r.id} disabled={usedRoles.includes(r.id) && p.role !== r.id}>
                        {r.icon} {r.name}
                      </option>
                    ))}
                  </select>
                  <div style={{fontSize: 11, color: "var(--muted)", marginTop: 4}}>{role?.desc}</div>
                </div>
                <div>
                  {players.length > minPlayers && (
                    <button className="btn ghost" onClick={() => removePlayer(i)} style={{padding: "6px 10px"}} title="Elimină">✕</button>
                  )}
                </div>
              </div>
            );
          })}
        </div>
      </div>

      <div className="foot-actions">
        <button className="btn ghost" onClick={() => go("m3-overview")}>← Înapoi la M3</button>
        <button className="btn primary" disabled={!canStart} onClick={startGame}>
          {canStart ? "Începe simularea →" : "Completează numele și alege roluri unice"}
        </button>
      </div>
    </div>
  );
}

// ── Team Simulator Section ──────────────────────────────

function TeamSimulatorSection({ state, update, go }) {
  const team = state.m3team;
  if (!team?.scenarioId) { go("m3-team-setup"); return null; }

  const scenario = TEAM_SCENARIOS.find(s => s.id === team.scenarioId);
  if (!scenario) { go("m3-team-setup"); return null; }

  const sim = team.state;
  if (!sim) return null; // state not yet initialized
  const event = scenario.events[sim.eventIdx];
  const activeRoles = team.players.map(p => p.role);

  const currentRoleIdx = sim.currentRole || 0;
  const currentPlayer = team.players[currentRoleIdx];
  const currentRole = TEAM_ROLES.find(r => r.id === currentPlayer?.role);
  const choices = event?.teamChoices?.[currentPlayer?.role] || [];
  const chosen = sim.roleChoices?.[currentPlayer?.role];
  const allDecided = activeRoles.every(r => sim.roleChoices?.[r] !== undefined);

  const [showFeedback, setShowFeedback] = React.useState(false);
  const [passScreen, setPassScreen] = React.useState(false);

  const clamp = (v, min, max) => Math.max(min, Math.min(max, v));

  const selectChoice = (idx) => {
    if (chosen !== undefined) return;
    const newRoleChoices = { ...sim.roleChoices, [currentPlayer.role]: idx };
    update(s => ({
      ...s,
      m3team: {
        ...s.m3team,
        state: { ...s.m3team.state, roleChoices: newRoleChoices }
      }
    }));
    setShowFeedback(true);
  };

  const nextRole = () => {
    setShowFeedback(false);
    const next = currentRoleIdx + 1;
    if (next < team.players.length) {
      // Next player's turn — show pass screen
      update(s => ({
        ...s,
        m3team: { ...s.m3team, state: { ...s.m3team.state, currentRole: next } }
      }));
      setPassScreen(true);
    }
    // If all decided, allDecided will trigger the "apply" button
  };

  const dismissPassScreen = () => setPassScreen(false);

  const applyAndAdvance = () => {
    // Calculate combined effects
    let totalEffects = { budget: 0, days: 0, morale: 0, quality: 0 };
    const roundChoices = {};
    activeRoles.forEach(role => {
      const cIdx = sim.roleChoices[role];
      const choice = event.teamChoices[role]?.[cIdx];
      if (choice) {
        totalEffects.budget += choice.effects.budget || 0;
        totalEffects.days += choice.effects.days || 0;
        totalEffects.morale += choice.effects.morale || 0;
        totalEffects.quality += choice.effects.quality || 0;
        roundChoices[role] = { idx: cIdx, label: choice.label, feedback: choice.feedback, effects: choice.effects };
      }
    });

    // Check synergy bonuses/penalties
    const synergyResults = [];
    (event.synergy || []).forEach(syn => {
      const matchEntries = Object.entries(syn.match);
      const matches = matchEntries.every(([role, expectedIdx]) =>
        sim.roleChoices[role] === expectedIdx
      );
      // Only apply if all roles in the match are actually playing
      const allPresent = matchEntries.every(([role]) => activeRoles.includes(role));
      if (matches && allPresent) {
        if (syn.bonus) {
          totalEffects.morale += syn.bonus.morale || 0;
          totalEffects.quality += syn.bonus.quality || 0;
          totalEffects.budget += syn.bonus.budget || 0;
          totalEffects.days += syn.bonus.days || 0;
        }
        if (syn.penalty) {
          totalEffects.morale += syn.penalty.morale || 0;
          totalEffects.quality += syn.penalty.quality || 0;
          totalEffects.budget += syn.penalty.budget || 0;
          totalEffects.days += syn.penalty.days || 0;
        }
        synergyResults.push({ reason: syn.reason, bonus: !!syn.bonus });
      }
    });

    const newBudget = sim.budget + totalEffects.budget;
    const newDays = sim.days + totalEffects.days;
    const newMorale = clamp(sim.morale + totalEffects.morale, 0, 100);
    const newQuality = clamp(sim.quality + totalEffects.quality, 0, 100);
    const budgetSpent = sim.budgetSpent + Math.abs(Math.min(0, totalEffects.budget));

    const historyEntry = {
      eventId: event.id,
      eventTitle: event.title,
      day: event.day,
      choices: roundChoices,
      totalEffects,
      synergy: synergyResults,
      snapshot: { budget: newBudget, days: newDays, morale: newMorale, quality: newQuality }
    };

    const nextEventIdx = sim.eventIdx + 1;
    const isFinished = nextEventIdx >= scenario.events.length;

    if (isFinished) {
      // Calculate scores
      const budgetRemaining = newBudget / scenario.initialBudget * 100;
      const timeRemaining = (scenario.initialDays - newDays) / scenario.initialDays * 100;
      const budgetScore = clamp(budgetRemaining, 0, 100);
      const timeScore = clamp(timeRemaining, 0, 100);
      const teamScore = Math.round(budgetScore * 0.25 + timeScore * 0.25 + newMorale * 0.25 + newQuality * 0.25);

      // Coordination score: % of events with at least one synergy bonus
      const history = [...sim.history, historyEntry];
      const eventsWithBonus = history.filter(h => h.synergy.some(s => s.bonus)).length;
      const coordinationScore = Math.round((eventsWithBonus / scenario.events.length) * 100);

      update(s => ({
        ...s,
        m3team: {
          ...s.m3team,
          state: {
            ...s.m3team.state,
            budget: newBudget, budgetSpent, days: newDays,
            morale: newMorale, quality: newQuality,
            eventIdx: nextEventIdx,
            roleChoices: {},
            currentRole: 0,
            history: [...sim.history, historyEntry]
          },
          finished: true,
          teamScore,
          coordinationScore,
          roleScores: {}
        }
      }));
      go("m3-team-report");
    } else {
      update(s => ({
        ...s,
        m3team: {
          ...s.m3team,
          state: {
            ...s.m3team.state,
            budget: newBudget, budgetSpent, days: newDays,
            morale: newMorale, quality: newQuality,
            eventIdx: nextEventIdx,
            roleChoices: {},
            currentRole: 0,
            history: [...sim.history, historyEntry]
          }
        }
      }));
      setPassScreen(true);
    }
    setShowFeedback(false);
  };

  if (!event) { go("m3-team-report"); return null; }

  // Stat bar helper
  const statBar = (label, value, max, unit, color) => (
    <div style={{flex: 1, minWidth: 120}}>
      <div style={{display: "flex", justifyContent: "space-between", fontSize: 12, marginBottom: 4}}>
        <span style={{fontWeight: 600}}>{label}</span>
        <span>{typeof value === "number" ? (unit === "RON" ? value.toLocaleString("ro-RO") + " RON" : value + (unit || "")) : value}</span>
      </div>
      <div className="progress-bar" style={{background: "var(--line)", margin: 0, height: 6}}>
        <div className="progress-bar-fill" style={{width: `${clamp((value / max) * 100, 0, 100)}%`, background: color || "var(--accent)"}}></div>
      </div>
    </div>
  );

  // Pass screen overlay
  if (passScreen) {
    const nextPlayer = team.players[sim.currentRole];
    const nextRoleInfo = TEAM_ROLES.find(r => r.id === nextPlayer?.role);
    return (
      <div style={{display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", minHeight: "60vh", textAlign: "center"}}>
        <div style={{fontSize: 48, marginBottom: 16}}>{nextRoleInfo?.icon}</div>
        <h2 style={{fontFamily: "var(--display)", fontSize: 24, marginBottom: 8}}>Transmite dispozitivul</h2>
        <p style={{fontSize: 16, color: "var(--muted)", marginBottom: 8}}>
          Următorul: <strong>{nextPlayer?.name}</strong>
        </p>
        <p style={{fontSize: 14, color: "var(--muted)", marginBottom: 24}}>
          Rol: {nextRoleInfo?.name} — {nextRoleInfo?.desc}
        </p>
        <button className="btn primary" onClick={dismissPassScreen}>Sunt gata →</button>
      </div>
    );
  }

  return (
    <div>
      <div className="main-head">
        <div className="crumb">Simulare echipă · Runda {sim.eventIdx + 1} / {scenario.events.length}</div>
        <h1 className="section-title">{event.title}</h1>
        <div className="section-meta">
          <span>Ziua {event.day}</span>
          <span className="dot"></span>
          <span>Decide: <strong>{currentPlayer?.name}</strong> ({currentRole?.name})</span>
        </div>
      </div>

      {/* Dashboard */}
      <div style={{display: "flex", gap: 16, flexWrap: "wrap", marginBottom: 24, padding: "16px 20px", background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 12}}>
        {statBar("Buget rămas", sim.budget, scenario.initialBudget, "RON")}
        {statBar("Zile consumate", sim.days, scenario.initialDays, "")}
        {statBar("Moral echipă", sim.morale, 100, "%", sim.morale < 40 ? "var(--danger, #e74c3c)" : undefined)}
        {statBar("Calitate", sim.quality, 100, "%", sim.quality < 40 ? "var(--danger, #e74c3c)" : undefined)}
      </div>

      {/* Event context */}
      <div style={{marginBottom: 24, padding: "18px 22px", background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 12}}>
        <div className="eyebrow" style={{marginBottom: 8}}>Context</div>
        <p style={{fontSize: 15, lineHeight: 1.6, margin: 0}}>{event.context}</p>
      </div>

      {/* Role indicator */}
      <div style={{marginBottom: 16, display: "flex", gap: 8}}>
        {team.players.map((p, i) => {
          const r = TEAM_ROLES.find(tr => tr.id === p.role);
          const decided = sim.roleChoices?.[p.role] !== undefined;
          const isCurrent = i === currentRoleIdx;
          return (
            <div
              key={p.role}
              style={{
                padding: "8px 14px",
                borderRadius: 8,
                border: `2px solid ${isCurrent ? "var(--accent)" : decided ? "var(--success, #27ae60)" : "var(--line)"}`,
                background: isCurrent ? "var(--accent-bg, rgba(99,102,241,0.08))" : "var(--bg-card)",
                fontSize: 13,
                fontWeight: isCurrent ? 700 : 400,
                opacity: decided && !isCurrent ? 0.6 : 1
              }}
            >
              {r?.icon} {p.name} {decided && !isCurrent ? "✓" : ""}
            </div>
          );
        })}
      </div>

      {/* Choices for current role */}
      {chosen === undefined && (
        <div style={{marginBottom: 24}}>
          <div className="eyebrow" style={{marginBottom: 12}}>
            {currentRole?.icon} Decizia ta ca {currentRole?.name}
          </div>
          <div style={{display: "grid", gap: 10}}>
            {choices.map((c, j) => (
              <button
                key={j}
                className="tool-card"
                onClick={() => selectChoice(j)}
                style={{textAlign: "left", cursor: "pointer"}}
              >
                <div className="tool-title" style={{marginBottom: 4}}>{c.label}</div>
                <div style={{fontSize: 13, color: "var(--muted)"}}>
                  {Object.entries(c.effects).filter(([, v]) => v !== 0).map(([k, v]) => {
                    const labels = { budget: "Buget", days: "Zile", morale: "Moral", quality: "Calitate" };
                    return `${labels[k]}: ${v > 0 ? "+" : ""}${k === "budget" ? v.toLocaleString("ro-RO") : v}`;
                  }).join(" · ")}
                </div>
              </button>
            ))}
          </div>
        </div>
      )}

      {/* Feedback after choosing */}
      {showFeedback && chosen !== undefined && (
        <div style={{marginBottom: 24, padding: "16px 20px", background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 12}}>
          <div className="eyebrow" style={{marginBottom: 8}}>Feedback — {currentRole?.name}</div>
          <p style={{fontSize: 14, lineHeight: 1.6, margin: "0 0 12px 0"}}>{choices[chosen]?.feedback}</p>
          {currentRoleIdx < team.players.length - 1 ? (
            <button className="btn primary" onClick={nextRole}>Următorul jucător →</button>
          ) : (
            <button className="btn primary" onClick={() => setShowFeedback(false)}>Continuă →</button>
          )}
        </div>
      )}

      {/* All decided — show summary and advance */}
      {allDecided && !showFeedback && (
        <div style={{marginBottom: 24, padding: "18px 22px", background: "var(--bg-card)", border: "2px solid var(--accent)", borderRadius: 12}}>
          <div className="eyebrow" style={{marginBottom: 12}}>Rezumat runda — toți au decis</div>
          <div style={{display: "grid", gap: 8, marginBottom: 16}}>
            {team.players.map(p => {
              const cIdx = sim.roleChoices[p.role];
              const choice = event.teamChoices[p.role]?.[cIdx];
              const r = TEAM_ROLES.find(tr => tr.id === p.role);
              return (
                <div key={p.role} style={{padding: "10px 14px", background: "var(--bg)", borderRadius: 8, border: "1px solid var(--line)"}}>
                  <span style={{fontWeight: 600}}>{r?.icon} {p.name}:</span>{" "}
                  <span>{choice?.label}</span>
                </div>
              );
            })}
          </div>
          <button className="btn primary" onClick={applyAndAdvance}>
            {sim.eventIdx + 1 >= scenario.events.length ? "Vezi rezultatele →" : "Aplică și continuă →"}
          </button>
        </div>
      )}
    </div>
  );
}

// ── Team Report Section ─────────────────────────────────

function TeamReportSection({ state, update, go }) {
  const team = state.m3team;
  if (!team?.finished) { go("m3-team-setup"); return null; }

  const scenario = TEAM_SCENARIOS.find(s => s.id === team.scenarioId);
  const sim = team.state;
  const history = sim.history || [];

  const grade = team.teamScore >= 90 ? "A" : team.teamScore >= 75 ? "B" : team.teamScore >= 60 ? "C" : team.teamScore >= 45 ? "D" : "F";
  const gradeLabel = { A: "Excelent", B: "Foarte bine", C: "Bine", D: "Suficient", F: "Insuficient" };

  const totalSynergies = history.reduce((sum, h) => sum + h.synergy.filter(s => s.bonus).length, 0);
  const totalConflicts = history.reduce((sum, h) => sum + h.synergy.filter(s => !s.bonus).length, 0);

  const [expandedRound, setExpandedRound] = React.useState(null);

  const resetTeam = () => {
    update(s => ({
      ...s,
      m3team: { ...s.m3team, finished: false, teamScore: null, coordinationScore: null, state: null, scenarioId: null }
    }));
    go("m3-team-setup");
  };

  return (
    <div>
      <div className="main-head">
        <div className="crumb">Simulare echipă · Raport final</div>
        <h1 className="section-title">Raport de echipă</h1>
        <p className="section-lede">
          {scenario?.title} — {team.players.map(p => p.name).join(", ")}
        </p>
      </div>

      {/* Score card */}
      <div style={{display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(160px, 1fr))", gap: 14, marginBottom: 24}}>
        <div style={{padding: "20px", background: "var(--bg-card)", border: "2px solid var(--accent)", borderRadius: 12, textAlign: "center"}}>
          <div style={{fontSize: 42, fontWeight: 800, fontFamily: "var(--display)"}}>{team.teamScore}</div>
          <div style={{fontSize: 14, color: "var(--muted)"}}>Scor echipă</div>
          <div style={{marginTop: 4}}><Pill kind={grade === "A" || grade === "B" ? "info" : "default"}>{grade} — {gradeLabel[grade]}</Pill></div>
        </div>
        <div style={{padding: "20px", background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 12, textAlign: "center"}}>
          <div style={{fontSize: 42, fontWeight: 800, fontFamily: "var(--display)"}}>{team.coordinationScore}%</div>
          <div style={{fontSize: 14, color: "var(--muted)"}}>Coordonare</div>
        </div>
        <div style={{padding: "20px", background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 12, textAlign: "center"}}>
          <div style={{fontSize: 42, fontWeight: 800, fontFamily: "var(--display)", color: "var(--success, #27ae60)"}}>{totalSynergies}</div>
          <div style={{fontSize: 14, color: "var(--muted)"}}>Sinergii</div>
        </div>
        <div style={{padding: "20px", background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 12, textAlign: "center"}}>
          <div style={{fontSize: 42, fontWeight: 800, fontFamily: "var(--display)", color: "var(--danger, #e74c3c)"}}>{totalConflicts}</div>
          <div style={{fontSize: 14, color: "var(--muted)"}}>Conflicte</div>
        </div>
      </div>

      {/* Final stats */}
      <div style={{display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))", gap: 14, marginBottom: 24}}>
        {[
          { label: "Buget rămas", value: sim.budget.toLocaleString("ro-RO") + " RON", sub: `din ${scenario.initialBudget.toLocaleString("ro-RO")} RON` },
          { label: "Zile consumate", value: sim.days, sub: `din ${scenario.initialDays} zile limită` },
          { label: "Moral final", value: sim.morale + "%", sub: `start: ${scenario.initialMorale}%` },
          { label: "Calitate finală", value: sim.quality + "%", sub: `start: ${scenario.initialQuality}%` }
        ].map(s => (
          <div key={s.label} style={{padding: "16px 20px", background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 12}}>
            <div style={{fontSize: 24, fontWeight: 700, fontFamily: "var(--display)"}}>{s.value}</div>
            <div style={{fontSize: 13, fontWeight: 600}}>{s.label}</div>
            <div style={{fontSize: 12, color: "var(--muted)"}}>{s.sub}</div>
          </div>
        ))}
      </div>

      {/* Team composition */}
      <div style={{marginBottom: 24, padding: "18px 22px", background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 12}}>
        <div className="eyebrow" style={{marginBottom: 12}}>Echipa</div>
        <div style={{display: "flex", gap: 12, flexWrap: "wrap"}}>
          {team.players.map(p => {
            const r = TEAM_ROLES.find(tr => tr.id === p.role);
            return (
              <div key={p.role} style={{padding: "10px 16px", background: "var(--bg)", borderRadius: 8, border: "1px solid var(--line)"}}>
                <span style={{fontSize: 16, marginRight: 6}}>{r?.icon}</span>
                <strong>{p.name}</strong>
                <span style={{color: "var(--muted)", marginLeft: 6}}>— {r?.name}</span>
              </div>
            );
          })}
        </div>
      </div>

      {/* Round-by-round history */}
      <div style={{marginBottom: 24}}>
        <div className="eyebrow" style={{marginBottom: 12}}>Istoric decizii</div>
        <div style={{display: "grid", gap: 10}}>
          {history.map((h, i) => (
            <div key={i} style={{background: "var(--bg-card)", border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden"}}>
              <button
                onClick={() => setExpandedRound(expandedRound === i ? null : i)}
                style={{width: "100%", textAlign: "left", padding: "14px 18px", background: "transparent", border: "none", cursor: "pointer", display: "flex", justifyContent: "space-between", alignItems: "center", color: "var(--fg)"}}
              >
                <div>
                  <span style={{fontWeight: 600}}>Runda {i + 1}: {h.eventTitle}</span>
                  <span style={{color: "var(--muted)", marginLeft: 8, fontSize: 13}}>Ziua {h.day}</span>
                </div>
                <div style={{display: "flex", gap: 6, alignItems: "center"}}>
                  {h.synergy.filter(s => s.bonus).length > 0 && <Pill kind="info">{h.synergy.filter(s => s.bonus).length} sinergie</Pill>}
                  {h.synergy.filter(s => !s.bonus).length > 0 && <Pill kind="default">{h.synergy.filter(s => !s.bonus).length} conflict</Pill>}
                  <span style={{fontSize: 18}}>{expandedRound === i ? "−" : "+"}</span>
                </div>
              </button>
              {expandedRound === i && (
                <div style={{padding: "0 18px 16px"}}>
                  {Object.entries(h.choices).map(([role, c]) => {
                    const r = TEAM_ROLES.find(tr => tr.id === role);
                    const player = team.players.find(p => p.role === role);
                    return (
                      <div key={role} style={{padding: "10px 14px", margin: "6px 0", background: "var(--bg)", borderRadius: 8, border: "1px solid var(--line)"}}>
                        <div style={{fontWeight: 600, marginBottom: 4}}>{r?.icon} {player?.name} ({r?.short}): {c.label}</div>
                        <div style={{fontSize: 13, color: "var(--muted)"}}>{c.feedback}</div>
                      </div>
                    );
                  })}
                  {h.synergy.length > 0 && (
                    <div style={{marginTop: 8}}>
                      {h.synergy.map((s, j) => (
                        <div key={j} style={{padding: "8px 12px", margin: "4px 0", borderRadius: 6, fontSize: 13, fontWeight: 500, background: s.bonus ? "rgba(39,174,96,0.08)" : "rgba(231,76,60,0.08)", border: `1px solid ${s.bonus ? "rgba(39,174,96,0.2)" : "rgba(231,76,60,0.2)"}`}}>
                          {s.bonus ? "✦ Sinergie" : "⚠ Conflict"}: {s.reason}
                        </div>
                      ))}
                    </div>
                  )}
                </div>
              )}
            </div>
          ))}
        </div>
      </div>

      <div className="foot-actions">
        <button className="btn ghost" onClick={resetTeam}>↻ Joacă din nou</button>
        <button className="btn ghost" onClick={() => go("m3-overview")}>← Înapoi la M3</button>
        <button className="btn primary" onClick={() => go("m4-overview")}>Trec la M4 →</button>
      </div>
    </div>
  );
}

Object.assign(window, {
  M3OverviewSection, SimulatorSection, ReportSection,
  TEAM_ROLES, TEAM_SCENARIOS, TeamSetupSection, TeamSimulatorSection, TeamReportSection
});
