/* ============================================================
   ensō rse — Quizz onboarding · Espace MANAGER
   ============================================================ */

const ROLE_ICON = { commercial: "briefcase", cs: "life-buoy", marketing: "megaphone", produit: "boxes" };

function statusOf(r) {
  if (!r.attempts.length) return { label: "Invité·e — pas encore passé", tone: "neutral", icon: "clock" };
  const ph = window.QD.phaseOf(r.attempts[r.attempts.length - 1]);
  return { label: `Quizz ${window.QD.PHASES[ph].label} réalisé`, tone: ph === "j15" ? "env" : "soc", icon: ph === "j15" ? "trending-up" : "check-circle" };
}
function fmtDate(iso) {
  try { return new Date(iso).toLocaleDateString("fr-FR", { day: "numeric", month: "short" }); } catch (e) { return ""; }
}

/* ---------- liste recrues ---------- */
function ManagerHome({ onOpen, onInvite, refreshKey }) {
  const QD = window.QD;
  const recruits = window.Store.all().sort((a, b) => (b.attempts[0]?.date || b.createdAt).localeCompare(a.attempts[0]?.date || a.createdAt));
  const done = recruits.filter(r => r.attempts.length);
  const avg = done.length ? Math.round(done.reduce((s, r) => s + r.attempts[r.attempts.length - 1].global, 0) / done.length) : 0;

  return (
    <div className="fade-up" style={{ maxWidth: 1080, margin: "0 auto", padding: "8px 0 60px" }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", flexWrap: "wrap", gap: 16, marginBottom: 28 }}>
        <div>
          <Eyebrow>Espace manager</Eyebrow>
          <h1 style={{ fontSize: "var(--fs-3xl)", marginTop: 10 }}>Tes recrues</h1>
          <p className="muted" style={{ fontSize: "var(--fs-md)", marginTop: 6 }}>Suis les niveaux d'entrée, repère les lacunes et adapte chaque onboarding.</p>
        </div>
        <Btn icon="plus" onClick={onInvite}>Inviter une recrue</Btn>
      </div>

      {/* stat strip */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(3,1fr)", gap: 16, marginBottom: 30 }}>
        {[{ k: "Recrues suivies", v: recruits.length, ic: "users", c: "var(--color-env-600)" },
          { k: "Quizz réalisés", v: done.reduce((s, r) => s + r.attempts.length, 0), ic: "list-checks", c: "var(--color-soc-600)" },
          { k: "Niveau d'entrée moyen", v: avg + "%", ic: "gauge", c: "var(--color-gov-600)" }].map(s => (
          <Card key={s.k} pad={20} style={{ display: "flex", alignItems: "center", gap: 14 }}>
            <div style={{ width: 44, height: 44, borderRadius: 12, background: "var(--color-neutral-50)", display: "grid", placeItems: "center", color: s.c, flex: "none" }}>
              <Icon name={s.ic} size={22} />
            </div>
            <div>
              <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: "var(--fs-2xl)", lineHeight: 1 }}>{s.v}</div>
              <div className="muted" style={{ fontSize: "var(--fs-sm)", marginTop: 3 }}>{s.k}</div>
            </div>
          </Card>
        ))}
      </div>

      <div style={{ display: "grid", gap: 12 }}>
        {recruits.map(r => {
          const st = statusOf(r);
          const last = r.attempts[r.attempts.length - 1];
          const lvl = last ? QD.levelFor(last.global) : null;
          return (
            <Card key={r.id} hover onClick={() => onOpen(r.id)} pad={18}
              style={{ display: "grid", gridTemplateColumns: "auto 1fr auto auto", gap: 20, alignItems: "center" }}>
              <div style={{ width: 46, height: 46, borderRadius: "50%", background: "var(--color-neutral-50)", display: "grid", placeItems: "center", color: "var(--accent-700)" }}>
                <Icon name={ROLE_ICON[r.role]} size={22} />
              </div>
              <div>
                <div style={{ fontWeight: 700, fontSize: "var(--fs-md)" }}>{r.name}</div>
                <div className="muted" style={{ fontSize: "var(--fs-sm)", marginTop: 2 }}>
                  {QD.ROLES[r.role].label} · {QD.STATUTS[r.statut].label}
                </div>
              </div>
              <div style={{ display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 6 }}>
                <Pill tone={st.tone}><Icon name={st.icon} size={14} />{st.label}</Pill>
                {last && <span className="subtle" style={{ fontSize: "var(--fs-xs)" }}>Dernier&nbsp;: {fmtDate(last.date)}</span>}
              </div>
              <div style={{ display: "flex", alignItems: "center", gap: 16, minWidth: 92, justifyContent: "flex-end" }}>
                {last ? (
                  <div style={{ textAlign: "right" }}>
                    <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: "var(--fs-xl)", color: lvl.color, lineHeight: 1 }}>{last.global}%</div>
                    <div style={{ fontSize: "var(--fs-xs)", fontWeight: 600, color: lvl.color }}>{lvl.label}</div>
                  </div>
                ) : <span className="subtle" style={{ fontSize: "var(--fs-sm)" }}>—</span>}
                <Icon name="chevron-right" size={20} color="var(--fg-subtle)" />
              </div>
            </Card>
          );
        })}
      </div>
    </div>
  );
}

