// screens-test.jsx — DISC, IQ, Member Area

const DISC_SEC = 15; // detik per soal

function DiscScreen({ t, lang, state, setState, onNext, layout }) {
  const allGroups = window.APPDATA.disc;
  const [idx,  setIdx]  = useState(0);
  const [warn, setWarn] = useState(false);
  const [left, setLeft] = useState(DISC_SEC);

  // Clear previous answers and generate a new random seed on mount
  useEffect(() => {
    const seed = Math.floor(Math.random() * 0xFFFFFFFF);
    setState((s) => ({ ...s, disc: {}, discResult: undefined, discScore: undefined, discSeed: seed }));
  }, []);

  // Shuffled group order — stable for this session (seed stored in state)
  const seed = state.discSeed || 1;
  const order = useMemo(() => seededShuffle(allGroups.map((_, i) => i), seed), [seed]);
  const groups = order.map(i => allGroups[i]);

  const answers = state.disc || {};
  const cur = answers[idx] || {};

  // Reset timer setiap ganti soal
  useEffect(() => { setLeft(DISC_SEC); }, [idx]);

  // Countdown per soal
  useEffect(() => {
    if (left <= 0) {
      if (idx < groups.length - 1) { setWarn(false); setIdx((i) => i + 1); }
      else computeAndFinish();
      return;
    }
    const tm = setTimeout(() => setLeft((l) => l - 1), 1000);
    return () => clearTimeout(tm);
  }, [left]);

  function pick(kind, wordIdx) {
    setWarn(false);
    setState((s) => {
      const a = { ...(s.disc || {}) };
      const g = { ...(a[idx] || {}) };
      if (kind === "most"  && g.least === wordIdx) g.least = undefined;
      if (kind === "least" && g.most  === wordIdx) g.most  = undefined;
      g[kind] = wordIdx;
      a[idx] = g;
      return { ...s, disc: a };
    });
  }

  function next() {
    if (cur.most === undefined || cur.least === undefined) { setWarn(true); return; }
    if (idx < groups.length - 1) { setIdx(idx + 1); }
    else { computeAndFinish(); }
  }

  function computeAndFinish() {
    const score = { D: 0, I: 0, S: 0, C: 0 };
    groups.forEach((g, gi) => {
      const a = answers[gi] || {};
      if (a.most  !== undefined) score[g[a.most].d]  += 2;
      if (a.least !== undefined) score[g[a.least].d] -= 1;
    });
    const top = Object.entries(score).sort((x, y) => y[1] - x[1])[0][0];
    setState((s) => ({ ...s, discResult: top, discScore: score }));
    onNext({ discResult: top, discScore: score });
  }

  const pct      = Math.round((idx / groups.length) * 100);
  const fullbleed = layout === "fullbleed";
  const timerColor = left <= 5 ? "var(--danger)" : left <= 8 ? "#d97706" : "var(--brand)";
  const timerPct   = (left / DISC_SEC) * 100;

  return (
    <div className="center-wrap">
      <div className={fullbleed ? "col-mid fadein" : "col-mid card card-pad fadein"}>
        <div className="disc-head">
          <div>
            <div className="eyebrow">{t.discEyebrow}</div>
            <h1 className="title" style={{ margin: "8px 0 0" }}>{t.discTitle}</h1>
          </div>
          <div style={{ display:"flex", alignItems:"center", gap:14 }}>
            <span style={{ display:"flex", alignItems:"center", gap:6, fontWeight:700, color:timerColor, fontSize:15 }}>
              <svg width="28" height="28" viewBox="0 0 36 36" style={{ transform:"rotate(-90deg)" }}>
                <circle cx="18" cy="18" r="15" fill="none" stroke="var(--line)" strokeWidth="3"/>
                <circle cx="18" cy="18" r="15" fill="none" stroke={timerColor} strokeWidth="3"
                  strokeDasharray={`${2*Math.PI*15}`}
                  strokeDashoffset={`${2*Math.PI*15*(1-timerPct/100)}`}
                  style={{ transition:"stroke-dashoffset 1s linear, stroke .3s" }}/>
              </svg>
              {left}s
            </span>
            <div className="disc-prog">{t.group} {idx + 1} {t.of} {groups.length}</div>
          </div>
        </div>
        <p className="sub">{t.discSub}</p>

        <div className="iq-track" style={{ marginTop: 14 }}>
          <div className="iq-fill" style={{ width: pct + "%" }} />
        </div>

        <div className="disc-colhead" style={{ marginTop: 20 }}>
          <span />
          <span className="ch most">{t.discMost}</span>
          <span className="ch least">{t.discLeast}</span>
        </div>
        <div className="disc-table">
          {groups[idx].map((w, wi) => (
            <div className="disc-row" key={wi} style={{
              borderColor: cur.most === wi ? "var(--success)" : cur.least === wi ? "var(--danger)" : "var(--line)"
            }}>
              <span className="word">{w[lang]}</span>
              <button className={`disc-pick most ${cur.most  === wi ? "on" : ""}`} onClick={() => pick("most",  wi)}><Icon name="check" size={16} /></button>
              <button className={`disc-pick least ${cur.least === wi ? "on" : ""}`} onClick={() => pick("least", wi)}><Icon name="x"     size={15} /></button>
            </div>
          ))}
        </div>

        {warn && <div className="err" style={{ marginTop: 12 }}>{t.discPickBoth}</div>}

        <div className="flexbtns">
          {idx > 0 && <Button variant="ghost" icon="arrowL" onClick={() => setIdx(idx - 1)}>{t.back}</Button>}
          <span className="grow" />
          <Button lg iconR={idx < groups.length - 1 ? "arrow" : "check"} onClick={next}>
            {idx < groups.length - 1 ? t.discNext : t.discFinish}
          </Button>
        </div>
      </div>
    </div>
  );
}

const IQ_SEC = 35; // detik per soal

