/* qplayers.jsx — All 9 question-type players + IMAGE_BASED + Feynman variant
   Each player exports a component that renders the *inside* of a Phone frame
   (HUD lives outside the player, composed in qstates.jsx). Uniform anchor:
   AnimatedFeedback for correct/wrong/partial. No fullscreen overlays.       */

const { useState: useStateP } = React;

/* ═══════════════════════════════════════════════════════════════
   1 · MULTIPLE_CHOICE
   States: empty / selected / correct / wrong
═══════════════════════════════════════════════════════════════ */
function MCPlayer({ state = 'empty', dark = false, hintRevealed = false }) {
  const options = [
    { letter: 'A', text: 'x = 2', correct: false },
    { letter: 'B', text: 'x = 4', correct: true },
    { letter: 'C', text: 'x = 6', correct: false },
    { letter: 'D', text: 'x = 8', correct: false },
  ];
  const selected = state === 'empty' ? null : 'B';
  const wrongPick = state === 'wrong' ? 'C' : null;
  return (
    <window.PlayBody qtype="MULTIPLE_CHOICE" dark={dark}>
      <window.TypeBadge type="MULTIPLE_CHOICE" />
      <h2 style={{ margin: 0, fontSize: 20, fontWeight: 800, lineHeight: 1.3, color: dark ? '#F1F5F9' : '#0F172A' }}>
        Wat is de oplossing van 2x + 6 = 14?
      </h2>
      {hintRevealed && (
        <div style={{
          padding: 10, borderRadius: 10, background: dark ? 'rgba(245,158,11,0.10)' : '#FEF3C7',
          border: `1px solid ${dark ? 'rgba(245,158,11,0.25)' : '#FDE68A'}`,
          fontSize: 13, color: '#92400E', display: 'flex', gap: 8, alignItems: 'flex-start',
        }}>
          <window.LucideIcon name="lightbulb" size={14} />
          <span><b>Hint:</b> Trek eerst 6 van beide kanten af.</span>
        </div>
      )}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
        {options.map(o => {
          const isPicked = (wrongPick || selected) === o.letter;
          let bg, border, fg = dark ? '#F1F5F9' : '#0F172A', letterBg = dark ? '#1E293B' : '#F1F5F9', letterFg = dark ? '#94A3B8' : '#64748B', icon = null;
          if (state === 'correct' && o.correct) {
            bg = dark ? 'rgba(34,197,94,0.12)' : '#F0FDF4';
            border = '#16A34A'; letterBg = '#16A34A'; letterFg = '#FFF';
            icon = <window.LucideIcon name="check" size={16} color="#16A34A" />;
          } else if (state === 'wrong' && isPicked) {
            bg = dark ? 'rgba(220,38,38,0.12)' : '#FEF2F2'; border = '#DC2626'; letterBg = '#DC2626'; letterFg = '#FFF';
            icon = <window.LucideIcon name="x" size={16} color="#DC2626" />;
          } else if (state === 'wrong' && o.correct) {
            bg = dark ? 'rgba(34,197,94,0.10)' : '#F0FDF4'; border = '#86EFAC'; letterBg = '#16A34A'; letterFg = '#FFF';
          } else if (state === 'selected' && isPicked) {
            bg = dark ? 'rgba(0,180,216,0.12)' : '#EFF9FF'; border = '#0096C7'; letterBg = '#0096C7'; letterFg = '#FFF';
          } else {
            bg = dark ? '#111827' : '#FFFFFF'; border = dark ? '#1E293B' : '#E2E8F0';
          }
          const dim = state !== 'empty' && state !== 'selected' && !o.correct && !isPicked;
          return (
            <div key={o.letter} style={{
              padding: '14px 14px', borderRadius: 12,
              background: bg, border: `2px solid ${border}`,
              display: 'flex', alignItems: 'center', gap: 12,
              opacity: dim ? 0.4 : 1, transition: 'all .2s ease',
            }}>
              <span style={{
                width: 28, height: 28, borderRadius: 8, background: letterBg, color: letterFg,
                display: 'grid', placeItems: 'center', fontWeight: 900, fontSize: 13,
              }}>{o.letter}</span>
              <span style={{ flex: 1, fontSize: 15, fontWeight: 600, color: fg }}>{o.text}</span>
              {icon}
            </div>
          );
        })}
      </div>
      {(state === 'correct' || state === 'wrong') && (
        <window.AnimatedFeedback
          dark={dark}
          kind={state === 'correct' ? 'correct' : 'wrong'}
          text={state === 'correct' ? 'Klopt!' : 'Niet helemaal — het was B.'}
          sub={state === 'correct' ? '+40 punten · streak 3×' : '2x = 8, dus x = 4.'}
        />
      )}
      {state === 'empty' && (
        <div style={{ marginTop: 'auto' }}>
          <window.CtaBar label="Controleer" disabled />
        </div>
      )}
      {state === 'selected' && (
        <div style={{ marginTop: 'auto' }}>
          <window.CtaBar label="Controleer" />
        </div>
      )}
      {(state === 'correct' || state === 'wrong') && (
        <div style={{ marginTop: 'auto' }}>
          <window.CtaBar label="Volgende vraag →" kind={state === 'correct' ? 'success' : 'primary'} />
        </div>
      )}
    </window.PlayBody>
  );
}
window.MCPlayer = MCPlayer;