/* ---------- analyse certitude/justesse ---------- */
function analyzeAttempt(attempt) {
  const qById = window.Store.qById;
  const flags = { mastered: [], fragile: [], misconception: [], gap: [] };
  Object.keys(attempt.answers).forEach(qid => {
    const q = qById[qid]; if (!q || q.type === "selfrate" || q.type === "free") return;
    const f = window.Store.flagFor(attempt.answers[qid]);
    if (f) flags[f].push({ q, a: attempt.answers[qid] });
  });
  return flags;
}

/* ---------- onglets ---------- */
function Tabs({ tabs, active, onChange }) {
  return (
    <div style={{ display: "flex", gap: 4, borderBottom: "1px solid var(--border-default)", marginBottom: 26, flexWrap: "wrap" }}>
      {tabs.map(t => {
        const on = active === t.k;
        return (
          <button key={t.k} onClick={() => onChange(t.k)}
            style={{ padding: "12px 16px", background: "none", border: "none", borderBottom: on ? "2.5px solid var(--accent-500)" : "2.5px solid transparent",
              marginBottom: -1, fontFamily: "var(--font-body)", fontWeight: 600, fontSize: "var(--fs-sm)",
              color: on ? "var(--fg-default)" : "var(--fg-muted)", display: "inline-flex", gap: 7, alignItems: "center", transition: "color .15s" }}>
            <Icon name={t.ic} size={17} />{t.label}
          </button>
        );
      })}
    </div>
  );
}

/* ---------- détail recrue ---------- */
function RecruitDetail({ id, onBack, onPassQuiz }) {
  const QD = window.QD;
  const r = window.Store.get(id);
  const [tab, setTab] = useState("overview");
  if (!r) return null;
  const last = r.attempts[r.attempts.length - 1];
  const prev = r.attempts.length > 1 ? r.attempts[r.attempts.length - 2] : null;
  const lvl = last ? QD.levelFor(last.global) : null;
  const flags = last ? analyzeAttempt(last) : null;
  const hasJ15 = r.attempts.some((a) => QD.phaseOf(a) === "j15");

  const tabs = [
    { k: "overview", label: "Vue d'ensemble", ic: "gauge" },
    { k: "discours", label: "Adapter mon discours", ic: "message-circle" },
    { k: "answers", label: "Détail des réponses", ic: "list-checks" },
  ];
  if (r.attempts.length > 1) tabs.push({ k: "progress", label: "Progression", ic: "trending-up" });

  return (
    <div className="fade-up" style={{ maxWidth: 1000, margin: "0 auto", padding: "8px 0 60px" }}>
      <button onClick={onBack} style={{ display: "inline-flex", gap: 7, alignItems: "center", background: "none", border: "none", color: "var(--fg-muted)", fontWeight: 600, fontSize: "var(--fs-sm)", marginBottom: 18, padding: 0 }}>
        <Icon name="arrow-left" size={17} /> Toutes les recrues
      </button>

      {/* header */}
      <div style={{ display: "flex", gap: 20, alignItems: "center", flexWrap: "wrap", marginBottom: 28 }}>
        <div style={{ width: 60, height: 60, borderRadius: "50%", background: "var(--color-env-100)", display: "grid", placeItems: "center", color: "var(--accent-700)", flex: "none" }}>
          <Icon name={ROLE_ICON[r.role]} size={28} />
        </div>
        <div style={{ flex: 1, minWidth: 200 }}>
          <h1 style={{ fontSize: "var(--fs-2xl)" }}>{r.name}</h1>
          <div className="muted" style={{ marginTop: 4 }}>{QD.ROLES[r.role].label} · {QD.STATUTS[r.statut].label}</div>
        </div>
        {last ? (
          <div style={{ display: "flex", alignItems: "center", gap: 18 }}>
            <div style={{ textAlign: "right" }}>
              <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: "var(--fs-3xl)", color: lvl.color, lineHeight: 1 }}>{last.global}%</div>
              <div style={{ fontWeight: 700, color: lvl.color }}>{lvl.label}</div>
              <div className="subtle" style={{ fontSize: "var(--fs-xs)", marginTop: 2 }}>au quizz {QD.PHASES[QD.phaseOf(last)].label}</div>
            </div>
            {hasJ15 ?
            <Pill tone="env"><Icon name="check-circle" size={14} />Quizz J+15 réalisé</Pill> :
            <Btn variant="secondary" icon="refresh" onClick={() => onPassQuiz(r.id)}>Passer le quizz {QD.PHASES["j15"].label}</Btn>}
          </div>
        ) : (
          <div style={{ textAlign: "right" }}>
            <Pill tone="neutral" style={{ marginBottom: 10 }}><Icon name="clock" size={14} />Pas encore passé le quizz</Pill><br />
            <Btn variant="primary" icon="send" onClick={() => onPassQuiz(r.id)}>Lancer son quizz J0</Btn>
          </div>
        )}
      </div>

      {!last ? (
        <Card pad={40} style={{ textAlign: "center" }}>
          <Icon name="clock" size={34} color="var(--fg-subtle)" style={{ margin: "0 auto 12px" }} />
          <h3 style={{ fontSize: "var(--fs-lg)", marginBottom: 8 }}>{r.name.split(" ")[0]} n'a pas encore passé le quizz d'entrée.</h3>
          <p className="muted" style={{ maxWidth: 420, margin: "0 auto" }}>Lance son quizz pour découvrir son niveau d'entrée et calibrer son onboarding.</p>
        </Card>
      ) : (
        <>
          <Tabs tabs={tabs} active={tab} onChange={setTab} />
          {tab === "overview" && <OverviewTab r={r} last={last} prev={prev} flags={flags} />}
          {tab === "discours" && <DiscoursTab last={last} flags={flags} name={r.name} role={r.role} statut={r.statut} />}
          {tab === "answers" && <AnswersTab attempt={last} prev={prev} />}
          {tab === "progress" && prev && <ProgressTab r={r} prev={prev} last={last} />}
        </>
      )}
    </div>
  );
}