// ── Cell SVG renderer untuk soal matriks gambar ────────────────────────────
function cellSvg(desc, size = 44) {
  const cx = size / 2, cy = size / 2;
  if (!desc) return `<svg viewBox="0 0 ${size} ${size}"><text x="${cx}" y="${cy+8}" text-anchor="middle" font-size="22" fill="#bbb">?</text></svg>`;

  if (desc.t === "ar") {
    const map = { e:"→", se:"↘", s:"↓", sw:"↙", w:"←", nw:"↖", n:"↑", ne:"↗" };
    return `<svg viewBox="0 0 ${size} ${size}"><text x="${cx}" y="${cy+10}" text-anchor="middle" font-size="${Math.round(size*0.62)}" fill="currentColor">${map[desc.d]||"?"}</text></svg>`;
  }

  if (desc.t === "dots") {
    const n = Math.min(desc.n, 6), r = size * 0.11;
    const pos = {
      1: [[cx,cy]],
      2: [[cx-r*1.5,cy],[cx+r*1.5,cy]],
      3: [[cx-r*1.5,cy-r],[cx+r*1.5,cy-r],[cx,cy+r*1.2]],
      4: [[cx-r*1.3,cy-r*1.3],[cx+r*1.3,cy-r*1.3],[cx-r*1.3,cy+r*1.3],[cx+r*1.3,cy+r*1.3]],
      5: [[cx-r*1.4,cy-r*1.4],[cx+r*1.4,cy-r*1.4],[cx-r*1.4,cy+r*1.4],[cx+r*1.4,cy+r*1.4],[cx,cy]],
      6: [[cx-r*1.4,cy-r*1.6],[cx+r*1.4,cy-r*1.6],[cx-r*1.4,cy],[cx+r*1.4,cy],[cx-r*1.4,cy+r*1.6],[cx+r*1.4,cy+r*1.6]],
    };
    const circles = (pos[n]||pos[1]).map(([x,y]) => `<circle cx="${x.toFixed(1)}" cy="${y.toFixed(1)}" r="${r}" fill="currentColor"/>`).join('');
    return `<svg viewBox="0 0 ${size} ${size}">${circles}</svg>`;
  }

  if (desc.t === "sh") {
    const sz = [0.22,0.35,0.48][desc.sz-1] * size;
    const fill = desc.f ? "currentColor" : "none";
    const sw = 2;
    if (desc.s === "cir") return `<svg viewBox="0 0 ${size} ${size}"><circle cx="${cx}" cy="${cy}" r="${sz}" fill="${fill}" stroke="currentColor" stroke-width="${sw}"/></svg>`;
    if (desc.s === "sq")  return `<svg viewBox="0 0 ${size} ${size}"><rect x="${(cx-sz).toFixed(1)}" y="${(cy-sz).toFixed(1)}" width="${(sz*2).toFixed(1)}" height="${(sz*2).toFixed(1)}" fill="${fill}" stroke="currentColor" stroke-width="${sw}"/></svg>`;
    if (desc.s === "tri") return `<svg viewBox="0 0 ${size} ${size}"><polygon points="${cx},${cy-sz} ${cx-sz},${cy+sz*0.7} ${cx+sz},${cy+sz*0.7}" fill="${fill}" stroke="currentColor" stroke-width="${sw}"/></svg>`;
    if (desc.s === "dia") return `<svg viewBox="0 0 ${size} ${size}"><polygon points="${cx},${cy-sz} ${cx+sz},${cy} ${cx},${cy+sz} ${cx-sz},${cy}" fill="${fill}" stroke="currentColor" stroke-width="${sw}"/></svg>`;
  }

  if (desc.t === "multi") {
    const n = desc.n, s = [0.17,0.14,0.12][n-1] * size;
    const xp = n === 1 ? [cx] : n === 2 ? [cx-s*1.3,cx+s*1.3] : [cx-s*1.5,cx,cx+s*1.5];
    const shapes = xp.map(x => {
      if (desc.s === "cir") return `<circle cx="${x}" cy="${cy}" r="${s}" fill="currentColor"/>`;
      if (desc.s === "sq")  return `<rect x="${x-s}" y="${cy-s}" width="${s*2}" height="${s*2}" fill="currentColor"/>`;
      if (desc.s === "tri") return `<polygon points="${x},${cy-s} ${x-s},${cy+s*0.7} ${x+s},${cy+s*0.7}" fill="currentColor"/>`;
      return '';
    }).join('');
    return `<svg viewBox="0 0 ${size} ${size}">${shapes}</svg>`;
  }

  if (desc.t === "line") {
    const rad = desc.a * Math.PI / 180, len = size * 0.38;
    const x1 = (cx - Math.cos(rad)*len).toFixed(1), y1 = (cy - Math.sin(rad)*len).toFixed(1);
    const x2 = (cx + Math.cos(rad)*len).toFixed(1), y2 = (cy + Math.sin(rad)*len).toFixed(1);
    return `<svg viewBox="0 0 ${size} ${size}"><line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="currentColor" stroke-width="3" stroke-linecap="round"/></svg>`;
  }

  if (desc.t === "pos") {
    const row = Math.floor(desc.pos / 3), col = desc.pos % 3;
    const cw = size / 3;
    const px = (col * cw + cw/2).toFixed(1), py = (row * cw + cw/2 + cw*0.3).toFixed(1);
    return `<svg viewBox="0 0 ${size} ${size}"><text x="${px}" y="${py}" text-anchor="middle" font-size="${Math.round(cw*0.8)}" fill="currentColor">${desc.sym||"★"}</text></svg>`;
  }

  return `<svg viewBox="0 0 ${size} ${size}"><text x="${cx}" y="${cy+5}" text-anchor="middle" font-size="14" fill="currentColor">?</text></svg>`;
}

function IqScreen({ t, lang, state, setState, onNext, layout }) {
  const allQ   = window.APPDATA.iq;
  const allFig = window.APPDATA.iqFig || [];
  const [started, setStarted] = useState(false);
  const [idx,     setIdx]     = useState(0);
  const [left,    setLeft]    = useState(IQ_SEC);

  // Clear previous answers and generate new seed on mount
  useEffect(() => {
    const seed = Math.floor(Math.random() * 0xFFFFFFFF);
    setState((s) => ({ ...s, iq: {}, iqResult: undefined, iqCorrect: undefined, iqSeed: seed }));
  }, []);

  const seed = state.iqSeed || 1;

  // 15 soal teks acak + 5 soal visual acak = 20 soal total, diacak bersama
  const Q = useMemo(() => {
    const textOrder = seededShuffle(allQ.map((_,i)=>i), seed);
    const textPick  = textOrder.slice(0, 15).map(i => allQ[i]);
    const figOrder  = seededShuffle(allFig.map((_,i)=>i), seed ^ 0xABCD);
    const figPick   = figOrder.slice(0, Math.min(5, allFig.length)).map(i => allFig[i]);
    const combined  = [...textPick, ...figPick];
    return seededShuffle(combined.map((_,i)=>i), seed ^ 0x1234).map(i => combined[i]);
  }, [seed]);

  const answers = state.iq || {};

  // Reset timer setiap ganti soal
  useEffect(() => { if (started) setLeft(IQ_SEC); }, [idx]);

  // Countdown per soal
  useEffect(() => {
    if (!started) return;
    if (left <= 0) {
      // Waktu habis: pindah soal berikutnya atau selesai
      if (idx < Q.length - 1) setIdx((i) => i + 1);
      else finish();
      return;
    }
    const tm = setTimeout(() => setLeft((l) => l - 1), 1000);
    return () => clearTimeout(tm);
  }, [started, left]);

  function answer(qi, oi) {
    setState((s) => ({ ...s, iq: { ...(s.iq || {}), [qi]: oi } }));
  }
  function nextQ() {
    if (idx < Q.length - 1) setIdx((i) => i + 1);
    else finish();
  }
  function finish() {
    const snap = state.iq || {};
    let correct = 0;
    Q.forEach((q, i) => { if (snap[i] === q.a) correct++; });
    const iqScore = Math.round(90 + (correct / Q.length) * 45);
    setState((s) => ({ ...s, iqResult: iqScore, iqCorrect: correct }));
    onNext({ iqResult: iqScore, iqCorrect: correct });
  }
  function submit() { if (confirm(t.iqConfirm)) finish(); }

  const answered = Object.keys(answers).length;
  // Warna timer: hijau > 17, kuning 9-17, merah ≤ 8
  const timerColor = left <= 8 ? "var(--danger)" : left <= 17 ? "#d97706" : "var(--brand)";
  const timerPct   = (left / IQ_SEC) * 100;

  if (!started) {
    return (
      <div className="center-wrap">
        <div className="col-narrow card card-pad fadein tcenter">
          <div className="done-check" style={{ background: "var(--brand-soft)", color: "var(--brand)" }}>
            <Icon name="clock" size={40} />
          </div>
          <div className="eyebrow">{t.iqEyebrow}</div>
          <h1 className="title">{t.iqTitle}</h1>
          <p className="sub">{t.iqSub}</p>
          <div style={{ textAlign: "left", display: "flex", flexDirection: "column", gap: 12, margin: "22px 0 8px" }}>
            {[t.iqInstr1, t.iqInstr2, t.iqInstr3].map((x, i) => (
              <div key={i} style={{ display: "flex", gap: 10, alignItems: "center", fontSize: 14.5 }}>
                <span style={{ flex: "0 0 auto", width: 24, height: 24, borderRadius: 7, background: "var(--brand-soft)", color: "var(--brand)", display: "grid", placeItems: "center" }}>
                  <Icon name="check" size={14} />
                </span>{x}
              </div>
            ))}
          </div>
          <Button block lg iconR="arrow" onClick={() => setStarted(true)} style={{ marginTop: 16 }}>{t.iqStart}</Button>
        </div>
      </div>
    );
  }

  const q         = Q[idx];
  const fullbleed = layout === "fullbleed";

  return (
    <div className="center-wrap">
      <div className={fullbleed ? "col-mid fadein" : "col-mid card card-pad fadein"}>
        <div className="iq-bar">
          <div className="iq-track"><div className="iq-fill" style={{ width: ((idx + 1) / Q.length) * 100 + "%" }} /></div>
          <span className="disc-prog">{answered}/{Q.length}</span>
        </div>

        <div className="eyebrow" style={{ display:"flex", alignItems:"center", justifyContent:"space-between" }}>
          <span>{t.question} {idx + 1} / {Q.length}</span>
          <span style={{ display:"flex", alignItems:"center", gap:6, fontWeight:700, color:timerColor, fontSize:15 }}>
            <svg width="28" height="28" viewBox="0 0 36 36" style={{ transform:"rotate(-90deg)" }}>
              <circle cx="18" cy="18" r="15" fill="none" stroke="var(--line)" strokeWidth="3"/>
              <circle cx="18" cy="18" r="15" fill="none" stroke={timerColor} strokeWidth="3"
                strokeDasharray={`${2*Math.PI*15}`}
                strokeDashoffset={`${2*Math.PI*15*(1-timerPct/100)}`}
                style={{ transition:"stroke-dashoffset 1s linear, stroke .3s" }}/>
            </svg>
            {left}s
          </span>
        </div>
        <h2 className="iq-q" style={{ marginTop: 8 }}>{q.q[lang]}</h2>

        {q.type === "matrix" ? (
          <div className="iq-matrix">
            {q.cells.map((cell, i) => (
              <div key={i} className={`iq-matrix-cell${cell === null ? " iq-matrix-unknown" : ""}`}
                dangerouslySetInnerHTML={{ __html: cellSvg(cell) }} />
            ))}
          </div>
        ) : q.figs ? (
          <div className="iq-figs">
            {q.figs.map((fch, i) => <div className="iq-fig" key={i}>{fch}</div>)}
          </div>
        ) : null}

        <div className="iq-opts">
          {q.opts.map((o, oi) => {
            const isImg = typeof o === "object" && o.t;
            const label = isImg ? null : (typeof o === "string" ? o : o[lang]);
            return (
              <button key={oi} className={`iq-opt${isImg ? " iq-opt-fig" : ""} ${answers[idx] === oi ? "on" : ""}`} onClick={() => answer(idx, oi)}>
                <span className="ol">{String.fromCharCode(65 + oi)}</span>
                {isImg
                  ? <span dangerouslySetInnerHTML={{ __html: cellSvg(o, 38) }} style={{ display:"flex", alignItems:"center" }} />
                  : label}
              </button>
            );
          })}
        </div>

        <div className="iq-nums">
          {Q.map((_, i) => (
            <button key={i} className={`iq-num ${i === idx ? "cur" : ""} ${answers[i] !== undefined ? "ans" : ""}`} disabled style={{ cursor: "default" }}>
              {i + 1}
            </button>
          ))}
        </div>

        <div className="flexbtns">
          <span className="grow" />
          {idx < Q.length - 1
            ? <Button iconR="arrow" onClick={nextQ}>{t.iqNext}</Button>
            : <Button iconR="check" onClick={submit}>{t.iqSubmit}</Button>}
        </div>
      </div>
    </div>
  );
}