/* ═══════════════════════════════════════════════════════════════
   2 · TERM_DEFINITION (flashcard)
═══════════════════════════════════════════════════════════════ */
function TDPlayer({ state = 'empty', dark = false, direction = 'NL→Latijn' }) {
  return (
    <window.PlayBody qtype="TERM_DEFINITION" dark={dark}>
      <window.TypeBadge type="TERM_DEFINITION" />
      <div style={{
        background: dark ? '#111827' : '#F8FAFC',
        borderRadius: 14, padding: '24px 18px',
        border: `1px solid ${dark ? '#1E293B' : '#E2E8F0'}`,
        textAlign: 'center',
      }}>
        <div style={{ fontSize: 11, fontWeight: 800, color: dark ? '#94A3B8' : '#64748B', letterSpacing: 1, marginBottom: 8 }}>
          {direction}
        </div>
        <div style={{ fontFamily: "'Fredoka One', cursive", fontSize: 36, color: dark ? '#F1F5F9' : '#0F172A', lineHeight: 1 }}>
          {direction === 'Duits → NL' ? 'Schmetterling' : 'water'}
        </div>
        <div style={{ marginTop: 10 }}>
          <span style={{
            display: 'inline-block', padding: '3px 10px', borderRadius: 999,
            background: dark ? 'rgba(0,180,216,0.14)' : '#EFF9FF',
            color: dark ? '#7DD3FC' : '#0096C7',
            fontSize: 11, fontWeight: 700,
          }}>zelfstandig naamwoord</span>
        </div>
      </div>
      {/* Input */}
      <div style={{
        height: 50, borderRadius: 12,
        background: dark ? '#0A0F1E' : '#FFFFFF',
        border: state === 'wrong' ? '2px solid #DC2626'
              : state === 'correct' ? '2px solid #16A34A'
              : `2px solid ${dark ? '#1E293B' : '#E2E8F0'}`,
        padding: '0 14px', display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <span style={{
          flex: 1, fontSize: 16, fontWeight: 600,
          color: state === 'wrong' ? '#DC2626' : state === 'correct' ? '#16A34A' : (dark ? '#F1F5F9' : '#0F172A'),
        }}>
          {state === 'empty' ? <span style={{ color: dark ? '#475569' : '#94A3B8', fontWeight: 500 }}>Type je antwoord…</span>
            : state === 'typing' ? 'aqu|'
            : state === 'wrong' ? 'ignis'
            : direction === 'Duits → NL' ? 'vlinder' : 'aqua'}
        </span>
        {state === 'correct' && <window.LucideIcon name="check" size={18} color="#16A34A" />}
        {state === 'wrong' && <window.LucideIcon name="x" size={18} color="#DC2626" />}
      </div>
      {state === 'wrong' && (
        <window.AnimatedFeedback dark={dark} kind="wrong"
          text="Niet goed — poging 1 van 2"
          sub="Probeer nog een keer; je krijgt halve punten als 't lukt."
        />
      )}
      {state === 'correct' && (
        <window.AnimatedFeedback dark={dark} kind="correct"
          text="Klopt!" sub="+30 punten · 'aqua' is nominatief enkelvoud van water."
        />
      )}
      <div style={{ marginTop: 'auto' }}>
        {state === 'empty' && <window.CtaBar label="Controleer" disabled />}
        {state === 'typing' && <window.CtaBar label="Controleer" />}
        {state === 'wrong' && <window.CtaBar label="Probeer opnieuw" />}
        {state === 'correct' && <window.CtaBar label="Volgende →" kind="success" />}
      </div>
    </window.PlayBody>
  );
}
window.TDPlayer = TDPlayer;

/* ═══════════════════════════════════════════════════════════════
   3 · MATCHING (pitch: tap-to-pair, NOT drag)
═══════════════════════════════════════════════════════════════ */
function MatchPlayer({ state = 'empty', dark = false }) {
  // 4 begrippen ↔ 4 omschrijvingen, in 2x4 grid
  // states: empty (none paired), pairing (1 selected), partial (3/4 paired), done
  const left = [
    { id: 'mit', label: 'Mitose' },
    { id: 'mei', label: 'Meiose' },
    { id: 'rep', label: 'DNA-replicatie' },
    { id: 'tra', label: 'Transcriptie' },
  ];
  const right = [
    { id: 'rna', label: 'RNA-synthese', pairTo: 'tra' },
    { id: 'cel', label: 'Celdeling',    pairTo: 'mit' },
    { id: 'chr', label: 'Chromosomen­reductie', pairTo: 'mei' },
    { id: 'kop', label: 'DNA-kopiëren', pairTo: 'rep' },
  ];

  const pairs = state === 'empty' ? {}
    : state === 'pairing' ? { activeLeft: 'mit' }
    : state === 'wrong' ? { mit: 'cel', mei: 'rna', rep: 'kop' }   // mei→rna is fout
    : state === 'done' ? { mit: 'cel', mei: 'chr', rep: 'kop', tra: 'rna' }
    : {};

  const wrongHL = state === 'wrong' ? { mei: 'rna' } : {};

  const colorFor = (lid) => {
    const colors = ['#0096C7', '#7C3AED', '#EA580C', '#16A34A'];
    const idx = ['mit','mei','rep','tra'].indexOf(lid);
    return colors[idx];
  };

  const getPairColor = (sideId, side) => {
    if (side === 'left') return pairs[sideId] ? colorFor(sideId) : null;
    // right side: find which left maps to it
    const leftMatch = Object.entries(pairs).find(([_l, r]) => r === sideId)?.[0];
    return leftMatch ? colorFor(leftMatch) : null;
  };

  const isWrongLeft = (id) => wrongHL[id];
  const isWrongRight = (id) => Object.values(wrongHL).includes(id);

  return (
    <window.PlayBody qtype="MATCHING" dark={dark}>
      <window.TypeBadge type="MATCHING" />
      <div>
        <h2 style={{ margin: '0 0 4px', fontSize: 18, fontWeight: 800, color: dark ? '#F1F5F9' : '#0F172A', lineHeight: 1.3 }}>
          Koppel begrip aan omschrijving
        </h2>
        <div style={{ fontSize: 13, color: dark ? '#94A3B8' : '#64748B' }}>
          Tik links, dan rechts — {Object.keys(pairs).filter(k=>k!=='activeLeft').length} van 4 gekoppeld
        </div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr auto 1fr', gap: 6, alignItems: 'center' }}>
        {left.map((l, i) => {
          const c = getPairColor(l.id, 'left');
          const isActive = pairs.activeLeft === l.id;
          const wrong = isWrongLeft(l.id);
          return (
            <React.Fragment key={l.id}>
              <div style={{
                padding: '11px 10px', borderRadius: 10,
                background: dark ? '#111827' : '#FFF',
                border: `2px solid ${wrong ? '#DC2626' : isActive ? '#0096C7' : c || (dark ? '#1E293B' : '#E2E8F0')}`,
                fontSize: 13, fontWeight: 700, color: dark ? '#F1F5F9' : '#0F172A',
                display: 'flex', alignItems: 'center', gap: 8,
                boxShadow: isActive ? '0 0 0 4px rgba(0,150,199,0.15)' : 'none',
              }}>
                <span style={{
                  width: 20, height: 20, borderRadius: 999,
                  background: c || (dark ? '#1E293B' : '#F1F5F9'),
                  flexShrink: 0,
                }}></span>
                <span style={{ flex: 1, minWidth: 0 }}>{l.label}</span>
              </div>
              <div style={{ width: 14 }}>
                {c && (
                  <svg width="14" height="2" viewBox="0 0 14 2"><line x1="0" y1="1" x2="14" y2="1" stroke={c} strokeWidth="2" strokeDasharray="2 2" /></svg>
                )}
              </div>
              {(() => {
                const r = right[i];
                const cR = getPairColor(r.id, 'right');
                const wR = isWrongRight(r.id);
                return (
                  <div style={{
                    padding: '11px 10px', borderRadius: 10,
                    background: dark ? '#111827' : '#FFF',
                    border: `2px solid ${wR ? '#DC2626' : cR || (dark ? '#1E293B' : '#E2E8F0')}`,
                    fontSize: 12.5, fontWeight: 600, color: dark ? '#F1F5F9' : '#0F172A',
                  }}>{r.label}</div>
                );
              })()}
            </React.Fragment>
          );
        })}
      </div>
      {state === 'wrong' && (
        <window.AnimatedFeedback dark={dark} kind="partial"
          text="3 van 4 goed"
          sub="Meiose is chromosomen­reductie, niet RNA-synthese."
        />
      )}
      {state === 'done' && (
        <window.AnimatedFeedback dark={dark} kind="correct"
          text="Volledig!" sub="+80 punten · alle 4 paren correct"
        />
      )}
      <div style={{ marginTop: 'auto' }}>
        {state === 'empty' && <window.CtaBar label="Controleer" disabled />}
        {state === 'pairing' && <window.CtaBar label="Controleer" disabled />}
        {state === 'wrong' && <window.CtaBar label="Volgende →" />}
        {state === 'done' && <window.CtaBar label="Volgende →" kind="success" />}
      </div>
    </window.PlayBody>
  );
}
window.MatchPlayer = MatchPlayer;

/* ═══════════════════════════════════════════════════════════════
   4 · ORDERING (drag with handles + tap-arrows)
═══════════════════════════════════════════════════════════════ */
function OrderPlayer({ state = 'empty', dark = false }) {
  // Mitose-stappen — current state vs correct
  const items = state === 'partial'
    ? [
        { n: 1, t: 'Telofase',  ok: false, was: 4 },
        { n: 2, t: 'Metafase',  ok: true },
        { n: 3, t: 'Anafase',   ok: true },
        { n: 4, t: 'Profase',   ok: false, was: 1 },
      ]
    : [
        { n: 1, t: 'Profase' },
        { n: 2, t: 'Metafase' },
        { n: 3, t: 'Anafase' },
        { n: 4, t: 'Telofase' },
      ];
  return (
    <window.PlayBody qtype="ORDERING" dark={dark}>
      <window.TypeBadge type="ORDERING" />
      <h2 style={{ margin: 0, fontSize: 18, fontWeight: 800, color: dark ? '#F1F5F9' : '#0F172A', lineHeight: 1.3 }}>
        Zet de mitose-stappen in juiste volgorde
      </h2>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
        {items.map((it, i) => {
          const wrong = state === 'partial' && it.ok === false;
          const right = state === 'partial' && it.ok === true;
          const empty = state === 'empty';
          return (
            <div key={it.n} style={{
              padding: '11px 10px', borderRadius: 10,
              background: dark ? '#111827' : '#FFF',
              border: wrong ? '2px solid #DC2626' : right ? '2px solid #16A34A'
                    : `2px solid ${dark ? '#1E293B' : '#E2E8F0'}`,
              display: 'flex', alignItems: 'center', gap: 10,
            }}>
              <span style={{ color: dark ? '#475569' : '#CBD5E1', cursor: 'grab' }}>
                <window.LucideIcon name="grip-vertical" size={18} />
              </span>
              <span style={{
                width: 26, height: 26, borderRadius: 999,
                background: wrong ? '#DC2626' : right ? '#16A34A' : '#0091B2',
                color: '#FFF', fontSize: 12, fontWeight: 900,
                display: 'grid', placeItems: 'center', flexShrink: 0,
              }}>{it.n}</span>
              <span style={{ flex: 1, fontSize: 14, fontWeight: 700, color: dark ? '#F1F5F9' : '#0F172A' }}>
                {it.t}
              </span>
              {/* Tap-arrows for accessibility */}
              <div style={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
                <button style={{ width: 22, height: 18, borderRadius: 4, border: 'none', background: dark ? '#1E293B' : '#F1F5F9', color: dark ? '#94A3B8' : '#64748B', display: 'grid', placeItems: 'center', cursor: 'pointer', opacity: i === 0 ? 0.3 : 1 }} disabled={i===0}>
                  <window.LucideIcon name="chevron-up" size={12} />
                </button>
                <button style={{ width: 22, height: 18, borderRadius: 4, border: 'none', background: dark ? '#1E293B' : '#F1F5F9', color: dark ? '#94A3B8' : '#64748B', display: 'grid', placeItems: 'center', cursor: 'pointer', opacity: i === items.length-1 ? 0.3 : 1 }} disabled={i===items.length-1}>
                  <window.LucideIcon name="chevron-down" size={12} />
                </button>
              </div>
            </div>
          );
        })}
      </div>
      {state === 'partial' && (
        <window.AnimatedFeedback dark={dark} kind="partial"
          text="2 van 4 op juiste plek"
          sub="Profase komt eerst, Telofase als laatste."
        />
      )}
      <div style={{ marginTop: 'auto' }}>
        {state === 'empty' && <window.CtaBar label="Controleer" />}
        {state === 'partial' && <window.CtaBar label="Volgende →" />}
      </div>
    </window.PlayBody>
  );
}
window.OrderPlayer = OrderPlayer;

/* ═══════════════════════════════════════════════════════════════
   5 · FILL_IN_BLANK (inline blanks)
═══════════════════════════════════════════════════════════════ */
function FillPlayer({ state = 'empty', dark = false, hintRevealed = false }) {
  const blank1 = state === 'empty' ? '' : 'samengestel';
  const blank2 = state === 'empty' ? '' : 'elektri';
  return (
    <window.PlayBody qtype="FILL_IN_BLANK" dark={dark}>
      <window.TypeBadge type="FILL_IN_BLANK" />
      <h2 style={{ margin: 0, fontSize: 17, fontWeight: 800, color: dark ? '#F1F5F9' : '#0F172A', lineHeight: 1.3 }}>
        Vul de ontbrekende woorden in:
      </h2>
      <div style={{ fontSize: 16, lineHeight: 1.9, color: dark ? '#F1F5F9' : '#0F172A' }}>
        Tijdens elektrolyse wordt een{' '}
        <span style={{
          display: 'inline-block', minWidth: 110, padding: '1px 8px',
          borderBottom: state === 'partial' ? '2px solid #16A34A' : `2px solid ${dark ? '#475569' : '#94A3B8'}`,
          fontWeight: 700,
          color: state === 'partial' ? '#16A34A' : (dark ? '#F1F5F9' : '#0F172A'),
        }}>
          {state === 'partial' ? <>samengestelde <window.LucideIcon name="check" size={12} color="#16A34A" /></> : blank1 || ' '}
        </span>{' '}
        stof gesplitst door middel van{' '}
        <span style={{
          display: 'inline-block', minWidth: 90, padding: '1px 8px',
          borderBottom: state === 'partial' ? '2px solid #DC2626' : `2px solid ${dark ? '#475569' : '#94A3B8'}`,
          fontWeight: 700,
          color: state === 'partial' ? '#DC2626' : (dark ? '#F1F5F9' : '#0F172A'),
        }}>
          {state === 'partial' ? <>elektri <window.LucideIcon name="x" size={12} color="#DC2626" /></> : blank2 || ' '}
        </span>.
        {state === 'partial' && (
          <div style={{ fontSize: 13, color: '#16A34A', marginTop: 6, fontWeight: 600 }}>
            Correct: <i>elektrische energie</i>
          </div>
        )}
      </div>
      {hintRevealed && (
        <div style={{
          padding: 10, borderRadius: 10, background: dark ? 'rgba(245,158,11,0.10)' : '#FEF3C7',
          border: `1px solid ${dark ? 'rgba(245,158,11,0.25)' : '#FDE68A'}`,
          fontSize: 13, color: '#92400E', display: 'flex', gap: 8, alignItems: 'flex-start',
        }}>
          <window.LucideIcon name="lightbulb" size={14} />
          <span><b>Tip:</b> Het tweede woord begint met "elektr…"</span>
        </div>
      )}
      {state === 'partial' && (
        <window.AnimatedFeedback dark={dark} kind="partial"
          text="1 van 2 goed" sub="+25 punten — half"
        />
      )}
      <div style={{ marginTop: 'auto' }}>
        {state === 'empty' && <window.CtaBar label="Controleer" disabled />}
        {state === 'partial' && <window.CtaBar label="Volgende →" />}
      </div>
    </window.PlayBody>
  );
}
window.FillPlayer = FillPlayer;

/* ═══════════════════════════════════════════════════════════════
   6 · CONTEXTUAL (reading + AI validation)
═══════════════════════════════════════════════════════════════ */
function ContextPlayer({ state = 'empty', dark = false }) {
  const text = state === 'wrong' ? 'fotosynthese' : state === 'validating' ? 'Chlorofyl' : state === 'correct' ? 'Chlorofyl' : 'Chloro';
  return (
    <window.PlayBody qtype="CONTEXTUAL" dark={dark}>
      <window.TypeBadge type="CONTEXTUAL" />
      {/* Leestekst */}
      <div style={{
        padding: '12px 14px', borderLeft: '3px solid #4F46E5',
        background: dark ? 'rgba(79,70,229,0.10)' : '#EEF2FF',
        borderRadius: '0 10px 10px 0',
      }}>
        <div style={{ fontSize: 10, fontWeight: 800, color: '#4F46E5', letterSpacing: 1, marginBottom: 4 }}>LEESTEKST</div>
        <p style={{ margin: 0, fontSize: 13, lineHeight: 1.5, color: dark ? '#E0E7FF' : '#1E1B4B' }}>
          Planten maken hun eigen voedsel via fotosynthese. Dit proces vindt plaats in de chloroplasten,
          waar het groene pigment{' '}
          {state === 'correct' ? <mark style={{ background: '#86EFAC', borderRadius: 3, padding: '0 3px' }}>chlorofyl</mark> : <b>chlorofyl</b>}
          {' '}zonlicht absorbeert.
        </p>
      </div>
      <h2 style={{ margin: 0, fontSize: 16, fontWeight: 800, color: dark ? '#F1F5F9' : '#0F172A', lineHeight: 1.3 }}>
        Welk pigment zorgt voor de groene kleur van planten?
      </h2>
      <div style={{
        height: 48, borderRadius: 12, padding: '0 14px',
        border: state === 'correct' ? '2px solid #16A34A'
              : state === 'wrong' ? '2px solid #DC2626'
              : `2px solid ${dark ? '#1E293B' : '#E2E8F0'}`,
        background: state === 'validating' ? (dark ? '#1E293B' : '#F8FAFC') : (dark ? '#111827' : '#FFF'),
        display: 'flex', alignItems: 'center', gap: 8,
        opacity: state === 'validating' ? 0.7 : 1,
      }}>
        {state === 'validating' && <window.LucideIcon name="loader-2" size={16} color="#0096C7" />}
        <span style={{ fontSize: 15, fontWeight: 600, color: state === 'wrong' ? '#DC2626' : state === 'correct' ? '#16A34A' : (dark ? '#F1F5F9' : '#0F172A') }}>
          {state === 'empty' ? <span style={{ color: dark ? '#475569' : '#94A3B8', fontWeight: 500 }}>Type je antwoord…</span> : text}
        </span>
        {state === 'correct' && <window.LucideIcon name="check" size={18} color="#16A34A" style={{ marginLeft: 'auto' }} />}
        {state === 'wrong' && <window.LucideIcon name="x" size={18} color="#DC2626" style={{ marginLeft: 'auto' }} />}
      </div>
      {state === 'validating' && (
        <div style={{ fontSize: 12, color: dark ? '#94A3B8' : '#64748B', textAlign: 'center', display: 'flex', alignItems: 'center', gap: 6, justifyContent: 'center' }}>
          <window.LucideIcon name="sparkles" size={12} color="#0096C7" />
          Pulse controleert je antwoord…
        </div>
      )}
      {state === 'wrong' && (
        <window.AnimatedFeedback dark={dark} kind="wrong"
          text="Niet helemaal" sub='Het was "chlorofyl" — het groene pigment, niet het proces.'
        />
      )}
      {state === 'correct' && (
        <window.AnimatedFeedback dark={dark} kind="correct"
          text="Klopt!" sub="+22 punten · streak 2× · chlorofyl is gehighlight in de tekst."
        />
      )}
      <div style={{ marginTop: 'auto' }}>
        {state === 'empty' && <window.CtaBar label="Controleer" disabled />}
        {state === 'validating' && <window.CtaBar label="Controleren…" disabled />}
        {(state === 'wrong' || state === 'correct') && <window.CtaBar label="Volgende →" kind={state === 'correct' ? 'success' : 'primary'} />}
      </div>
    </window.PlayBody>
  );
}
window.ContextPlayer = ContextPlayer;

/* ═══════════════════════════════════════════════════════════════
   7 · MULTI_FIELD (form with text + radio)
═══════════════════════════════════════════════════════════════ */
function MultiFieldPlayer({ state = 'empty', dark = false }) {
  return (
    <window.PlayBody qtype="MULTI_FIELD" dark={dark}>
      <window.TypeBadge type="MULTI_FIELD" />
      <h2 style={{ margin: 0, fontSize: 18, fontWeight: 800, color: dark ? '#F1F5F9' : '#0F172A', lineHeight: 1.3 }}>
        Beschrijf de mitose
      </h2>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {/* Field: duur */}
        <Field
          dark={dark}
          label="DUUR"
          val={state === 'empty' ? '' : '1-2 uur'}
          status={state === 'partial' || state === 'all-wrong' ? 'wrong' : null}
          hint={state === 'partial' || state === 'all-wrong' ? 'Correct: variabel, 1-24 uur' : null}
        />
        {/* Field: resultaat */}
        <Field
          dark={dark}
          label="RESULTAAT"
          val={state === 'empty' ? '' : '2 identieke dochtercellen'}
          status={state === 'partial' ? 'correct' : state === 'all-wrong' ? 'wrong' : null}
        />
        {/* Field: celtype (radio) */}
        <div style={{
          padding: '10px 12px', borderRadius: 12,
          border: `1px solid ${dark ? '#1E293B' : '#E2E8F0'}`,
          background: dark ? '#111827' : '#FFF',
        }}>
          <div style={{ fontSize: 10, fontWeight: 800, color: dark ? '#94A3B8' : '#64748B', letterSpacing: 1, marginBottom: 6 }}>CELTYPE</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
            {['Geslachtscel', 'Lichaamscel', 'Stamcel'].map(o => {
              const sel = state !== 'empty' && o === 'Lichaamscel';
              const correctOpt = state === 'partial' && o === 'Lichaamscel';
              return (
                <div key={o} style={{
                  padding: '8px 10px', borderRadius: 8,
                  background: correctOpt ? (dark ? 'rgba(34,197,94,0.12)' : '#F0FDF4')
                    : sel ? (dark ? 'rgba(0,180,216,0.12)' : '#EFF9FF') : 'transparent',
                  display: 'flex', alignItems: 'center', gap: 10,
                  border: correctOpt ? '1px solid #16A34A' : '1px solid transparent',
                }}>
                  <span style={{
                    width: 14, height: 14, borderRadius: 999,
                    border: `2px solid ${sel ? (correctOpt ? '#16A34A' : '#0096C7') : (dark ? '#475569' : '#CBD5E1')}`,
                    background: sel ? (correctOpt ? '#16A34A' : '#0096C7') : 'transparent',
                    boxShadow: sel ? `inset 0 0 0 2px ${correctOpt ? '#F0FDF4' : '#EFF9FF'}` : 'none',
                  }}></span>
                  <span style={{ fontSize: 13, fontWeight: 600, color: dark ? '#F1F5F9' : '#0F172A' }}>{o}</span>
                  {correctOpt && <window.LucideIcon name="check" size={14} color="#16A34A" style={{ marginLeft: 'auto' }} />}
                </div>
              );
            })}
          </div>
        </div>
      </div>
      {state === 'partial' && (
        <window.AnimatedFeedback dark={dark} kind="partial"
          text="2 van 3 goed" sub="+27 van 40 punten · duur was niet 1-2 uur."
        />
      )}
      <div style={{ marginTop: 'auto' }}>
        {state === 'empty' && <window.CtaBar label="Controleer" disabled />}
        {state === 'filled' && <window.CtaBar label="Controleer" />}
        {state === 'partial' && <window.CtaBar label="Volgende →" />}
      </div>
    </window.PlayBody>
  );
}
window.MultiFieldPlayer = MultiFieldPlayer;

function Field({ dark, label, val, status, hint }) {
  const border = status === 'correct' ? '#16A34A' : status === 'wrong' ? '#DC2626' : (dark ? '#1E293B' : '#E2E8F0');
  return (
    <div style={{
      padding: '10px 12px', borderRadius: 12,
      border: `${status ? '2px' : '1px'} solid ${border}`,
      background: dark ? '#111827' : '#FFF',
    }}>
      <div style={{ fontSize: 10, fontWeight: 800, color: dark ? '#94A3B8' : '#64748B', letterSpacing: 1, marginBottom: 4 }}>{label}</div>
      <div style={{ fontSize: 14, fontWeight: 700, color: dark ? '#F1F5F9' : '#0F172A', minHeight: 20, display: 'flex', alignItems: 'center', gap: 8 }}>
        {val || <span style={{ color: dark ? '#475569' : '#94A3B8', fontWeight: 500 }}>—</span>}
        {status === 'correct' && <window.LucideIcon name="check" size={14} color="#16A34A" style={{ marginLeft: 'auto' }} />}
        {status === 'wrong' && <window.LucideIcon name="x" size={14} color="#DC2626" style={{ marginLeft: 'auto' }} />}
      </div>
      {hint && <div style={{ fontSize: 11, color: '#DC2626', fontWeight: 600, marginTop: 4 }}>{hint}</div>}
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════════
   8 · TABLE_FILL
═══════════════════════════════════════════════════════════════ */
function TablePlayer({ state = 'empty', dark = false }) {
  return (
    <window.PlayBody qtype="TABLE_FILL" dark={dark}>
      <window.TypeBadge type="TABLE_FILL" />
      <h2 style={{ margin: 0, fontSize: 17, fontWeight: 800, color: dark ? '#F1F5F9' : '#0F172A', lineHeight: 1.3 }}>
        Welke celdelen komen voor in dier- en plantencellen?
      </h2>
      <div style={{
        borderRadius: 10, overflow: 'hidden',
        border: `1px solid ${dark ? '#1E293B' : '#E2E8F0'}`,
      }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
          <thead>
            <tr style={{ background: dark ? '#0A0F1E' : '#F1F5F9' }}>
              <th style={{ padding: 8, textAlign: 'left', fontSize: 10, fontWeight: 800, letterSpacing: 0.5, color: dark ? '#94A3B8' : '#64748B' }}>CELDEEL</th>
              <th style={{ padding: 8, fontSize: 10, fontWeight: 800, letterSpacing: 0.5, color: dark ? '#94A3B8' : '#64748B' }}>DIERCEL</th>
              <th style={{ padding: 8, fontSize: 10, fontWeight: 800, letterSpacing: 0.5, color: dark ? '#94A3B8' : '#64748B' }}>PLANTCEL</th>
            </tr>
          </thead>
          <tbody>
            {[
              { c: 'Celwand',     d: 'wrong', p: 'right' },
              { c: 'Celkern',     d: state === 'partial' ? 'right' : 'empty',  p: state === 'partial' ? 'right' : 'empty' },
              { c: 'Chloroplast', d: state === 'partial' ? 'wrong' : 'empty',  p: state === 'partial' ? 'right' : 'empty' },
              { c: 'Mitochondriën',d:'empty',                                  p: 'right' },
            ].map((r, i) => (
              <tr key={i} style={{ borderTop: `1px solid ${dark ? '#1E293B' : '#E2E8F0'}` }}>
                <td style={{ padding: 9, fontWeight: 700, color: dark ? '#F1F5F9' : '#0F172A' }}>{r.c}</td>
                <td style={{ padding: 9, textAlign: 'center' }}><Cell v={r.d} dark={dark} /></td>
                <td style={{ padding: 9, textAlign: 'center' }}><Cell v={r.p} dark={dark} /></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      {state === 'partial' && (
        <window.AnimatedFeedback dark={dark} kind="partial"
          text="5 van 8 cellen goed" sub="+50 van 80 punten · chloroplast in diercel = fout."
        />
      )}
      <div style={{ marginTop: 'auto' }}>
        {state === 'empty' && <window.CtaBar label="Controleer" disabled />}
        {state === 'filling' && <window.CtaBar label="Controleer" />}
        {state === 'partial' && <window.CtaBar label="Volgende →" />}
      </div>
    </window.PlayBody>
  );
}
window.TablePlayer = TablePlayer;

function Cell({ v, dark }) {
  if (v === 'right') return <window.LucideIcon name="check" size={16} color="#16A34A" />;
  if (v === 'wrong') return <window.LucideIcon name="x" size={16} color="#DC2626" />;
  return <span style={{ color: dark ? '#475569' : '#CBD5E1', fontSize: 14 }}>—</span>;
}

/* ═══════════════════════════════════════════════════════════════
   9 · IMAGE_BASED (NEW — greenfield) — hotspot tap
═══════════════════════════════════════════════════════════════ */
function ImagePlayer({ state = 'empty', dark = false }) {
  // Topografie: "Klik op Frankrijk"
  const showCorrectMarker = state === 'correct' || state === 'wrong';
  const showUserMarker = state !== 'empty';
  return (
    <window.PlayBody qtype="IMAGE_BASED" dark={dark}>
      <window.TypeBadge type="IMAGE_BASED" />
      <h2 style={{ margin: 0, fontSize: 18, fontWeight: 800, color: dark ? '#F1F5F9' : '#0F172A', lineHeight: 1.3 }}>
        Tik op Frankrijk
      </h2>
      <div style={{
        position: 'relative', width: '100%', aspectRatio: '4/3',
        background: dark ? '#0A0F1E' : '#EFF9FF',
        borderRadius: 12, border: `1px solid ${dark ? '#1E293B' : '#BAE6FD'}`,
        overflow: 'hidden',
      }}>
        {/* Stylized Europe placeholder */}
        <svg viewBox="0 0 400 300" style={{ width: '100%', height: '100%', display: 'block' }}>
          <rect width="400" height="300" fill={dark ? '#0A0F1E' : '#EFF9FF'} />
          {/* shapes */}
          <path d="M120,80 Q130,60 160,65 L200,70 Q220,90 215,130 L195,170 Q170,180 150,170 L120,140 Q100,120 110,100 Z"
            fill={state === 'wrong' ? '#FCA5A5' : (dark ? '#1E293B' : '#FFF')}
            stroke={dark ? '#475569' : '#94A3B8'} strokeWidth="1.2"/>
          {/* France highlighted on correct/wrong */}
          <path d="M140,180 Q145,160 165,158 L195,165 Q210,180 205,210 L185,235 Q165,240 150,225 L138,205 Z"
            fill={showCorrectMarker ? (state === 'correct' ? '#86EFAC' : 'rgba(134,239,172,0.55)') : (dark ? '#111827' : '#FFFFFF')}
            stroke={showCorrectMarker ? '#16A34A' : (dark ? '#475569' : '#94A3B8')}
            strokeWidth={showCorrectMarker ? 2 : 1.2}/>
          {/* Other countries */}
          <path d="M210,140 L260,135 Q275,165 265,200 L235,210 L215,180 Z"
            fill={dark ? '#1E293B' : '#FFF'} stroke={dark ? '#475569' : '#94A3B8'} strokeWidth="1.2"/>
          <path d="M225,80 L295,75 Q305,110 290,135 L240,140 L215,115 Z"
            fill={dark ? '#1E293B' : '#FFF'} stroke={dark ? '#475569' : '#94A3B8'} strokeWidth="1.2"/>

          {/* User marker */}
          {showUserMarker && state === 'wrong' && (
            <g style={{ transformOrigin: '255px 165px', animation: 'scaleIn .25s ease' }}>
              <circle cx="255" cy="165" r="12" fill="#DC2626" stroke="#FFF" strokeWidth="3"/>
              <line x1="248" y1="158" x2="262" y2="172" stroke="#FFF" strokeWidth="2.4" strokeLinecap="round"/>
              <line x1="262" y1="158" x2="248" y2="172" stroke="#FFF" strokeWidth="2.4" strokeLinecap="round"/>
            </g>
          )}
          {showUserMarker && state === 'correct' && (
            <g style={{ transformOrigin: '170px 195px' }}>
              <circle cx="170" cy="195" r="14" fill="#16A34A" stroke="#FFF" strokeWidth="3"/>
              <path d="M163,195 L168,200 L177,189" stroke="#FFF" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
            </g>
          )}
          {showUserMarker && state === 'aiming' && (
            <circle cx="170" cy="195" r="10" fill="rgba(0,150,199,0.4)" stroke="#0096C7" strokeWidth="2" style={{ animation: 'pulseRing 1.4s infinite' }}/>
          )}
          {/* "Antwoord-pin" arrow when wrong */}
          {state === 'wrong' && (
            <g>
              <line x1="170" y1="195" x2="170" y2="195" stroke="#16A34A" strokeWidth="2"/>
              <circle cx="170" cy="195" r="9" fill="rgba(22,163,74,0.4)" stroke="#16A34A" strokeWidth="2" strokeDasharray="3 2"/>
            </g>
          )}
        </svg>
        <div style={{
          position: 'absolute', bottom: 8, right: 10,
          fontSize: 10, fontWeight: 700, letterSpacing: 0.5,
          color: dark ? '#475569' : '#94A3B8',
        }}>WEST-EUROPA</div>
      </div>
      {state === 'aiming' && (
        <div style={{ fontSize: 12, color: dark ? '#94A3B8' : '#64748B', textAlign: 'center' }}>
          Tik op de kaart om je antwoord te plaatsen.
        </div>
      )}
      {state === 'wrong' && (
        <window.AnimatedFeedback dark={dark} kind="wrong"
          text="Net niet — dat was Duitsland."
          sub="De groen-gestippelde gebied = Frankrijk."
        />
      )}
      {state === 'correct' && (
        <window.AnimatedFeedback dark={dark} kind="correct"
          text="Klopt!" sub="+45 punten · binnen 2 sec geraakt"
        />
      )}
      <div style={{ marginTop: 'auto' }}>
        {state === 'empty' && <window.CtaBar label="Tik eerst op de kaart" disabled />}
        {state === 'aiming' && <window.CtaBar label="Bevestig" />}
        {(state === 'wrong' || state === 'correct') && <window.CtaBar label="Volgende →" kind={state === 'correct' ? 'success' : 'primary'} />}
      </div>
    </window.PlayBody>
  );
}
window.ImagePlayer = ImagePlayer;

/* ═══════════════════════════════════════════════════════════════
   10 · FEYNMAN — global mode variant (every q gets explain-prompt)
═══════════════════════════════════════════════════════════════ */
function FeynmanPlayer({ state = 'empty', dark = false }) {
  // Reuses MC question, but adds explain-step
  return (
    <window.PlayBody qtype="MULTIPLE_CHOICE" dark={dark}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        <span style={{
          padding: '4px 10px', borderRadius: 999, fontSize: 11, fontWeight: 800, letterSpacing: 0.4,
          background: 'linear-gradient(135deg,#7C3AED,#0096C7)', color: '#FFF',
          display: 'inline-flex', alignItems: 'center', gap: 5,
        }}>
          <window.LucideIcon name="sparkles" size={11} /> FEYNMAN MODUS
        </span>
        <window.TypeBadge type="MULTIPLE_CHOICE" />
      </div>
      <h2 style={{ margin: 0, fontSize: 17, fontWeight: 800, color: dark ? '#F1F5F9' : '#0F172A', lineHeight: 1.3 }}>
        Wat is fotosynthese?
      </h2>
      {state === 'empty' && (
        <>
          <div style={{ fontSize: 13, color: dark ? '#94A3B8' : '#64748B' }}>
            Geef eerst je antwoord, leg dan uit voor een 10-jarige.
          </div>
          {[
            { l: 'A', t: 'Hoe planten energie maken uit zonlicht', sel: true },
            { l: 'B', t: 'Hoe planten ademen' },
          ].map(o => (
            <div key={o.l} style={{
              padding: '12px 14px', borderRadius: 12,
              background: o.sel ? (dark ? 'rgba(0,180,216,0.12)' : '#EFF9FF') : (dark ? '#111827' : '#FFF'),
              border: `2px solid ${o.sel ? '#0096C7' : (dark ? '#1E293B' : '#E2E8F0')}`,
              display: 'flex', alignItems: 'center', gap: 12, fontSize: 14, fontWeight: 600,
              color: dark ? '#F1F5F9' : '#0F172A',
            }}>
              <span style={{
                width: 26, height: 26, borderRadius: 8,
                background: o.sel ? '#0096C7' : (dark ? '#1E293B' : '#F1F5F9'),
                color: o.sel ? '#FFF' : (dark ? '#94A3B8' : '#64748B'),
                display: 'grid', placeItems: 'center', fontWeight: 900, fontSize: 12,
              }}>{o.l}</span>
              {o.t}
            </div>
          ))}
        </>
      )}
      {(state === 'explaining' || state === 'evaluated') && (
        <>
          <div style={{
            padding: 10, borderRadius: 10,
            background: dark ? 'rgba(34,197,94,0.10)' : '#F0FDF4',
            border: `1px solid ${dark ? 'rgba(34,197,94,0.25)' : '#BBF7D0'}`,
            fontSize: 12, color: '#16A34A', display: 'flex', gap: 8, alignItems: 'center',
          }}>
            <window.LucideIcon name="check" size={14} />
            Antwoord A correct · nu uitleggen voor een 10-jarige
          </div>
          <div style={{
            padding: '12px 14px', borderRadius: 12,
            background: dark ? '#111827' : '#FFF',
            border: `2px solid ${state === 'evaluated' ? '#7C3AED' : (dark ? '#1E293B' : '#E2E8F0')}`,
            fontSize: 13, lineHeight: 1.55, color: dark ? '#F1F5F9' : '#0F172A',
            minHeight: 90,
          }}>
            {state === 'explaining'
              ? <span style={{ color: dark ? '#475569' : '#94A3B8' }}>Schrijf in eigen woorden, alsof je 'n broertje of zusje uitlegt…</span>
              : <span>Planten zijn net keukens. Hun groene blaadjes vangen zonlicht, mengen dat met water uit de wortels en lucht, en bakken zo eigen suiker. Daarvan groeien ze.</span>
            }
          </div>
          <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: dark ? '#94A3B8' : '#64748B' }}>
            <span>{state === 'evaluated' ? '178 / 250 tekens' : '0 / 250 tekens'}</span>
            <span>min. 80 tekens</span>
          </div>
          {state === 'evaluated' && (
            <div style={{
              padding: '10px 12px', borderRadius: 10,
              background: dark ? 'rgba(124,58,237,0.12)' : '#F5F3FF',
              border: `1px solid ${dark ? 'rgba(124,58,237,0.30)' : '#DDD6FE'}`,
            }}>
              <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 4 }}>
                <window.LucideIcon name="sparkles" size={14} color="#7C3AED" />
                <span style={{ fontSize: 12, fontWeight: 800, color: '#6D28D9' }}>Pulse beoordeelt — 9/10 helderheid</span>
              </div>
              <div style={{ fontSize: 12.5, color: dark ? '#DDD6FE' : '#4C1D95', lineHeight: 1.5 }}>
                "Sterke metafoor (keuken). Eén ding ontbreekt: noem ook <i>zuurstof</i> als bijproduct."
              </div>
            </div>
          )}
        </>
      )}
      <div style={{ marginTop: 'auto' }}>
        {state === 'empty' && <window.CtaBar label="Bevestig antwoord" />}
        {state === 'explaining' && <window.CtaBar label="Pulse laten beoordelen" disabled />}
        {state === 'evaluated' && <window.CtaBar label="Volgende vraag →" kind="success" />}
      </div>
    </window.PlayBody>
  );
}
window.FeynmanPlayer = FeynmanPlayer;