/* ---------- tuile d'insight avec tooltip de détail au survol ---------- */
function InsightTile({ it, items }) {
  const [hover, setHover] = useState(false);
  const col = `var(--color-${it.tone === "danger" ? "gov-700" : it.tone === "gov" ? "gov-500" : "env-600"})`;
  const hoverable = items.length > 0;
  return (
    <div style={{ position: "relative" }}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}>
      <Card pad={20} style={{ cursor: hoverable ? "help" : "default", borderColor: hover && hoverable ? col : "var(--border-default)", transition: "border-color .15s" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 8 }}>
          <Icon name={it.icon} size={19} color={col} />
          <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: "var(--fs-2xl)" }}>{items.length}</div>
        </div>
        <div style={{ fontWeight: 700, fontSize: "var(--fs-sm)" }}>{it.label}</div>
        <div className="muted" style={{ fontSize: "var(--fs-xs)", marginTop: 3, lineHeight: 1.4 }}>{it.desc}</div>
        {hoverable &&
        <div style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: "var(--fs-xs)", fontWeight: 600, color: col, marginTop: 10 }}>
            <Icon name="eye" size={13} /> Survole pour le détail
          </div>}
      </Card>
      {hover && hoverable &&
      <div style={{ position: "absolute", top: "calc(100% + 8px)", left: 0, right: 0, zIndex: 30,
        background: "var(--bg-surface)", border: `1px solid ${col}`, borderRadius: "var(--r-md)",
        boxShadow: "var(--shadow-lg)", padding: "14px 16px", maxHeight: 280, overflowY: "auto" }}>
          <div style={{ fontSize: "var(--fs-xs)", fontWeight: 700, textTransform: "uppercase", letterSpacing: ".03em", color: col, marginBottom: 10 }}>
            {it.k === "misconception" ? "À corriger explicitement" : it.k === "fragile" ? "À reconsolider" : "Acquis solides"}
          </div>
          <div style={{ display: "grid", gap: 11 }}>
            {items.map((m) => {
            const dom = window.QD.DOMAINS.find((d) => d.id === m.q.domain);
            return (
              <div key={m.q.id} style={{ fontSize: "var(--fs-sm)", lineHeight: 1.45 }}>
                  <div style={{ display: "flex", gap: 7, alignItems: "center", marginBottom: 3 }}>
                    <Pill tone={dom.pillar} style={{ padding: "2px 8px" }}>{dom.short}</Pill>
                  </div>
                  <div style={{ fontWeight: 600 }}>{m.q.text}</div>
                  {m.q.explain && <div className="muted" style={{ marginTop: 2 }}>{m.q.explain}</div>}
                </div>);

          })}
          </div>
        </div>}
    </div>);

}

function OverviewTab({ r, last, prev, flags }) {
  const series = [{ values: last.scores, color: "var(--color-env-500)", fill: "rgba(0,175,143,.16)" }];
  if (prev) series.unshift({ values: prev.scores, color: "var(--color-neutral-300)", fill: "rgba(0,0,0,.04)", dots: false });
  const insight = [
    { k: "misconception", label: "Idées fausses à corriger", desc: "réponses fausses, mais données avec assurance", tone: "danger", icon: "alert-triangle" },
    { k: "fragile", label: "Acquis fragiles", desc: "bonnes réponses, mais au doute ou au hasard", tone: "gov", icon: "eye" },
    { k: "mastered", label: "Vraiment maîtrisés", desc: "justes ET assumés", tone: "env", icon: "check-circle" },
  ];
  return (
    <div className="fade-up">
      <div style={{ display: "grid", gridTemplateColumns: "minmax(0,1.05fr) minmax(0,1fr)", gap: 24, marginBottom: 24 }}>
        <Card pad={22}>
          <h3 style={{ fontSize: "var(--fs-lg)", marginBottom: 16 }}>Niveau par thème</h3>
          <DomainBars scores={last.scores} compare={prev ? prev.scores : null} />
        </Card>
        <Card pad={20}>
          <h3 style={{ fontSize: "var(--fs-lg)", marginBottom: 4, textAlign: "center" }}>Radar des connaissances</h3>
          {prev && <div className="muted" style={{ fontSize: "var(--fs-xs)", textAlign: "center", marginBottom: 2 }}>
            <span style={{ color: "var(--color-neutral-400)" }}>● {QD.PHASES[QD.phaseOf(prev)].label}</span> &nbsp; <span style={{ color: "var(--color-env-600)" }}>● {QD.PHASES[QD.phaseOf(last)].label}</span></div>}
          <div style={{ display: "grid", placeItems: "center" }}><Radar size={356} series={series} /></div>
        </Card>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "repeat(3,1fr)", gap: 16, position: "relative" }}>
        {insight.map(it =>
          <InsightTile key={it.k} it={it} items={flags[it.k]} />
        )}
      </div>
    </div>
  );
}