// ── Doc Card with lightbox ───────────────────────────────────────────────────────
function DocCard({ lang, p, t, isDiterima, docUrls, setDocUrls }) {
  const [preview,  setPreview]  = useState(null);
  const [kkUploading, setKkUploading] = useState(false);

  // Resolve URL: prefer server URL, fall back to blob URL from state
  function resolveUrl(type, stateVal) {
    return docUrls[type] || (typeof stateVal === "string" && stateVal.startsWith("blob:") ? stateVal : null);
  }

  function DocRow({ label, url, locked, isPdf }) {
    const has = !!url;
    return (
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "10px 0", borderBottom: "1px solid var(--line)" }}>
        <span style={{ fontSize: 14, fontWeight: 500 }}>{label}</span>
        {locked ? (
          <span style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 13, color: "var(--muted)" }}>
            <Icon name="lock" size={15} /> {lang === "id" ? "Terkunci" : "Locked"}
          </span>
        ) : has ? isPdf ? (
          <a href={url} target="_blank" rel="noreferrer"
            style={{ display: "flex", alignItems: "center", gap: 6, background: "var(--success)", color: "#fff", border: "none", borderRadius: 20, padding: "4px 12px", cursor: "pointer", fontSize: 13, fontWeight: 600, textDecoration: "none" }}>
            <Icon name="doc" size={14} /> {lang === "id" ? "Buka" : "Open"}
          </a>
        ) : (
          <button onClick={() => setPreview({ url, label })}
            style={{ display: "flex", alignItems: "center", gap: 6, background: "var(--success)", color: "#fff", border: "none", borderRadius: 20, padding: "4px 12px", cursor: "pointer", fontSize: 13, fontWeight: 600 }}>
            <Icon name="check" size={14} /> {lang === "id" ? "Lihat" : "View"}
          </button>
        ) : (
          <span style={{ fontSize: 13, color: "var(--muted)" }}>{lang === "id" ? "Belum diupload" : "Not uploaded"}</span>
        )}
      </div>
    );
  }

  async function uploadKk(file) {
    if (!file || !window.API.getToken()) return;
    setKkUploading(true);
    try {
      await window.API.upload(file, "kk");
      const d = await window.API.getMyDocs();
      if (d && !d.error) setDocUrls(d);
    } catch(e) { console.error("upload kk error", e); }
    setKkUploading(false);
  }

  const cvUrl = resolveUrl("cv", null);
  const kkUrl = resolveUrl("kk", p.kk);

  return (
    <>
      <div className="dash-card fadein" style={{ alignSelf: "start" }}>
        <h3><Icon name="file" size={18} /> {lang === "id" ? "Dokumen Anda" : "Your Documents"}</h3>
        <DocRow label="CV / Resume" url={cvUrl} isPdf />
        <DocRow label={lang === "id" ? "Foto KTP" : "ID Card Photo"} url={resolveUrl("ktp", p.ktp)} />
        <DocRow label={lang === "id" ? "Foto Terbaru" : "Recent Photo"} url={resolveUrl("photo", p.photo)} />

        {/* TTD Kontrak */}
        <DocRow label={lang === "id" ? "Tanda Tangan Kontrak" : "Contract Signature"} url={resolveUrl("signature", null)} />

        {/* KK — locked sampai diterima, lalu bisa upload */}
        <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", padding:"10px 0", borderBottom:"1px solid var(--line)" }}>
          <span style={{ fontSize:14, fontWeight:500 }}>
            {lang === "id" ? "Kartu Keluarga (KK)" : "Family Card (KK)"}
            {isDiterima && !kkUrl && <span style={{ marginLeft:6, fontSize:11, fontWeight:700, color:"var(--danger,#ef4444)", background:"#fef2f2", padding:"1px 7px", borderRadius:20 }}>Wajib</span>}
          </span>
          {!isDiterima ? (
            <span style={{ display:"flex", alignItems:"center", gap:6, fontSize:13, color:"var(--muted)" }}>
              <Icon name="lock" size={15} /> {lang === "id" ? "Terkunci" : "Locked"}
            </span>
          ) : kkUrl ? (
            <button onClick={() => setPreview({ url: kkUrl, label: lang === "id" ? "Kartu Keluarga (KK)" : "Family Card (KK)" })}
              style={{ display:"flex", alignItems:"center", gap:6, background:"var(--success)", color:"#fff", border:"none", borderRadius:20, padding:"4px 12px", cursor:"pointer", fontSize:13, fontWeight:600 }}>
              <Icon name="check" size={14} /> {lang === "id" ? "Lihat" : "View"}
            </button>
          ) : (
            <label style={{ display:"flex", alignItems:"center", gap:6, background:"var(--brand)", color:"#fff", borderRadius:20, padding:"4px 14px", cursor:"pointer", fontSize:13, fontWeight:600 }}>
              {kkUploading
                ? (lang === "id" ? "Mengupload..." : "Uploading...")
                : <><Icon name="upload" size={14} /> {lang === "id" ? "Upload KK" : "Upload KK"}</>}
              <input type="file" accept="image/*,application/pdf" style={{ display:"none" }}
                onChange={e => { if (e.target.files[0]) uploadKk(e.target.files[0]); }} />
            </label>
          )}
        </div>
      </div>

      {/* Lightbox */}
      {preview && (
        <div onClick={() => setPreview(null)}
          style={{ position: "fixed", inset: 0, zIndex: 9999, background: "rgba(0,0,0,.75)", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: 24 }}>
          <div onClick={(e) => e.stopPropagation()}
            style={{ background: "#fff", borderRadius: 20, overflow: "hidden", maxWidth: 520, width: "100%", boxShadow: "0 24px 60px rgba(0,0,0,.4)" }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "14px 18px", borderBottom: "1px solid var(--line)" }}>
              <span style={{ fontWeight: 700, fontSize: 15 }}>{preview.label}</span>
              <button onClick={() => setPreview(null)}
                style={{ background: "none", border: "none", cursor: "pointer", color: "var(--muted)", display: "flex" }}>
                <Icon name="x" size={22} />
              </button>
            </div>
            <img src={preview.url} alt={preview.label}
              style={{ width: "100%", display: "block", maxHeight: "70vh", objectFit: "contain" }} />
          </div>
        </div>
      )}
    </>
  );
}