function DiscoursTab({ last, flags, name, role, statut }) {
  const QD = window.QD;
  const ranked = QD.DOMAINS.map(d => ({ d, v: last.scores[d.id] })).filter(x => x.v != null).sort((a, b) => a.v - b.v);
  const first = name.split(" ")[0];
  const roleLabel = (QD.ROLES[role] || {}).label || "";
  const weakItems = ranked.filter(x => x.v < 60);
  const weakCount = weakItems.length;
  const focus = weakItems.map(x => x.d.short).join(" · ");
  const misTotal = flags.misconception.length;

  return (
    <div className="fade-up">
      {/* synthèse d'ouverture */}
      <Card pad={22} style={{ background: "var(--bg-inverse)", border: "none", color: "#fff", marginBottom: 22 }}>
        <div style={{ display: "flex", gap: 14, alignItems: "flex-start" }}>
          <Icon name="message-circle" size={24} color="var(--color-env-300)" />
          <div>
            <div style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: "var(--fs-lg)", marginBottom: 6 }}>
              Comment caler ton discours avec {first}
            </div>
            <p style={{ color: "rgba(255,255,255,.82)", fontSize: "var(--fs-sm)", lineHeight: 1.55 }}>
              {weakCount === 0
                ? "Profil " + roleLabel + " solide sur tous les thèmes : tu peux aller vite et le mettre en situation réelle. Les fiches ci-dessous, du plus fragile au plus solide, te donnent les angles concrets — théorie → pratique."
                : "Profil " + roleLabel + ". " + weakCount + (weakCount > 1 ? " thèmes" : " thème") + " à renforcer en priorité" + (focus ? " : " + focus : "") + ". Insiste sur le haut de liste, survole le bas. Chaque fiche détaille les gestes de coaching et les notions précises à faire passer."}
              {misTotal > 0 ? " " + misTotal + (misTotal > 1 ? " idées fausses sont" : " idée fausse est") + " à corriger explicitement (en rouge ci-dessous)." : ""}
            </p>
          </div>
        </div>
      </Card>

      <div style={{ display: "grid", gap: 16 }}>
        {ranked.map(({ d, v }, idx) => {
          const weak = v < 60;
          const reco = QD.recoFor(d.id, role, weak) || { headline: "", actions: [] };
          const mis = flags.misconception.filter(f => f.q.domain === d.id);
          return (
            <Card key={d.id} pad={0} style={{ overflow: "hidden", borderLeft: `4px solid ${weak ? "var(--color-gov-500)" : "var(--color-env-500)"}` }}>
              {/* en-tête fiche */}
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12, padding: "16px 20px", borderBottom: "1px solid var(--border-default)", background: weak ? "var(--color-gov-100)" : "var(--color-env-100)" }}>
                <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
                  <span style={{ width: 26, height: 26, borderRadius: "50%", background: weak ? "var(--color-gov-500)" : "var(--color-env-600)", color: "#fff", display: "grid", placeItems: "center", fontFamily: "var(--font-display)", fontWeight: 800, fontSize: "var(--fs-xs)", flex: "none" }}>{idx + 1}</span>
                  <div style={{ fontWeight: 700, fontSize: "var(--fs-md)" }}>{d.label}</div>
                </div>
                <Pill tone={weak ? "gov" : "env"}>{v}% · {weak ? "à renforcer" : "acquis"}</Pill>
              </div>

              <div style={{ padding: "18px 20px" }}>
                <p style={{ fontSize: "var(--fs-base)", lineHeight: 1.5, color: "var(--fg-default)", fontWeight: 600, marginBottom: reco.actions && reco.actions.length ? 16 : 0 }}>{reco.headline}</p>

                {/* gestes de coaching */}
                {reco.actions && reco.actions.length > 0 && (
                  <div style={{ display: "grid", gap: 10 }}>
                    {reco.actions.map((a, i) => (
                      <div key={i} style={{ display: "flex", gap: 10, alignItems: "flex-start" }}>
                        <Icon name={weak ? "arrow-right" : "check"} size={16} color={weak ? "var(--color-gov-600)" : "var(--color-env-600)"} style={{ marginTop: 3, flex: "none" }} />
                        <span style={{ fontSize: "var(--fs-sm)", lineHeight: 1.55, color: "var(--fg-default)" }}>{a}</span>
                      </div>
                    ))}
                  </div>
                )}

                {/* notions à driller */}
                {reco.points && reco.points.length > 0 && (
                  <div style={{ marginTop: 16, paddingTop: 14, borderTop: "1px dashed var(--border-strong)" }}>
                    <div style={{ display: "flex", gap: 6, alignItems: "center", fontSize: "var(--fs-xs)", fontWeight: 700, letterSpacing: ".02em", textTransform: "uppercase", color: "var(--fg-muted)", marginBottom: 10 }}>
                      <Icon name="target" size={14} /> Notions précises à faire passer
                    </div>
                    <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
                      {reco.points.map((p, i) => (
                        <span key={i} style={{ fontSize: "var(--fs-sm)", lineHeight: 1.4, padding: "7px 12px", borderRadius: "var(--r-md)", background: "var(--color-neutral-50)", border: "1px solid var(--border-default)", color: "var(--fg-default)" }}>{p}</span>
                      ))}
                    </div>
                  </div>
                )}

                {/* idées fausses repérées */}
                {mis.length > 0 && (
                  <div style={{ marginTop: 16, padding: "12px 14px", borderRadius: "var(--r-md)", background: "var(--danger-bg)", border: "1px solid #f6c8c4" }}>
                    <div style={{ display: "flex", gap: 7, alignItems: "center", fontWeight: 700, fontSize: "var(--fs-xs)", color: "var(--danger-fg)", marginBottom: 7 }}>
                      <Icon name="alert-triangle" size={14} /> Idée fausse assumée — à corriger explicitement
                    </div>
                    {mis.map(m => (
                      <div key={m.q.id} style={{ fontSize: "var(--fs-sm)", color: "var(--fg-default)", marginTop: 4, lineHeight: 1.5 }}>
                        <strong>« {m.q.text} »</strong>
                        {m.q.explain && <span className="muted"> — {m.q.explain}</span>}
                      </div>
                    ))}
                  </div>
                )}
              </div>
            </Card>
          );
        })}
      </div>
    </div>
  );
}