// ── Contract Screen ──────────────────────────────────────────────────────────────
function ContractScreen({ lang, t, onClose, onSigned }) {
  const [content,   setContent]   = useState("");
  const [loading,   setLoading]   = useState(true);
  const [errMsg,    setErrMsg]    = useState("");
  const [uploading, setUploading] = useState(false);
  const [uploadErr, setUploadErr] = useState("");
  const [done,      setDone]      = useState(false);
  const [sigUrl,    setSigUrl]    = useState(null);

  useEffect(() => {
    window.API.getContract()
      .then(d => {
        if (d?.error) { setErrMsg(d.error); }
        else if (d?.content) { setContent(d.content); }
        else { setErrMsg(lang === "id" ? "Kontrak belum tersedia, hubungi HRD." : "Contract not available yet, contact HR."); }
        setLoading(false);
      })
      .catch(() => {
        setErrMsg(lang === "id" ? "Gagal memuat kontrak. Periksa koneksi internet." : "Failed to load contract. Check your internet connection.");
        setLoading(false);
      });
  }, []);

  async function handleUpload(file) {
    if (!file) return;
    setUploadErr("");
    const previewUrl = URL.createObjectURL(file);
    setSigUrl(previewUrl);
    setUploading(true);
    try {
      const r = await window.API.signContract(file);
      if (r?.ok) {
        setDone(true);
        setTimeout(() => onSigned(), 1800);
      } else {
        setUploadErr(r?.error || (lang === "id" ? "Gagal upload. Coba lagi." : "Upload failed. Please try again."));
      }
    } catch (e) {
      setUploadErr(lang === "id" ? "Terjadi kesalahan jaringan. Coba lagi." : "Network error. Please try again.");
    } finally {
      setUploading(false);
    }
  }

  return (
    <div style={{ position:"fixed", inset:0, zIndex:500, background:"rgba(0,0,0,.7)", display:"flex", alignItems:"center", justifyContent:"center", padding:"16px" }}>
      <div style={{ background:"#fff", borderRadius:16, width:"100%", maxWidth:700, boxShadow:"0 8px 40px rgba(0,0,0,.35)", display:"flex", flexDirection:"column", maxHeight:"92vh", overflow:"hidden" }}>

        {/* Header */}
        <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", padding:"16px 22px", borderBottom:"1px solid var(--line)", flexShrink:0 }}>
          <div style={{ fontWeight:700, fontSize:16 }}>📄 {lang === "id" ? "Kontrak Kerja" : "Employment Contract"}</div>
          <button onClick={onClose} style={{ background:"none", border:"none", cursor:"pointer", color:"var(--muted)", display:"flex" }}><Icon name="x" size={22}/></button>
        </div>

        {/* Isi kontrak — scrollable */}
        <div style={{ flex:1, overflowY:"auto", padding:"28px 32px", background:"#fff", borderBottom:"1px solid var(--line)" }}>
          {loading ? (
            <div style={{ color:"var(--muted)", fontSize:14, textAlign:"center", padding:40 }}>Memuat kontrak...</div>
          ) : errMsg ? (
            <div style={{ color:"#ef4444", fontSize:14, padding:20, background:"#fef2f2", borderRadius:10 }}>{errMsg}</div>
          ) : (
            <div className="contract-body" dangerouslySetInnerHTML={{ __html: content }} />
          )}
        </div>

        {/* Tanda Tangan */}
        {!errMsg && !loading && (
          <div style={{ flexShrink:0, padding:"20px 28px", background:"#f9fafb", borderTop:"1px solid var(--line)" }}>
            {done ? (
              <div style={{ textAlign:"center", color:"#16a34a", fontWeight:700, fontSize:15, padding:"8px 0" }}>
                <Icon name="check" size={20}/> {lang === "id" ? "Kontrak berhasil ditandatangani!" : "Contract signed successfully!"}
              </div>
            ) : (
              <div style={{ display:"flex", gap:20, alignItems:"flex-start", flexWrap:"wrap" }}>

                {/* Kotak format TTD */}
                <div style={{ flex:"1 1 220px" }}>
                  <div style={{ fontSize:13, color:"var(--ink2)", marginBottom:8, fontWeight:600 }}>
                    {lang === "id" ? "Format Tanda Tangan" : "Signature Format"}
                  </div>
                  <div style={{ border:"1.5px dashed var(--line)", borderRadius:10, padding:"14px 16px", background:"#fff", fontSize:12, color:"var(--muted)", lineHeight:1.8 }}>
                    <div style={{ marginBottom:4 }}>{lang === "id" ? "Bandung, ............ 2026" : "Date: ............ 2026"}</div>
                    <div style={{ marginBottom:28 }}>{lang === "id" ? "Yang bertanda tangan di bawah ini," : "The undersigned below,"}</div>
                    {sigUrl
                      ? <img src={sigUrl} alt="TTD" style={{ maxHeight:72, maxWidth:"100%", display:"block", marginBottom:4, borderRadius:6 }} />
                      : <div style={{ height:56, borderBottom:"1px solid #ccc", marginBottom:4 }} />
                    }
                    <div style={{ fontWeight:600, color:"var(--ink)", fontSize:12 }}>( _________________________ )</div>
                    <div style={{ fontSize:11, color:"var(--muted)", marginTop:2 }}>{lang === "id" ? "Nama & Tanda Tangan Karyawan" : "Employee Name & Signature"}</div>
                  </div>
                </div>

                {/* Upload */}
                <div style={{ flex:"1 1 200px" }}>
                  <div style={{ fontSize:13, color:"var(--ink2)", marginBottom:8, fontWeight:600 }}>
                    {lang === "id" ? "Upload Tanda Tangan" : "Upload Signature"}
                  </div>
                  <div style={{ fontSize:12, color:"var(--muted)", marginBottom:12, lineHeight:1.6 }}>
                    {lang === "id"
                      ? "Tanda tangan di kertas putih, foto/scan, lalu upload di sini (JPG / PNG)."
                      : "Sign on white paper, take a photo or scan, then upload here (JPG / PNG)."}
                  </div>
                  {uploadErr && (
                    <div style={{ color:"#ef4444", fontSize:12, background:"#fef2f2", padding:"7px 11px", borderRadius:8, marginBottom:10 }}>
                      {uploadErr}
                    </div>
                  )}
                  <label style={{ display:"inline-flex", alignItems:"center", gap:8, background: uploading ? "var(--muted)" : "var(--brand)", color:"#fff", borderRadius:10, padding:"10px 20px", cursor: uploading ? "not-allowed" : "pointer", fontWeight:600, fontSize:13, transition:"background .2s" }}>
                    {uploading
                      ? <>{lang === "id" ? "Mengupload..." : "Uploading..."}</>
                      : <><Icon name="upload" size={15}/> {lang === "id" ? "Pilih File TTD" : "Choose Signature File"}</>}
                    <input type="file" accept="image/jpeg,image/png,image/webp" disabled={uploading} style={{ display:"none" }}
                      onChange={e => { if (e.target.files[0]) handleUpload(e.target.files[0]); e.target.value = ""; }} />
                  </label>
                </div>

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

// ── Ubah Kota Penempatan ────────────────────────────────────────────────────────
function LocationEditModal({ lang, masterLocations, currentLocations, onClose, onSaved }) {
  const [selected, setSelected] = useState(currentLocations || []);
  const [saving, setSaving] = useState(false);
  const [err, setErr] = useState("");

  async function save() {
    if (!selected.length) { setErr(lang === "id" ? "Pilih minimal satu kota" : "Select at least one city"); return; }
    setSaving(true);
    setErr("");
    try {
      const r = await window.API.updateLocation(selected);
      if (r?.ok) {
        onSaved(selected);
      } else {
        setErr(r?.error || (lang === "id" ? "Gagal menyimpan. Coba lagi." : "Failed to save. Please try again."));
      }
    } catch (e) {
      setErr(lang === "id" ? "Terjadi kesalahan jaringan. Coba lagi." : "Network error. Please try again.");
    } finally {
      setSaving(false);
    }
  }

  return (
    <div style={{ position:"fixed", inset:0, zIndex:500, background:"rgba(0,0,0,.7)", display:"flex", alignItems:"center", justifyContent:"center", padding:"16px" }}>
      <div style={{ background:"#fff", borderRadius:16, width:"100%", maxWidth:480, boxShadow:"0 8px 40px rgba(0,0,0,.35)", overflow:"hidden" }}>
        <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", padding:"16px 22px", borderBottom:"1px solid var(--line)" }}>
          <div style={{ fontWeight:700, fontSize:16 }}>{lang === "id" ? "Ubah Kota Penempatan" : "Change Placement City"}</div>
          <button onClick={onClose} style={{ background:"none", border:"none", cursor:"pointer", color:"var(--muted)", display:"flex" }}><Icon name="x" size={22}/></button>
        </div>
        <div style={{ padding:"22px" }}>
          <div style={{ fontSize:13, color:"var(--muted)", marginBottom:14, lineHeight:1.6 }}>
            {lang === "id"
              ? "Pilih satu atau lebih kota yang Anda inginkan sebagai lokasi penempatan."
              : "Select one or more cities you'd like as your placement location."}
          </div>
          <MultiChipSelect
            options={(masterLocations || []).map(l => ({ id: l.id, label: l.name }))}
            value={selected}
            onChange={setSelected}
            invalid={!!err}
            placeholder={lang === "id" ? "Pilih kota" : "Select city"}
          />
          {err && <div style={{ color:"#ef4444", fontSize:12, marginTop:10 }}>{err}</div>}
          <button onClick={save} disabled={saving}
            style={{ marginTop:18, width:"100%", background: saving ? "var(--muted)" : "var(--brand)", color:"#fff", border:"none", borderRadius:10, padding:"11px 20px", fontWeight:700, fontSize:14, cursor: saving ? "not-allowed" : "pointer" }}>
            {saving ? (lang === "id" ? "Menyimpan..." : "Saving...") : (lang === "id" ? "Simpan" : "Save")}
          </button>
        </div>
      </div>
    </div>
  );
}

// ── Member Area ─────────────────────────────────────────────────────────────────
function MemberScreen({ t, lang, state, setState, needsApt, masterLocations, onEditProfile, onLogout }) {
  const D      = window.APPDATA;
  const p      = state.profile || {};
  const [kkUploaded, setKkUploaded] = useState(false);
  const name   = (p.fullName || (state.reg && state.reg.name) || "").split(" ")[0] || "";
  // Data hasil test — ambil dari state lokal, fallback ke DB jika kosong
  const [dbApp, setDbApp] = useState(null);
  useEffect(() => {
    if (!window.API.getToken()) return;
    window.API.getMyApplication().then(d => {
      if (d?.application) setDbApp(d.application);
    }).catch(() => {});
  }, []);
  // Posisi/lokasi: utamakan data DB (bisa berubah via "Ubah Kota"), fallback ke cache lokal
  const posSrc = dbApp ? { positions: dbApp.positions_json, position: dbApp.position } : p;
  const posIdx = posSrc.positions?.length ? posSrc.positions : (posSrc.position !== undefined && posSrc.position !== "" ? posSrc.position : null);
  const posName = (() => {
    if (posIdx === null || posIdx === undefined) return "—";
    if (Array.isArray(posIdx)) {
      const names = posIdx.map(i => D.positions[lang][i]).filter(Boolean);
      return names.length ? names.join(", ") : "—";
    }
    return D.positions[lang][posIdx] || "—";
  })();
  const locSrc = dbApp ? { locations: dbApp.locations_json, location: dbApp.location } : p;
  const locIdx = locSrc.locations?.length ? locSrc.locations : (locSrc.location !== undefined && locSrc.location !== "" ? locSrc.location : null);
  const locName = (() => {
    if (locIdx === null || locIdx === undefined) return "";
    if (Array.isArray(locIdx)) {
      return locIdx.map(i => D.locations[lang][i]).filter(Boolean).join(", ");
    }
    return D.locations[lang][locIdx] || "";
  })();

  const disc     = state.discResult || dbApp?.disc_result || null;
  const discMeta = disc && D.discProfiles[disc] ? D.discProfiles[disc] : null;
  const discTxt  = discMeta ? (discMeta[lang] || "") : "";
  const iq       = state.iqResult   || dbApp?.iq_result   || null;
  const iqCorrect = state.iqCorrect ?? dbApp?.iq_correct  ?? 0;
  const _needsApt = needsApt !== undefined ? needsApt : (Array.isArray(posIdx) ? posIdx.some(i => D.needsAptitude(i)) : D.needsAptitude(posIdx));
  const apt      = state.aptResult  ?? dbApp?.apt_result  ?? null;
  const aptBand  = state.aptBand    || dbApp?.apt_band    || null;
  const aptSjt   = state.aptSjtScore ?? dbApp?.apt_sjt_score ?? 0;
  const aptRe    = state.aptReScore  ?? dbApp?.apt_re_score  ?? 0;
  const appId    = state.appId || dbApp?.app_id || (state.reg?.appId) || "RBN-??????";
  const today    = new Date().toLocaleDateString(lang === "id" ? "id-ID" : "en-US", { day: "numeric", month: "short", year: "numeric" });

  // Dokumen URLs (shared ke DocCard agar perubahan KK reflect di notifikasi)
  const [docUrls, setDocUrls] = useState({});
  useEffect(() => {
    if (!window.API.getToken()) return;
    window.API.getMyDocs().then(d => { if (d && !d.error) setDocUrls(d); }).catch(() => {});
  }, []);

  // Live status dari server
  const [liveStatus, setLiveStatus] = useState(null);
  useEffect(() => {
    if (!window.API.getToken()) return;
    window.API.getMyStatus().then(d => {
      if (d && !d.error) setLiveStatus(d);
    }).catch(() => {});
    const t = setInterval(() => {
      window.API.getMyStatus().then(d => { if (d && !d.error) setLiveStatus(d); }).catch(() => {});
    }, 60000);
    return () => clearInterval(t);
  }, []);

  const [confirmSaving, setConfirmSaving] = useState(false);
  function confirmInterview(val) {
    if (confirmSaving) return;
    setConfirmSaving(true);
    window.API.confirmInterview(val).then(d => {
      if (d && !d.error) setLiveStatus(s => ({ ...s, interview_confirm: val, interview_confirm_at: new Date().toISOString() }));
    }).catch(() => {}).finally(() => setConfirmSaving(false));
  }

  const _stMap = { review:"baru", shortlisted:"ditinjau", interview:"wawancara", accepted:"diterima", rejected:"ditolak" };
  const appStatus   = _stMap[liveStatus?.status] || liveStatus?.status || "baru";
  const isInterview = appStatus === "wawancara";
  const isDiterima  = appStatus === "diterima";
  const isDitolak   = appStatus === "ditolak";

  const placedPosName = dbApp?.placed_position_name || null;
  const placedLocName = dbApp?.placed_location_name || null;
  const contractSignedAt = dbApp?.contract_signed_at || null;
  const infoComplete = isDiterima && p.famName && p.famRelation && p.famPhone && docUrls.kk;
  const needsContract = infoComplete && !contractSignedAt;

  const [showContract, setShowContract] = useState(false);
  const [showLocationEdit, setShowLocationEdit] = useState(false);
  const canEditLocation = appStatus === "baru" && !liveStatus?.interview_at;
  const [pdfLoading,  setPdfLoading]  = useState(false);

  async function downloadContractPdf() {
    setPdfLoading(true);
    try {
      const d = await window.API.getContract();
      if (!d?.content) return;
      const html = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Kontrak Kerja</title>
<link rel="stylesheet" href="https://cdn.quilljs.com/1.3.7/quill.snow.css"/>
<style>body{font-family:Georgia,serif;max-width:720px;margin:40px auto;font-size:14px;line-height:1.8;color:#111;}.ql-editor{padding:0;border:none;font-family:inherit;font-size:inherit;}.ql-container{border:none;}h1,h2,h3{margin:12px 0 6px;}p{margin:0 0 8px;}ol,ul{padding-left:22px;margin:4px 0 10px;}table{width:100%;border-collapse:collapse;margin:8px 0;}td,th{padding:6px 10px;}strong{font-weight:700;}@media print{body{margin:20px;}}</style>
</head><body><div class="ql-editor">${d.content}</div>
<script>
window.onload=function(){
  var imgs=document.querySelectorAll('img');
  if(!imgs.length){window.print();return;}
  var loaded=0;
  function tryPrint(){if(++loaded>=imgs.length)window.print();}
  imgs.forEach(function(img){
    if(img.complete){tryPrint();}
    else{img.onload=tryPrint;img.onerror=tryPrint;}
  });
};
<\/script></body></html>`;
      const blob = new Blob([html], { type: 'text/html' });
      window.open(URL.createObjectURL(blob), '_blank');
    } catch {}
    setPdfLoading(false);
  }

  const isKaryawan    = isDiterima && !!contractSignedAt;
  const allTestsDone = disc && iq && (!_needsApt || apt !== null);
  const stages = [
    { label: t.stApply,   st: "done" },
    { label: t.stProfile, st: "done" },
    { label: t.stDisc,    st: disc ? "done" : "cur" },
    { label: t.stIq,      st: iq ? "done" : disc ? "cur" : "todo" },
    ...(_needsApt ? [{ label: t.stApt, st: apt !== null ? "done" : iq ? "cur" : "todo" }] : []),
    { label: t.stReview,    st: !allTestsDone ? "todo" : isInterview || isDiterima || isDitolak ? "done" : "cur" },
    { label: t.stInterview, st: isDitolak ? "skip" : isInterview ? "cur" : isDiterima ? "done" : "todo" },
    { label: t.stDecision,  st: isDiterima || isDitolak ? "done" : "todo" },
  ];
  const badge = { done: t.done2, cur: isInterview ? t.interviewScheduled : t.inProgress, todo: t.upcoming, skip: t.skipped };

  return (
    <div className="center-wrap">
      <div className="col-mid" style={{ maxWidth: 980 }}>
        <div className="dash-hero fadein">
          <div className="deco-ring" style={{ width: 300, height: 300, right: -100, top: -120 }} />
          <div className="deco-ring" style={{ width: 180, height: 180, right: -30, top: -60 }} />
          <div className="eyebrow" style={{ color: "rgba(255,255,255,.85)" }}>{t.memberArea}</div>
          <div className="dash-hi" style={{ marginTop: 8 }}>{t.memberHi}{name ? `, ${name}` : ""} 👋</div>
          <div className="dash-sub">{t.memberWelcome}</div>
          <div className="dash-submitted"><Icon name="check" size={16} /> {t.appSubmitted}</div>
          <div className="dash-meta">
            <div className="dm"><div className="k">{t.appId}</div><div className="v">{appId}</div></div>
            <div className="dm"><div className="k">{t.appliedOn}</div><div className="v">{today}</div></div>
            <div className="dm"><div className="k">{t.sumPosition}</div><div className="v">{posName}{locName ? " · " + locName : ""}
              {canEditLocation && (
                <button onClick={() => setShowLocationEdit(true)}
                  style={{ marginLeft:10, background:"rgba(255,255,255,.18)", border:"none", color:"#fff", borderRadius:8, padding:"3px 10px", fontSize:11.5, fontWeight:700, cursor:"pointer" }}>
                  {lang === "id" ? "Ubah Kota" : "Change City"}
                </button>
              )}
            </div></div>
            {isDiterima && placedPosName && (
              <div className="dm" style={{ background:"rgba(255,255,255,.15)", borderRadius:10, padding:"8px 14px" }}>
                <div className="k" style={{ color:"rgba(255,255,255,.75)" }}>✓ Posisi Ditempatkan</div>
                <div className="v" style={{ fontWeight:800 }}>{placedPosName}{placedLocName ? " — " + placedLocName : ""}</div>
              </div>
            )}
          </div>
        </div>

        {/* Notifikasi diterima — wajib lengkapi data */}
        {isDiterima && (!p.famName || !p.famRelation || !p.famPhone || !docUrls.kk) && (
          <div className="fadein" style={{
            marginTop: 16, padding: "16px 20px",
            background: "#fffbeb", border: "2px solid #f59e0b",
            borderRadius: "var(--radius)", display: "flex", gap: 14, alignItems: "flex-start"
          }}>
            <span style={{ fontSize: 24, lineHeight: 1 }}>🎉</span>
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 15, color: "#92400e", marginBottom: 6 }}>
                {lang === "id" ? "Selamat! Anda diterima — lengkapi data berikut" : "Congratulations! You're accepted — please complete the following"}
              </div>
              <div style={{ fontSize: 13.5, color: "#78350f", lineHeight: 1.7, marginBottom: 12 }}>
                {lang === "id"
                  ? "Untuk proses onboarding, lengkapi informasi berikut di formulir profil Anda:"
                  : "For onboarding, please complete the following in your profile form:"}
              </div>
              <div style={{ display: "flex", flexDirection: "column", gap: 6, marginBottom: 14 }}>
                {(!p.famName || !p.famRelation || !p.famPhone) && (
                  <div style={{ display: "flex", gap: 8, alignItems: "center", fontSize: 13.5, color: "#92400e" }}>
                    <span style={{ width: 20, height: 20, borderRadius: "50%", background: "#f59e0b", color: "#fff", display: "grid", placeItems: "center", flexShrink: 0, fontSize: 11, fontWeight: 700 }}>!</span>
                    {lang === "id" ? "Kontak darurat keluarga (nama, hubungan, nomor telepon)" : "Emergency family contact (name, relationship, phone number)"}
                  </div>
                )}
                {!docUrls.kk && (
                  <div style={{ display: "flex", gap: 8, alignItems: "center", fontSize: 13.5, color: "#92400e" }}>
                    <span style={{ width: 20, height: 20, borderRadius: "50%", background: "#f59e0b", color: "#fff", display: "grid", placeItems: "center", flexShrink: 0, fontSize: 11, fontWeight: 700 }}>!</span>
                    {lang === "id" ? "Upload Kartu Keluarga (KK)" : "Upload Family Card (KK)"}
                  </div>
                )}
              </div>
              <button className="btn btn-primary" onClick={onEditProfile}>
                {lang === "id" ? "Lengkapi Sekarang" : "Complete Now"}
              </button>
            </div>
          </div>
        )}

        {/* Banner wajib TTD kontrak */}
        {needsContract && (
          <div className="fadein" style={{
            marginTop: 16, padding: "16px 20px",
            background: "#f0fdf4", border: "2px solid #16a34a",
            borderRadius: "var(--radius)", display: "flex", gap: 14, alignItems: "flex-start"
          }}>
            <span style={{ fontSize: 24, lineHeight: 1 }}>📄</span>
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 15, color: "#14532d", marginBottom: 4 }}>
                {lang === "id" ? "Tandatangani Kontrak Kerja" : "Sign Your Employment Contract"}
              </div>
              <div style={{ fontSize: 13.5, color: "#166534", lineHeight: 1.6, marginBottom: 12 }}>
                {lang === "id"
                  ? "Semua data telah lengkap. Langkah terakhir: baca dan tandatangani kontrak kerja Anda."
                  : "All information is complete. Final step: read and sign your employment contract."}
              </div>
              <button className="btn btn-primary" style={{ background:"#16a34a", borderColor:"#16a34a" }} onClick={() => setShowContract(true)}>
                {lang === "id" ? "Buka & Tandatangani Kontrak" : "Open & Sign Contract"}
              </button>
            </div>
          </div>
        )}

        {/* Kartu karyawan resmi — menggantikan semua notif setelah TTD */}
        {isKaryawan && (
          <div className="fadein" style={{
            marginTop: 16, borderRadius: "var(--radius)", overflow: "hidden",
            border: "2px solid #16a34a", boxShadow: "0 4px 24px rgba(22,163,74,.12)"
          }}>
            <div style={{ background: "linear-gradient(135deg,#16a34a,#15803d)", padding: "20px 24px", color: "#fff" }}>
              <div style={{ fontSize: 26, marginBottom: 6 }}>🎉</div>
              <div style={{ fontWeight: 800, fontSize: 17, marginBottom: 4 }}>
                {lang === "id" ? "Selamat! Anda Resmi Menjadi Karyawan" : "Congratulations! You're Now an Official Employee"}
              </div>
              <div style={{ fontSize: 13.5, opacity: 0.9 }}>CV. Rabbani Asysa</div>
            </div>
            <div style={{ background: "#f0fdf4", padding: "16px 24px", display: "flex", flexWrap: "wrap", gap: 16, alignItems: "center" }}>
              <div style={{ flex: 1, minWidth: 180 }}>
                {placedPosName && (
                  <div style={{ marginBottom: 6 }}>
                    <div style={{ fontSize: 11, fontWeight: 700, color: "#15803d", textTransform: "uppercase", letterSpacing: ".06em" }}>Posisi</div>
                    <div style={{ fontWeight: 700, fontSize: 15, color: "#14532d" }}>{placedPosName}{placedLocName ? ` — ${placedLocName}` : ""}</div>
                  </div>
                )}
                <div style={{ fontSize: 12, color: "#166534" }}>
                  {lang === "id" ? "Kontrak ditandatangani" : "Contract signed"} · {new Date(contractSignedAt).toLocaleDateString(lang === "id" ? "id-ID" : "en-US", { day:"numeric", month:"long", year:"numeric" })}
                </div>
              </div>
              <button onClick={downloadContractPdf} disabled={pdfLoading}
                style={{ display:"flex", alignItems:"center", gap:8, background: pdfLoading ? "#86efac" : "#16a34a", color:"#fff", border:"none", borderRadius:10, padding:"10px 20px", fontWeight:700, fontSize:13, cursor: pdfLoading ? "not-allowed" : "pointer", transition:"background .2s", flexShrink:0 }}>
                {pdfLoading
                  ? <>{lang === "id" ? "Memuat..." : "Loading..."}</>
                  : <><Icon name="download" size={15}/> {lang === "id" ? "Download Kontrak PDF" : "Download Contract PDF"}</>}
              </button>
            </div>
          </div>
        )}

        {/* Halaman kontrak (overlay) */}
        {showContract && <ContractScreen lang={lang} t={t} onClose={() => setShowContract(false)} onSigned={() => {
          setShowContract(false);
          window.API.getMyApplication().then(d => { if (d?.application) setDbApp(d.application); });
        }} />}

        {showLocationEdit && (
          <LocationEditModal
            lang={lang}
            masterLocations={masterLocations}
            currentLocations={Array.isArray(locIdx) ? locIdx : (locIdx !== null ? [locIdx] : [])}
            onClose={() => setShowLocationEdit(false)}
            onSaved={(newLocs) => {
              setShowLocationEdit(false);
              setState(s => ({ ...s, profile: { ...s.profile, locations: newLocs, location: newLocs[0] } }));
              window.API.getMyApplication().then(d => { if (d?.application) setDbApp(d.application); });
            }}
          />
        )}

        {/* Jadwal wawancara — tepat di bawah profil pelamar */}
        {isInterview && (
          <div className="dash-card fadein" style={{ marginTop: 16, border: "2px solid var(--brand)", background: "var(--brand-soft)" }}>
            <h3 style={{ marginBottom: 16 }}><Icon name="wa" size={18} /> {liveStatus?.interview_mode === "offline" ? (lang === "id" ? "Jadwal Wawancara Tatap Muka" : "Onsite Interview Schedule") : t.interviewTitle}</h3>
            {liveStatus?.interview_at ? (
              <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
                <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
                  <div style={{ flex: 1, minWidth: 180 }}>
                    <div style={{ fontSize: 12, color: "var(--muted)", fontWeight: 600, marginBottom: 4 }}>{t.interviewWhen}</div>
                    <div style={{ fontWeight: 700, fontSize: 15 }}>
                      {new Date(liveStatus.interview_at).toLocaleString(lang === "id" ? "id-ID" : "en-US", { weekday: "long", day: "numeric", month: "long", year: "numeric", hour: "2-digit", minute: "2-digit" })}
                    </div>
                  </div>
                  {liveStatus.interview_mode === "offline" ? (
                    liveStatus.interview_location && (
                      <div style={{ flex: 1, minWidth: 180 }}>
                        <div style={{ fontSize: 12, color: "var(--muted)", fontWeight: 600, marginBottom: 4 }}>{lang === "id" ? "Lokasi" : "Location"}</div>
                        <div style={{ fontWeight: 600, fontSize: 15 }}>{liveStatus.interview_location}</div>
                      </div>
                    )
                  ) : liveStatus.interview_link && (
                    <div style={{ flex: 1, minWidth: 180 }}>
                      <div style={{ fontSize: 12, color: "var(--muted)", fontWeight: 600, marginBottom: 4 }}>{t.interviewLink}</div>
                      <a href={liveStatus.interview_link} target="_blank" rel="noreferrer"
                        style={{ fontWeight: 600, color: "var(--brand)", wordBreak: "break-all" }}>
                        {liveStatus.interview_link}
                      </a>
                    </div>
                  )}
                </div>
                {liveStatus.interview_notes && (
                  <div>
                    <div style={{ fontSize: 12, color: "var(--muted)", fontWeight: 600, marginBottom: 4 }}>{t.interviewNotes}</div>
                    <div style={{ fontSize: 14, color: "var(--fg)", lineHeight: 1.6, whiteSpace: "pre-line" }}>{liveStatus.interview_notes}</div>
                  </div>
                )}
                {liveStatus.interview_mode !== "offline" && liveStatus.interview_link && (
                  <a href={liveStatus.interview_link} target="_blank" rel="noreferrer"
                    className="btn btn-primary btn-lg" style={{ alignSelf: "flex-start", display: "flex", gap: 8, marginTop: 4 }}>
                    <Icon name="chevR" size={16} /> {t.interviewJoin}
                  </a>
                )}

                {/* Konfirmasi kehadiran */}
                <div style={{ marginTop: 8, paddingTop: 14, borderTop: "1px solid var(--brand-ring)" }}>
                  {liveStatus.interview_confirm ? (
                    <div style={{
                      display: "flex", alignItems: "center", gap: 8, fontSize: 14, fontWeight: 600,
                      color: liveStatus.interview_confirm === "yes" ? "#15803d" : "#b91c1c"
                    }}>
                      <Icon name={liveStatus.interview_confirm === "yes" ? "check" : "x"} size={16} />
                      {liveStatus.interview_confirm === "yes" ? t.interviewConfirmedYes : t.interviewConfirmedNo}
                    </div>
                  ) : (
                    <>
                      <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 10, color: "var(--fg)" }}>{t.interviewConfirmQ}</div>
                      <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
                        <button className="btn btn-primary" disabled={confirmSaving}
                          style={{ background: "#16a34a", borderColor: "#16a34a" }}
                          onClick={() => confirmInterview("yes")}>
                          {confirmSaving ? t.interviewConfirmSaving : <><Icon name="check" size={15} /> {t.interviewConfirmYes}</>}
                        </button>
                        <button className="btn btn-ghost" disabled={confirmSaving}
                          style={{ color: "#b91c1c", borderColor: "#fca5a5" }}
                          onClick={() => confirmInterview("no")}>
                          {confirmSaving ? t.interviewConfirmSaving : <><Icon name="x" size={15} /> {t.interviewConfirmNo}</>}
                        </button>
                      </div>
                    </>
                  )}
                </div>
              </div>
            ) : (
              <p style={{ color: "var(--muted)", fontSize: 14 }}>{t.interviewPending}</p>
            )}
          </div>
        )}

        {/* Row 1: Progress | Hasil test — disembunyikan jika sudah jadi karyawan */}
        <div className="member-grid" style={{ marginTop: 16, display: isKaryawan ? "none" : undefined }}>
          {/* Kiri: Progress timeline */}
          <div className="dash-card fadein">
            <h3><Icon name="briefcase" size={18} /> {t.progressTitle}</h3>
            <div className="timeline">
              {stages.map((s, i) => (
                <div className="tl-item" key={i}>
                  <div className="tl-rail">
                    <div className={`tl-node ${s.st}`}>
                      {s.st === "done" ? <Icon name="check" size={15} /> : i + 1}
                    </div>
                    {i < stages.length - 1 && <div className={`tl-bar ${s.st === "done" ? "done" : ""}`} />}
                  </div>
                  <div className="tl-body">
                    <div className="tl-title">{s.label}<span className={`tl-badge ${s.st}`}>{badge[s.st]}</span></div>
                    {s.st === "cur" && <div className="tl-when">{t.appSubmittedSub}</div>}
                  </div>
                </div>
              ))}
            </div>
          </div>

          {/* Kanan: Hasil test + status */}
          <div className="dash-card fadein" style={{ alignSelf: "start" }}>
            <h3><Icon name="star" size={18} /> {t.yourResults}</h3>
            <div className="res-grid">
              {disc ? (
                <div className="res">
                  <div className="rk">{t.sumDisc}</div>
                  <div className="rv">{disc}</div>
                  <div className="rs">{discTxt}</div>
                </div>
              ) : (
                <div className="res" style={{ opacity: 0.45 }}>
                  <div className="rk">{t.sumDisc}</div>
                  <div className="rv" style={{ fontSize: 18, color: "var(--muted)" }}>—</div>
                  <div className="rs">{lang === "id" ? "Belum mengerjakan" : "Not taken"}</div>
                </div>
              )}
              {iq ? (
                <div className="res">
                  <div className="rk">{t.sumIq}</div>
                  <div className="rv">{iq}</div>
                  <div className="rs">{iqCorrect}/{D.iq.length} ✓</div>
                </div>
              ) : (
                <div className="res" style={{ opacity: 0.45 }}>
                  <div className="rk">{t.sumIq}</div>
                  <div className="rv" style={{ fontSize: 18, color: "var(--muted)" }}>—</div>
                  <div className="rs">{lang === "id" ? "Belum mengerjakan" : "Not taken"}</div>
                </div>
              )}
              {_needsApt && apt !== null && (
                <div className="res full" style={{ background: "var(--brand-soft2)" }}>
                  <div className="rk">{t.sumApt}</div>
                  <div style={{ display: "flex", alignItems: "baseline", gap: 10, flexWrap: "wrap" }}>
                    <div className="rv" style={{ color: "var(--brand)" }}>{apt}<span style={{ fontSize: 14, color: "var(--muted)" }}>/100</span></div>
                    <span className="badge2">{aptBand}</span>
                  </div>
                  <div className="rs">{t.aptSituational}: {aptSjt} · {t.aptReasoning}: {aptRe}</div>
                </div>
              )}
              <div className="res full">
                <div className="rk">{t.sumStatus}</div>
                <div className="rv" style={{ color: isInterview ? "var(--brand)" : isDiterima ? "var(--ok)" : isDitolak ? "var(--err,#ef4444)" : "var(--warn)" }}>
                  ● {isInterview ? t.interviewScheduled : isDiterima ? (lang==="id"?"Diterima":"Accepted") : isDitolak ? (lang==="id"?"Ditolak":"Rejected") : t.statusReview}
                </div>
              </div>
            </div>
          </div>
        </div>

        {/* Row 2: Karakter insight — full width, hanya jika test 1 selesai */}
        {disc && discMeta && (
          <div className="dash-card fadein" style={{ marginTop: 16, background: "var(--brand-soft)", border: "1px solid var(--brand-ring)", boxShadow: "none" }}>
            <div style={{ display: "flex", alignItems: "flex-start", gap: 20, flexWrap: "wrap" }}>
              <div style={{ flex: "0 0 auto", width: 56, height: 56, borderRadius: 16, background: "var(--brand)", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 26, fontWeight: 800 }}>{disc}</div>
              <div style={{ flex: 1, minWidth: 220 }}>
                <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 6 }}>{discMeta.name} <span style={{ fontWeight: 400, color: "var(--muted)", fontSize: 14 }}>— {lang === "id" ? "Tipe Kepribadian Anda" : "Your Personality Type"}</span></div>
                <p style={{ fontSize: 13.5, color: "var(--fg)", lineHeight: 1.65, margin: "0 0 10px" }}>{discMeta.desc?.[lang] || discTxt}</p>
                {discMeta.traits?.[lang] && (
                  <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
                    {discMeta.traits[lang].map((tr, i) => (
                      <span key={i} style={{ fontSize: 12, padding: "3px 12px", borderRadius: 20, background: "var(--brand)", color: "#fff", fontWeight: 600 }}>{tr}</span>
                    ))}
                  </div>
                )}
              </div>
            </div>
          </div>
        )}

        {/* Row 3: Edit profil | Dokumen lanjutan */}
        <div className="member-grid" style={{ marginTop: 16 }}>
          <div className="dash-card fadein" style={{ alignSelf: "start" }}>
            <button className="edit-cta" onClick={onEditProfile} style={{ margin: 0 }}>
              <span className="ei"><Icon name="edit" size={20} /></span>
              <span style={{ flex: 1 }}>
                <span className="et" style={{ display: "block" }}>{t.editProfile}</span>
                <span className="es">{t.editProfileSub}</span>
              </span>
              <Icon name="chevR" size={18} />
            </button>
          </div>
          <DocCard lang={lang} p={p} t={t} isDiterima={isDiterima} docUrls={docUrls} setDocUrls={setDocUrls} />
        </div>

      </div>
    </div>
  );
}

Object.assign(window, { DiscScreen, IqScreen, MemberScreen });