function AnswersTab({ attempt, prev }) {
  const QD = window.QD, qById = window.Store.qById;
  const ids = attempt.quizIds.filter(id => qById[id]);
  const certLabel = { sure: "Sûr·e", mid: "Mitigé·e", guess: "Au hasard" };
  // questions ratées à J0 (présentes dans l'essai précédent et fausses) → marquées « reposées »
  const retakeWrong = prev ? new Set(Object.keys(prev.answers).filter(qid => {
    const q = qById[qid], a = prev.answers[qid];
    return q && q.type !== "selfrate" && a && a.correct === false;
  })) : new Set();
  return (
    <div className="fade-up" style={{ display: "grid", gap: 12 }}>
      {ids.map(id => {
        const q = qById[id], a = attempt.answers[id];
        const dom = QD.DOMAINS.find(d => d.id === q.domain);
        if (q.type === "selfrate") {
          const rl = { maitrise: "« Je saurais l'expliquer »", idee: "« J'en ai une idée, flou »", nouveau: "« Nouveau pour moi »" };
          return (
            <Card key={id} pad={16} style={{ background: "var(--color-neutral-25)" }}>
              <div style={{ display: "flex", gap: 8, alignItems: "center", marginBottom: 6, flexWrap: "wrap" }}>
                <Pill tone={dom.pillar} style={{ padding: "3px 9px" }}>{dom.short}</Pill>
                <Pill tone="neutral" style={{ padding: "3px 9px" }}>Auto-évaluation</Pill>
              </div>
              <div style={{ fontWeight: 600, marginBottom: 4 }}>{q.text}</div>
              <div className="muted" style={{ fontSize: "var(--fs-sm)" }}>Déclaré&nbsp;: <strong style={{ color: "var(--fg-default)" }}>{rl[a?.rate] || "—"}</strong></div>
            </Card>
          );
        }
        if (q.type === "free") {
          return (
            <Card key={id} pad={16} style={{ background: "var(--color-neutral-25)" }}>
              <div style={{ display: "flex", gap: 8, alignItems: "center", marginBottom: 6, flexWrap: "wrap" }}>
                <Pill tone={dom.pillar} style={{ padding: "3px 9px" }}>{dom.short}</Pill>
                <Pill tone="neutral" style={{ padding: "3px 9px" }}>Réponse libre</Pill>
              </div>
              <div style={{ fontWeight: 600, marginBottom: 6 }}>{q.text}</div>
              <div className="muted" style={{ fontSize: "var(--fs-sm)", lineHeight: 1.5, whiteSpace: "pre-wrap" }}>
                {a?.text && a.text.trim() ? a.text : <em>Pas de réponse saisie.</em>}
              </div>
              {q.model &&
                <div className="muted" style={{ fontSize: "var(--fs-sm)", marginTop: 8, paddingTop: 8, borderTop: "1px dashed var(--border-strong)", lineHeight: 1.5 }}>
                  <strong style={{ color: "var(--color-env-700)" }}>Repère&nbsp;:</strong> {q.model}
                </div>}
            </Card>
          );
        }
        const ok = a?.correct;
        const okIdx = q.type === "qcm" ? q.options.findIndex(o => o.ok) : null;
        const chosen = q.type === "qcm" ? (a?.choice != null ? q.options[a.choice].t : "—") : (a?.choice ? "Vrai" : "Faux");
        const right = q.type === "qcm" ? q.options[okIdx].t : (q.answer ? "Vrai" : "Faux");
        return (
          <Card key={id} pad={18} style={{ borderColor: ok ? "var(--color-env-200)" : "#f6c8c4" }}>
            <div style={{ display: "flex", gap: 12, alignItems: "flex-start" }}>
              <Icon name={ok ? "check-circle" : "x-circle"} size={22} color={ok ? "var(--color-env-600)" : "var(--danger-500)"} style={{ marginTop: 2 }} />
              <div style={{ flex: 1 }}>
                <div style={{ display: "flex", gap: 8, alignItems: "center", marginBottom: 7, flexWrap: "wrap" }}>
                  <Pill tone={dom.pillar} style={{ padding: "3px 9px" }}>{dom.short}</Pill>
                  {retakeWrong.has(id) && <Pill tone={ok ? "env" : "danger"} style={{ padding: "3px 9px" }}><Icon name="refresh" size={12} />Reposée · ratée à J0</Pill>}
                  <Pill tone={a?.certainty === "sure" ? (ok ? "env" : "danger") : "neutral"} style={{ padding: "3px 9px" }}>Certitude&nbsp;: {certLabel[a?.certainty] || "—"}</Pill>
                </div>
                <div style={{ fontWeight: 600, marginBottom: 8 }}>{q.text}</div>
                <div style={{ fontSize: "var(--fs-sm)", display: "grid", gap: 3 }}>
                  <div>Sa réponse&nbsp;: <strong style={{ color: ok ? "var(--color-env-700)" : "var(--danger-fg)" }}>{chosen}</strong></div>
                  {!ok && <div className="muted">Bonne réponse&nbsp;: <strong style={{ color: "var(--color-env-700)" }}>{right}</strong></div>}
                </div>
                <div className="muted" style={{ fontSize: "var(--fs-sm)", marginTop: 8, paddingTop: 8, borderTop: "1px dashed var(--border-strong)", lineHeight: 1.5 }}>{q.explain}</div>
              </div>
            </div>
          </Card>
        );
      })}
    </div>
  );
}

function ROLE_LABEL(role) { return (window.QD.ROLES[role] || {}).label || role; }

// Statut de validation d'un thème à J+15 (en tenant compte du niveau atteint + progression)
function themeStatus(j0, j15) {
  if (j15 == null) return { key: "na", label: "—", tone: "neutral" };
  if (j15 >= 68) return { key: "valide", label: "Acquis validé", tone: "env" };
  if (j15 >= 45) return { key: "progres", label: "En progrès", tone: "soc" };
  return { key: "fragile", label: "À consolider", tone: "gov" };
}

// Bilan téléchargeable (HTML autonome, imprimable en PDF)
function buildBilanHTML(r, prev, last) {
  const QD = window.QD;
  const logo = (window.__resources && window.__resources.logoColor) || "assets/logo-enso.png";
  const fmt = iso => { try { return new Date(iso).toLocaleDateString("fr-FR", { day: "numeric", month: "long", year: "numeric" }); } catch (e) { return ""; } };
  const lvl0 = QD.levelFor(prev.global), lvl15 = QD.levelFor(last.global);
  const delta = last.global - prev.global;

  // re-test des questions ratées à J0
  const qById = window.Store.qById;
  const wrong0 = Object.keys(prev.answers).filter(qid => { const q = qById[qid], a = prev.answers[qid]; return q && q.type !== "selfrate" && a && a.correct === false; });
  const reposed = wrong0.filter(qid => last.quizIds.includes(qid));
  const reposedOk = reposed.filter(qid => last.answers[qid] && last.answers[qid].correct);

  const rows = QD.DOMAINS.map(d => {
    const v0 = prev.scores[d.id], v15 = last.scores[d.id];
    const st = themeStatus(v0, v15);
    const dl = (v0 != null && v15 != null) ? v15 - v0 : null;
    const toneCol = { env: "#00997D", soc: "#8F0DF2", gov: "#F7703B", neutral: "#6C746F" }[st.tone];
    return `<tr>
      <td class="th">${d.label}</td>
      <td class="num">${v0 == null ? "—" : v0 + "%"}</td>
      <td class="num">${v15 == null ? "—" : "<strong>" + v15 + "%</strong>"}</td>
      <td class="num" style="color:${dl == null ? "#8C9590" : dl >= 0 ? "#00997D" : "#D92D20"}">${dl == null ? "—" : (dl >= 0 ? "▲ +" : "▼ ") + Math.abs(dl)}</td>
      <td><span class="badge" style="color:${toneCol};border-color:${toneCol}33;background:${toneCol}14">${st.label}</span></td>
    </tr>`;
  }).join("");

  const validated = QD.DOMAINS.filter(d => themeStatus(prev.scores[d.id], last.scores[d.id]).key === "valide").length;

  return `<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><title>Bilan de validation des acquis — ${r.name}</title>
<style>
  @page { margin: 18mm; }
  * { box-sizing: border-box; }
  body { font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; color: #1F2622; margin: 0; padding: 40px; background: #fff; line-height: 1.5; }
  .wrap { max-width: 820px; margin: 0 auto; }
  header { display: flex; justify-content: space-between; align-items: flex-start; border-bottom: 3px solid #00AF8F; padding-bottom: 18px; margin-bottom: 26px; }
  .logo { height: 34px; }
  .doc-tag { text-transform: uppercase; letter-spacing: .18em; font-size: 11px; font-weight: 700; color: #006956; }
  h1 { font-size: 26px; margin: 4px 0 0; letter-spacing: -.01em; }
  .meta { color: #4E5752; font-size: 14px; margin-top: 8px; }
  .meta strong { color: #1F2622; }
  .right { text-align: right; }
  .verdict { display: flex; gap: 16px; align-items: stretch; margin: 8px 0 28px; }
  .vcard { flex: 1; border: 1px solid #E9EDEB; border-radius: 14px; padding: 18px 20px; }
  .vcard .k { font-size: 12px; color: #6C746F; text-transform: uppercase; letter-spacing: .06em; }
  .vcard .big { font-size: 34px; font-weight: 800; line-height: 1.1; margin-top: 4px; }
  .vcard .sub { font-size: 13px; color: #4E5752; }
  .arrow { align-self: center; font-size: 26px; color: #B6BFB9; }
  table { width: 100%; border-collapse: collapse; margin-top: 8px; }
  th, td { text-align: left; padding: 11px 10px; font-size: 14px; border-bottom: 1px solid #E9EDEB; }
  thead th { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: #6C746F; border-bottom: 2px solid #D6DCD8; }
  td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
  td.th { font-weight: 600; }
  .badge { display: inline-block; padding: 3px 10px; border-radius: 999px; font-size: 12px; font-weight: 700; border: 1px solid; white-space: nowrap; }
  h2 { font-size: 16px; margin: 30px 0 10px; }
  .note { background: #F5FFFC; border: 1px solid #D7F4EE; border-radius: 12px; padding: 14px 18px; font-size: 14px; color: #1F2622; }
  .foot { margin-top: 34px; padding-top: 14px; border-top: 1px solid #E9EDEB; font-size: 12px; color: #8C9590; display: flex; justify-content: space-between; }
  @media print { body { padding: 0; } .noprint { display: none; } }
</style></head>
<body><div class="wrap">
  <header>
    <div>
      <div class="doc-tag">Bilan de validation des acquis</div>
      <h1>${r.name}</h1>
      <div class="meta">${ROLE_LABEL(r.role)} · ${(QD.STATUTS[r.statut] || {}).label || ""}</div>
    </div>
    <div class="right"><img src="${logo}" class="logo" alt="ensō rse"><div class="meta" style="margin-top:10px">Quizz J0 · ${fmt(prev.date)}<br>Quizz J+15 · ${fmt(last.date)}</div></div>
  </header>

  <div class="verdict">
    <div class="vcard"><div class="k">Niveau à J0</div><div class="big" style="color:#6C746F">${prev.global}%</div><div class="sub">${lvl0.label}</div></div>
    <div class="arrow">→</div>
    <div class="vcard" style="border-color:${lvl15.color}55;background:${lvl15.color}0d"><div class="k">Niveau à J+15</div><div class="big" style="color:${lvl15.color}">${last.global}%</div><div class="sub" style="color:${lvl15.color}">${lvl15.label}</div></div>
    <div class="vcard"><div class="k">Progression</div><div class="big" style="color:${delta >= 0 ? "#00997D" : "#D92D20"}">${delta >= 0 ? "+" : ""}${delta}</div><div class="sub">points · ${validated}/${QD.DOMAINS.length} thèmes validés</div></div>
  </div>

  <h2>Validation des acquis par thème</h2>
  <table>
    <thead><tr><th>Thème</th><th class="num">J0</th><th class="num">J+15</th><th class="num">Évolution</th><th>Statut</th></tr></thead>
    <tbody>${rows}</tbody>
  </table>

  <h2>Re-test des questions manquées à J0</h2>
  <div class="note">${reposed.length === 0 ? "Aucune question n'avait été manquée à J0." : `Sur les <strong>${wrong0.length}</strong> question(s) manquée(s) à J0, <strong>${reposed.length}</strong> ont été reposées à J+15 — dont <strong>${reposedOk.length}</strong> désormais réussie(s)${reposed.length ? ` (${Math.round(reposedOk.length / reposed.length * 100)}% de correction)` : ""}.`}</div>

  <div class="foot"><span>ensō rse · Bilan d'onboarding</span><span>Édité le ${fmt(new Date().toISOString())}</span></div>
</div></body></html>`;
}

function downloadBilan(r, prev, last) {
  const html = buildBilanHTML(r, prev, last);
  const blob = new Blob([html], { type: "text/html;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = `Bilan acquis - ${r.name} - J+15.html`;
  document.body.appendChild(a); a.click(); document.body.removeChild(a);
  setTimeout(() => URL.revokeObjectURL(url), 2000);
}

// Une ligne de comparaison J0 / J+15 pour un thème — deux barres distinctes et étiquetées.
function ThemeCompareRow({ d, v0, v15 }) {
  const col = window.PILLAR_COLOR[d.pillar];
  const st = themeStatus(v0, v15);
  const dl = (v0 != null && v15 != null) ? v15 - v0 : null;
  const Bar = ({ label, val, color, faded }) => (
    <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
      <span style={{ width: 42, flex: "none", fontSize: "var(--fs-xs)", fontWeight: 700, letterSpacing: ".02em", color: faded ? "var(--fg-subtle)" : "var(--fg-muted)" }}>{label}</span>
      <div style={{ flex: 1, height: 12, borderRadius: 999, background: "var(--color-neutral-100)", overflow: "hidden" }}>
        <div style={{ height: "100%", width: (val || 0) + "%", background: color, borderRadius: 999, transition: "width .8s var(--ease-out)" }} />
      </div>
      <span style={{ width: 42, flex: "none", textAlign: "right", fontWeight: 700, fontSize: "var(--fs-sm)", fontVariantNumeric: "tabular-nums", color: faded ? "var(--fg-subtle)" : "var(--fg-default)" }}>{val == null ? "—" : val + "%"}</span>
    </div>
  );
  return (
    <div style={{ padding: "14px 0", borderBottom: "1px solid var(--border-default)" }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 10, gap: 12 }}>
        <span style={{ fontWeight: 700, fontSize: "var(--fs-base)" }}>{d.label}</span>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          {dl != null && <span style={{ fontSize: "var(--fs-sm)", fontWeight: 700, color: dl >= 0 ? "var(--color-env-600)" : "var(--danger-500)" }}>{dl >= 0 ? "▲ +" : "▼ "}{Math.abs(dl)} pts</span>}
          <Pill tone={st.tone} style={{ padding: "3px 10px" }}>{st.label}</Pill>
        </div>
      </div>
      <div style={{ display: "grid", gap: 7 }}>
        <Bar label="J0" val={v0} color="var(--color-neutral-300)" faded />
        <Bar label="J+15" val={v15} color={col} />
      </div>
    </div>
  );
}

function ProgressTab({ r, prev, last }) {
  const QD = window.QD;
  const delta = last.global - prev.global;
  const validated = QD.DOMAINS.filter(d => themeStatus(prev.scores[d.id], last.scores[d.id]).key === "valide").length;
  const total = QD.DOMAINS.length;
  return (
    <div className="fade-up">
      <Card pad={26} style={{ marginBottom: 22, display: "flex", alignItems: "center", justifyContent: "space-around", flexWrap: "wrap", gap: 20 }}>
        <div style={{ textAlign: "center" }}>
          <div className="muted" style={{ fontSize: "var(--fs-sm)", marginBottom: 4 }}>Quizz {QD.PHASES[QD.phaseOf(prev)].label} · {fmtDate(prev.date)}</div>
          <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: "var(--fs-3xl)", color: "var(--fg-muted)" }}>{prev.global}%</div>
          <div className="muted" style={{ fontSize: "var(--fs-sm)" }}>{QD.levelFor(prev.global).label}</div>
        </div>
        <Icon name="arrow-right" size={28} color="var(--fg-subtle)" />
        <div style={{ textAlign: "center" }}>
          <div className="muted" style={{ fontSize: "var(--fs-sm)", marginBottom: 4 }}>Quizz {QD.PHASES[QD.phaseOf(last)].label} · {fmtDate(last.date)}</div>
          <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: "var(--fs-3xl)", color: QD.levelFor(last.global).color }}>{last.global}%</div>
          <div style={{ fontSize: "var(--fs-sm)", color: QD.levelFor(last.global).color }}>{QD.levelFor(last.global).label}</div>
        </div>
        <Pill tone={delta >= 0 ? "env" : "gov"} style={{ fontSize: "var(--fs-md)", padding: "10px 18px" }}>
          <Icon name="trending-up" size={18} /> {delta >= 0 ? "+" : ""}{delta} points
        </Pill>
      </Card>

      {/* bilan de validation téléchargeable */}
      <Card pad={0} style={{ marginBottom: 22, overflow: "hidden", background: "var(--bg-inverse)", border: "none", color: "#fff" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 18, padding: "20px 24px", flexWrap: "wrap" }}>
          <div style={{ width: 52, height: 52, borderRadius: 14, background: "rgba(255,255,255,.12)", display: "grid", placeItems: "center", flex: "none" }}>
            <Icon name="award" size={26} color="var(--color-env-300)" />
          </div>
          <div style={{ flex: 1, minWidth: 220 }}>
            <div style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: "var(--fs-lg)" }}>Bilan de validation des acquis</div>
            <div style={{ color: "rgba(255,255,255,.78)", fontSize: "var(--fs-sm)", marginTop: 3 }}>
              {validated}/{total} thème{validated > 1 ? "s" : ""} validé{validated > 1 ? "s" : ""} · {delta >= 0 ? "+" : ""}{delta} pts entre J0 et J+15. Document à archiver ou partager (imprimable en PDF).
            </div>
          </div>
          <Btn variant="primary" icon="download" onClick={() => downloadBilan(r, prev, last)}>Télécharger le bilan</Btn>
        </div>
      </Card>

      <Card pad={22}>
        <h3 style={{ fontSize: "var(--fs-lg)", marginBottom: 6 }}>Ce qui a infusé, thème par thème</h3>
        <div style={{ display: "flex", alignItems: "center", gap: 18, marginBottom: 8, flexWrap: "wrap" }}>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 7, fontSize: "var(--fs-sm)", color: "var(--fg-muted)" }}>
            <span style={{ width: 22, height: 10, borderRadius: 999, background: "var(--color-neutral-300)" }} /> Quizz J0
          </span>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 7, fontSize: "var(--fs-sm)", color: "var(--fg-muted)" }}>
            <span style={{ width: 22, height: 10, borderRadius: 999, background: "var(--color-env-500)" }} /> Quizz J+15
          </span>
        </div>
        <div>
          {QD.DOMAINS.map(d => (
            <ThemeCompareRow key={d.id} d={d} v0={prev.scores[d.id]} v15={last.scores[d.id]} />
          ))}
        </div>
      </Card>
    </div>
  );
}

Object.assign(window, { ManagerHome, RecruitDetail });
