/* components.jsx — pixel UI in Dutch.
   Globals exported on window:
     Avatar, NavTabs, VillagerCard, RecipeCard, StudentDetail,
     RecipesPage, ChestBanner, DonateModal, ClassCraftModal,
     AdminLoginModal, Toasts
*/

const { useState, useEffect, useMemo, useRef } = React;

// ===========================================================
// Avatar
// ===========================================================
function Avatar({ student, allowUpload = false, onUpload }) {
  const fileRef = useRef(null);
  const handlePick = (e) => {
    const f = e.target.files?.[0];
    if (f) onUpload?.(f);
    e.target.value = '';
  };
  return (
    <div className="avatar-block">
      {student.avatar
        ? <img src={student.avatar} alt={student.name}/>
        : <PixelAvatar seed={student.id}/>}
      {allowUpload && (
        <>
          <input ref={fileRef} type="file" accept="image/*" hidden onChange={handlePick}/>
          <button
            onClick={(e) => { e.stopPropagation(); fileRef.current?.click(); }}
            style={{
              position: 'absolute', bottom: 0, left: 0, right: 0,
              background: 'rgba(6,5,11,0.85)',
              fontFamily: 'var(--font-disp)', fontSize: 9,
              letterSpacing: 1.5, color: 'var(--ender-hi)',
              padding: '6px', textTransform: 'uppercase',
              borderTop: '2px solid var(--ender)',
            }}
          >
            Foto uploaden
          </button>
        </>
      )}
    </div>
  );
}

// ===========================================================
// NavTabs
// ===========================================================
function NavTabs({ value, onChange }) {
  const tabs = [
    { id: 'roster',  label: 'Klaslijst' },
    { id: 'recipes', label: 'Recepten'  },
  ];
  return (
    <div className="tabs">
      {tabs.map(t => (
        <button
          key={t.id}
          className={`tab ${value === t.id ? 'active' : ''}`}
          onClick={() => onChange(t.id)}
        >{t.label}</button>
      ))}
    </div>
  );
}

// ===========================================================
// VillagerCard
// ===========================================================
function VillagerCard({ student, onOpen }) {
  const firstName = student.name.split(' ')[0];

  const baseKeys      = ['water', 'paddenstoel', 'zand'];
  const rareKeys      = ['lava', 'zeewier', 'fles'];
  const legendaryKeys = ['enderparel', 'enderpoeder'];

  return (
    <div className="villager-card" onClick={onOpen}>
      <div className="inner">
        <h3 className="villager-name">{firstName}</h3>

        <Avatar student={student}/>

        <div className="rows">
          <div className="row-strip tier-1">
            {baseKeys.map(k => {
              const qty = student.inventory[k] || 0;
              return (
                <div key={k} className={`slot ${qty === 0 ? 'zero' : ''}`} title={ITEMS[k].name}>
                  <ItemIcon itemKey={k} size={20}/> {qty}
                </div>
              );
            })}
          </div>

          <div className="row-strip tier-2">
            {rareKeys.map(k => {
              const qty = student.inventory[k] || 0;
              return (
                <div key={k} className={`slot ${qty === 0 ? 'zero' : ''}`} title={ITEMS[k].name}>
                  <ItemIcon itemKey={k} size={20}/> {qty}
                </div>
              );
            })}
          </div>

          <div className="row-strip tier-3">
            {legendaryKeys.map(k => {
              const qty = student.inventory[k] || 0;
              return (
                <div key={k} className={`slot ${qty === 0 ? 'zero' : ''}`} title={ITEMS[k].name}>
                  <ItemIcon itemKey={k} size={20}/> {qty}
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
}

// ===========================================================
// RecipeCard — grey by default, purple border for class recipes;
//              craftable state stays purple highlight.
// ===========================================================
function RecipeCard({
  recipe, supply, onCraft,
  craftLabel = 'Maken',
  hideButton = false,
  catalogMode = false,
}) {
  const craftable = !catalogMode && recipe.cost.every(([k, q]) => (supply?.[k] || 0) >= q);
  const catClass = `cat-${recipe.category}`;
  return (
    <div className={`recipe-card ${catClass} ${catalogMode ? '' : (craftable ? 'craftable' : '')}`}>
      <div className="recipe-inner">
        <div className="recipe-head">
          <div className="recipe-icon-box"><ItemIcon itemKey={recipe.output} size={28} glow={craftable}/></div>
          <div>
            <p className="recipe-name">{recipe.name}</p>
            <span className="recipe-tag">{RECIPE_CATEGORY_LABEL[recipe.category]}</span>
          </div>
        </div>

        {recipe.explanation && (
          <p className="recipe-explanation">{recipe.explanation}</p>
        )}

        <div className="recipe-cost">
          {recipe.cost.map(([k, q]) => {
            const have = supply?.[k] || 0;
            const missing = !catalogMode && have < q;
            return (
              <span key={k} className={`cost-chip ${missing ? 'missing' : ''}`} title={ITEMS[k].name}>
                <ItemIcon itemKey={k} size={14}/>
                ×{q}
                {!catalogMode && <span className="have">({have})</span>}
              </span>
            );
          })}
        </div>

        {!hideButton && (
          <button
            className={`craft-btn ${craftable ? 'enabled' : ''}`}
            disabled={!craftable}
            onClick={(e) => onCraft?.(recipe, e)}
          >
            {craftable ? craftLabel : 'Te weinig'}
          </button>
        )}
      </div>
    </div>
  );
}

// ===========================================================
// StudentDetail
// ===========================================================
function StudentDetail({ student, adminMode, recipes, onClose, onCraft, onDonate, onGift, onUploadAvatar }) {
  useEffect(() => {
    const h = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, [onClose]);

  const firstName = student.name.split(' ')[0];

  const craftable = recipes.filter(r => r.cost.every(([k, q]) => (student.inventory[k] || 0) >= q));

  const ownedKeys = Object.entries(student.inventory)
    .filter(([, v]) => v > 0)
    .map(([k]) => k)
    .sort((a, b) => (ITEMS[a]?.tier ?? 9) - (ITEMS[b]?.tier ?? 9));

  return (
    <div className="detail-overlay" onClick={onClose}>
      <div className="detail-panel" onClick={(e) => e.stopPropagation()}>
        <div className="detail-inner">
          <div className="detail-head">
            <Avatar student={student} allowUpload={adminMode} onUpload={onUploadAvatar}/>
            <div style={{ flex: 1, minWidth: 0 }}>
              <h2 className="name">Werkbank van {firstName}</h2>
              <div className="meta">Inwoner · ID {String(student.id).padStart(3,'0')}</div>
            </div>
            <button className="detail-close" onClick={onClose} title="Sluit (Esc)">✕</button>
          </div>

          <div className="detail-body">
            <p className="section-eyebrow">Inventaris</p>
            <div className="you-have">
              {ownedKeys.length === 0 && <span className="muted">Lege inventaris.</span>}
              {ownedKeys.map(k => (
                <span key={k} className="have-chip" title={ITEMS[k]?.name}>
                  <ItemIcon itemKey={k} size={16}/>
                  <span>{ITEMS[k]?.name}</span>
                  <span style={{ color: 'var(--ender-hi)' }}>×{student.inventory[k]}</span>
                </span>
              ))}
            </div>

            <div style={{ height: 30 }}/>

            <p className="section-eyebrow">Wat {firstName} nu kan maken</p>
            <h2 className="section-heading">
              {craftable.length === 0
                ? 'Nog niets — verzamel meer materialen!'
                : `${craftable.length} recept${craftable.length === 1 ? '' : 'en'} klaar`}
            </h2>

            {craftable.length > 0 && (
              <div className="recipe-grid">
                {craftable.map(r => (
                  <RecipeCard
                    key={r.key}
                    recipe={r}
                    supply={student.inventory}
                    onCraft={(recipe, e) => onCraft(student.id, recipe, e)}
                    craftLabel="Maak het"
                  />
                ))}
              </div>
            )}

            <div className="cta-bar">
              {adminMode && (
                <button className="btn-pixel violet" onClick={onGift}>
                  <span>＋</span> Geef materiaal
                </button>
              )}
              <button className="btn-pixel" onClick={onDonate}>
                <span>★</span> Doneer aan Klaskist
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ===========================================================
// ChestBanner — compact horizontal class chest at top of roster
// ===========================================================
function ChestBanner({ classChest, classRewards, adminMode, recipes, onOpenClassCraft, onGiftToChest }) {
  const trackedKeys = [
    'water', 'paddenstoel', 'zand',
    'lava', 'zeewier', 'fles',
    'enderparel', 'enderpoeder',
  ];
  const totalDonated = trackedKeys.reduce((a, k) => a + (classChest[k] || 0), 0);
  const classRecipes = recipes.filter(r => r.category === 'class');
  const anyCraftable = classRecipes.some(r =>
    r.cost.every(([k, q]) => (classChest[k] || 0) >= q));

  // In teacher mode the whole banner is a click target. Buttons inside stop
  // propagation so they keep their own behaviour.
  const handleBannerClick = adminMode
    ? (e) => {
        if (e.target.closest('button')) return;
        onGiftToChest?.();
      }
    : undefined;

  return (
    <div
      className={`chest-banner ${adminMode ? 'clickable' : ''}`}
      onClick={handleBannerClick}
      role={adminMode ? 'button' : undefined}
      title={adminMode ? 'Klik om materiaal aan de kist te geven' : undefined}
    >
      <div className="inner">
        <div className="title">
          <div className="title-mark">⬛</div>
          <div>
            <h2>Klaskist</h2>
            <div className="sub">
              {totalDonated} gedoneerd
              {classRewards.length > 0 && ` · ${classRewards.length} klasbeloning${classRewards.length === 1 ? '' : 'en'}`}
              {adminMode && <span className="gift-hint"> · klik om te geven</span>}
            </div>
          </div>
        </div>

        <div className="chest-stash">
          {trackedKeys.map(k => {
            const qty = classChest[k] || 0;
            return (
              <span key={k} className={`stash-slot ${qty > 0 ? 'has' : 'empty'}`} title={ITEMS[k].name}>
                <ItemIcon itemKey={k} size={20} glow={qty > 0}/>
                <span className="val">{qty}</span>
              </span>
            );
          })}
        </div>

        <div className="actions">
          <button
            className="btn-pixel violet"
            onClick={(e) => { e.stopPropagation(); onOpenClassCraft(); }}
            disabled={!anyCraftable}
            style={!anyCraftable ? { opacity: 0.55, cursor: 'not-allowed' } : null}
          >
            <span>★</span> Klas Craften
          </button>
          {classRewards.length > 0 && (
            <div className="rewards-line" title="Behaalde klasbeloningen">
              {classRewards.map((r, i) => (
                <ItemIcon key={i} itemKey={r.key} size={14} glow/>
              ))}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ===========================================================
// RecipesPage — full recipe catalog
// ===========================================================
function RecipesPage({ recipes, adminMode, onEditRecipes }) {
  const groups = [
    { cat: 'basic',     label: 'Basis beloningen' },
    { cat: 'rare',      label: 'Zeldzame materialen' },
    { cat: 'advanced',  label: 'Gevorderde beloningen' },
    { cat: 'legendary', label: 'Legendarische materialen' },
    { cat: 'class',     label: 'Klasbeloningen (ultra-zeldzaam)' },
  ];
  const byCat = useMemo(() => {
    const m = {};
    for (const r of recipes) (m[r.category] ??= []).push(r);
    return m;
  }, [recipes]);

  return (
    <>
      <div style={{ display: 'flex', alignItems: 'center', gap: 16, flexWrap: 'wrap' }}>
        <div>
          <p className="page-eyebrow">Receptenboek</p>
          <h1 className="page-title">Alle recepten</h1>
        </div>
        {adminMode && (
          <button
            className="btn-pixel violet"
            style={{ padding: '10px 16px', fontSize: 11, marginLeft: 'auto' }}
            onClick={onEditRecipes}
          >
            ✎ Recepten bewerken
          </button>
        )}
      </div>
      <p className="page-sub">
        Overzicht voor de klas. Inwoners maken hun beloningen aan de werkbank; de klas maakt ultra-zeldzame beloningen samen via de Klaskist.
      </p>

      <div style={{ height: 24 }}/>

      {groups.map(g => (
        <section key={g.cat} className="recipes-section">
          <div className="recipes-section-head">
            <h2>{g.label}</h2>
            <span className="count">{(byCat[g.cat] || []).length} recept{((byCat[g.cat]||[]).length === 1) ? '' : 'en'}</span>
          </div>
          <div className="recipe-grid">
            {(byCat[g.cat] || []).map(r => (
              <RecipeCard
                key={r.key}
                recipe={r}
                catalogMode
                hideButton
              />
            ))}
          </div>
        </section>
      ))}
    </>
  );
}

// ===========================================================
// DonateModal
// ===========================================================
function DonateModal({ student, onCancel, onConfirm }) {
  const donatableKeys = [
    'water', 'paddenstoel', 'zand',
    'lava', 'zeewier', 'fles',
    'enderparel', 'enderpoeder',
  ];
  const [picks, setPicks] = useState({});

  const bump = (k, delta) => {
    setPicks(p => {
      const cur = p[k] || 0;
      const max = student.inventory[k] || 0;
      const next = Math.min(max, Math.max(0, cur + delta));
      return { ...p, [k]: next };
    });
  };

  const total = Object.values(picks).reduce((a, b) => a + b, 0);
  const firstName = student.name.split(' ')[0];

  return (
    <div className="modal-overlay" onClick={onCancel}>
      <div className="modal wide" onClick={(e)=>e.stopPropagation()}>
        <div className="modal-inner">
          <h3>Doneer aan Klaskist</h3>
          <p>Kies hoeveel {firstName} van elk item wil doneren.</p>

          {donatableKeys.map(k => {
            const have = student.inventory[k] || 0;
            const pick = picks[k] || 0;
            if (have === 0) return null;
            return (
              <div key={k} className="donate-row">
                <div className="icon-box"><ItemIcon itemKey={k} size={22}/></div>
                <span className="name">{ITEMS[k].name}</span>
                <span className="have-count">heeft: {have}</span>
                <div className="qty-picker">
                  <button onClick={()=>bump(k,-1)} disabled={pick === 0}>−</button>
                  <span className="val">{pick}</span>
                  <button onClick={()=>bump(k,+1)} disabled={pick >= have}>+</button>
                </div>
              </div>
            );
          })}

          {donatableKeys.every(k => (student.inventory[k] || 0) === 0) && (
            <p className="muted">Nog niets om te doneren.</p>
          )}

          <div className="modal-actions" style={{ marginTop: 18 }}>
            <button className="btn-pixel ghost" onClick={onCancel}>Annuleer</button>
            <button
              className="btn-pixel violet"
              disabled={total === 0}
              style={total === 0 ? { opacity: 0.5, cursor: 'not-allowed' } : null}
              onClick={() => onConfirm(picks)}
            >
              Doneer {total > 0 && `· ${total}`}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ===========================================================
// ClassCraftModal
// ===========================================================
function ClassCraftModal({ classChest, recipes, onCancel, onConfirm }) {
  const classRecipes = recipes.filter(r => r.category === 'class');
  return (
    <div className="modal-overlay" onClick={onCancel}>
      <div className="modal wide" onClick={(e)=>e.stopPropagation()} style={{ width: 'min(760px, 100%)' }}>
        <div className="modal-inner">
          <h3 style={{ color: 'var(--ender-hi)' }}>★ Klas Craften</h3>
          <p>Gebruik materialen uit de Klaskist om een ultra-zeldzame beloning te maken voor iedereen.</p>

          <div className="recipe-grid" style={{ marginTop: 10 }}>
            {classRecipes.map(r => (
              <RecipeCard
                key={r.key}
                recipe={r}
                supply={classChest}
                onCraft={(recipe, e) => onConfirm(recipe, e)}
                craftLabel="Maak"
              />
            ))}
          </div>

          <div className="modal-actions" style={{ marginTop: 18 }}>
            <button className="btn-pixel ghost" onClick={onCancel}>Sluit</button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ===========================================================
// GiftModal — generic add/remove picker used for all teacher gift flows:
//   target = student | chest | all
// Allows + and − per item (can go negative to take away).
// When `currentMap` is passed, shows "heeft: X → Y" per row.
// When `broadcast` is true (gift to all), positive-only and no current display.
// ===========================================================
function GiftModal({
  title,
  subtitle,
  currentMap,
  broadcast = false,
  confirmLabel = 'Toepassen',
  onCancel,
  onConfirm,
}) {
  const trackedKeys = [
    'water', 'paddenstoel', 'zand',
    'lava', 'zeewier', 'fles',
    'enderparel', 'enderpoeder',
  ];

  const [picks, setPicks] = useState({});

  const bump = (k, delta) => {
    setPicks(p => {
      const cur = p[k] || 0;
      let next = cur + delta;
      if (broadcast && next < 0) next = 0;
      return { ...p, [k]: next };
    });
  };

  const setAll = (delta) => {
    setPicks(p => {
      const next = { ...p };
      for (const k of trackedKeys) {
        const cur = next[k] || 0;
        const v = cur + delta;
        next[k] = broadcast && v < 0 ? 0 : v;
      }
      return next;
    });
  };

  const anyDelta = trackedKeys.some(k => (picks[k] || 0) !== 0);

  return (
    <div className="modal-overlay" onClick={onCancel}>
      <div className="modal wide" onClick={(e)=>e.stopPropagation()} style={{ width: 'min(640px, 100%)' }}>
        <div className="modal-inner">
          <h3>{title}</h3>
          {subtitle && <p>{subtitle}</p>}

          <div style={{ display: 'flex', gap: 8, marginBottom: 14, flexWrap: 'wrap' }}>
            <button className="btn-pixel ghost" style={{ padding: '8px 12px', fontSize: 10 }} onClick={() => setAll(+1)}>
              + 1 van alles
            </button>
            {!broadcast && (
              <button className="btn-pixel ghost" style={{ padding: '8px 12px', fontSize: 10 }} onClick={() => setAll(-1)}>
                − 1 van alles
              </button>
            )}
            <button className="btn-pixel ghost" style={{ padding: '8px 12px', fontSize: 10 }} onClick={() => setPicks({})}>
              Reset
            </button>
          </div>

          {trackedKeys.map(k => {
            const cur = currentMap?.[k] ?? 0;
            const pick = picks[k] || 0;
            const next = Math.max(0, cur + pick);
            const pickColor = pick > 0 ? 'var(--green)' : pick < 0 ? 'var(--danger)' : 'var(--ink-faint)';
            return (
              <div key={k} className="donate-row">
                <div className="icon-box"><ItemIcon itemKey={k} size={22}/></div>
                <span className="name">{ITEMS[k].name}</span>
                {!broadcast && (
                  <span className="have-count">
                    {cur}{pick !== 0 && <> → <b style={{ color: 'var(--ink)' }}>{next}</b></>}
                  </span>
                )}
                <div className="qty-picker">
                  <button onClick={()=>bump(k,-1)} disabled={broadcast && pick === 0}>−</button>
                  <span className="val" style={{ color: pickColor }}>
                    {pick > 0 ? `+${pick}` : pick}
                  </span>
                  <button onClick={()=>bump(k,+1)}>+</button>
                </div>
              </div>
            );
          })}

          <div className="modal-actions" style={{ marginTop: 18 }}>
            <button className="btn-pixel ghost" onClick={onCancel}>Annuleer</button>
            <button
              className="btn-pixel violet"
              disabled={!anyDelta}
              style={!anyDelta ? { opacity: 0.5, cursor: 'not-allowed' } : null}
              onClick={() => onConfirm(picks)}
            >
              {confirmLabel}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ===========================================================
// RecipeEditorModal — teacher can edit/add/delete recipes
// ===========================================================
function RecipeEditorModal({ recipes, onSave, onReset, onCancel }) {
  const [draft, setDraft] = useState(() => JSON.parse(JSON.stringify(recipes)));
  const [confirmReset, setConfirmReset] = useState(false);

  const categories = [
    { cat: 'basic',     label: 'Basis beloningen' },
    { cat: 'rare',      label: 'Zeldzame materialen' },
    { cat: 'advanced',  label: 'Gevorderde beloningen' },
    { cat: 'legendary', label: 'Legendarische materialen' },
    { cat: 'class',     label: 'Klasbeloningen' },
  ];

  const itemKeys = Object.keys(ITEMS);

  const upd = (key, field, val) =>
    setDraft(d => d.map(r => r.key === key ? { ...r, [field]: val } : r));

  const updCostQty = (key, idx, qty) =>
    setDraft(d => d.map(r => r.key !== key ? r :
      { ...r, cost: r.cost.map((c, i) => i === idx ? [c[0], Math.max(1, qty)] : c) }));

  const updCostItem = (key, idx, ik) =>
    setDraft(d => d.map(r => r.key !== key ? r :
      { ...r, cost: r.cost.map((c, i) => i === idx ? [ik, c[1]] : c) }));

  const addIngredient = (key) =>
    setDraft(d => d.map(r => r.key !== key ? r :
      { ...r, cost: [...r.cost, ['water', 1]] }));

  const removeIngredient = (key, idx) =>
    setDraft(d => d.map(r => r.key !== key ? r :
      { ...r, cost: r.cost.filter((_, i) => i !== idx) }));

  const deleteRecipe = (key) =>
    setDraft(d => d.filter(r => r.key !== key));

  const addRecipe = (cat) => {
    const ts = Date.now();
    setDraft(d => [...d, {
      key: `recipe_${ts}`,
      output: 'water',
      name: 'Nieuw recept',
      category: cat,
      explanation: '',
      cost: [['water', 1]],
    }]);
  };

  const inputStyle = {
    width: '100%', background: 'var(--bg-deep)', border: '2px solid var(--line)',
    padding: '8px 10px', fontFamily: 'var(--font-body)', fontSize: 16,
    color: 'var(--ink)', outline: 'none', marginBottom: 6,
  };
  const labelStyle = { display: 'block', fontSize: 11, color: 'var(--ink-dim)',
    fontFamily: 'var(--font-disp)', letterSpacing: 1, marginBottom: 3, textTransform: 'uppercase' };

  return (
    <div className="modal-overlay" onClick={onCancel}>
      <div className="modal wide" onClick={e => e.stopPropagation()}
           style={{ width: 'min(820px, 98%)', maxHeight: '92vh', display: 'flex', flexDirection: 'column' }}>
        <div className="modal-inner" style={{ overflow: 'auto', flex: 1 }}>
          <h3>Recepten bewerken</h3>
          <p>Bewerk naam, uitleg en kosten. Voeg nieuwe recepten toe of verwijder bestaande.</p>

          {categories.map(({ cat, label }) => {
            const catRecipes = draft.filter(r => r.category === cat);
            return (
              <section key={cat} style={{ marginBottom: 28 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 10,
                  borderBottom: '2px solid var(--line)', paddingBottom: 8 }}>
                  <h4 style={{ margin: 0, fontSize: 14, fontFamily: 'var(--font-disp)', letterSpacing: 1 }}>
                    {label}
                  </h4>
                  <button className="btn-pixel ghost"
                    style={{ fontSize: 10, padding: '4px 10px', marginLeft: 'auto' }}
                    onClick={() => addRecipe(cat)}>
                    + Recept
                  </button>
                </div>

                {catRecipes.length === 0 && (
                  <p style={{ color: 'var(--ink-faint)', fontSize: 14, margin: '8px 0' }}>
                    Geen recepten. Klik "+ Recept" om er een toe te voegen.
                  </p>
                )}

                {catRecipes.map(r => (
                  <div key={r.key} style={{
                    background: 'var(--bg-deep)', border: '2px solid var(--line)',
                    padding: 14, marginBottom: 10,
                  }}>
                    <div style={{ display: 'flex', gap: 10, marginBottom: 8 }}>
                      <div style={{ flex: 1 }}>
                        <span style={labelStyle}>Naam</span>
                        <input style={inputStyle} value={r.name}
                          onChange={e => upd(r.key, 'name', e.target.value)} />
                      </div>
                      <div style={{ flex: 1 }}>
                        <span style={labelStyle}>Output item</span>
                        <select style={{ ...inputStyle, marginBottom: 0 }} value={r.output}
                          onChange={e => upd(r.key, 'output', e.target.value)}>
                          {itemKeys.map(k => (
                            <option key={k} value={k}>{ITEMS[k].name}</option>
                          ))}
                        </select>
                      </div>
                    </div>

                    <span style={labelStyle}>Uitleg (optioneel)</span>
                    <textarea style={{ ...inputStyle, resize: 'vertical' }}
                      value={r.explanation || ''} rows={2}
                      onChange={e => upd(r.key, 'explanation', e.target.value)} />

                    <span style={labelStyle}>Ingrediënten</span>
                    {r.cost.map(([ik, qty], idx) => (
                      <div key={idx} style={{ display: 'flex', gap: 6, alignItems: 'center', marginBottom: 4 }}>
                        <select style={{ ...inputStyle, flex: 1, marginBottom: 0 }} value={ik}
                          onChange={e => updCostItem(r.key, idx, e.target.value)}>
                          {itemKeys.map(k => (
                            <option key={k} value={k}>{ITEMS[k].name}</option>
                          ))}
                        </select>
                        <input type="number" min="1" value={qty} style={{ ...inputStyle, width: 70, marginBottom: 0 }}
                          onChange={e => updCostQty(r.key, idx, parseInt(e.target.value) || 1)} />
                        <button onClick={() => removeIngredient(r.key, idx)}
                          disabled={r.cost.length <= 1}
                          style={{ color: 'var(--danger)', fontSize: 16, opacity: r.cost.length <= 1 ? 0.3 : 1 }}>
                          ✕
                        </button>
                      </div>
                    ))}
                    <button className="btn-pixel ghost" style={{ fontSize: 10, padding: '4px 8px', marginTop: 4 }}
                      onClick={() => addIngredient(r.key)}>
                      + Ingredient
                    </button>

                    <div style={{ textAlign: 'right', marginTop: 8 }}>
                      <button onClick={() => deleteRecipe(r.key)}
                        style={{ color: 'var(--danger)', fontSize: 11, fontFamily: 'var(--font-disp)',
                          letterSpacing: 1, textTransform: 'uppercase' }}>
                        Verwijder recept
                      </button>
                    </div>
                  </div>
                ))}
              </section>
            );
          })}

          <div className="modal-actions" style={{ marginTop: 8, flexWrap: 'wrap', gap: 8 }}>
            {confirmReset ? (
              <>
                <span style={{ color: 'var(--danger)', fontSize: 13, alignSelf: 'center' }}>
                  Zeker? Al jouw aanpassingen worden verwijderd.
                </span>
                <button className="btn-pixel ghost" onClick={() => setConfirmReset(false)}>Nee</button>
                <button className="btn-pixel"
                  style={{ background: 'var(--danger)', border: '3px solid var(--danger)' }}
                  onClick={() => { onReset(); }}>
                  Ja, herstel
                </button>
              </>
            ) : (
              <button className="btn-pixel ghost" style={{ fontSize: 10 }}
                onClick={() => setConfirmReset(true)}>
                Herstel standaard
              </button>
            )}
            <div style={{ marginLeft: 'auto', display: 'flex', gap: 8 }}>
              <button className="btn-pixel ghost" onClick={onCancel}>Annuleer</button>
              <button className="btn-pixel violet" onClick={() => onSave(draft)}>Opslaan</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ===========================================================
// AdminLoginModal
// ===========================================================
function AdminLoginModal({ onSubmit, onCancel, error }) {
  const [val, setVal] = useState('');
  const inputRef = useRef(null);
  useEffect(() => { inputRef.current?.focus(); }, []);
  const submit = (e) => { e?.preventDefault(); onSubmit(val); };

  return (
    <div className="modal-overlay" onClick={onCancel}>
      <form className="modal" onClick={(e)=>e.stopPropagation()} onSubmit={submit}>
        <div className="modal-inner">
          <h3>Leerkrachtmodus</h3>
          <p>Voer het wachtwoord in om materialen toe te kennen en foto's te uploaden.</p>
          <input
            ref={inputRef}
            type="password"
            value={val}
            onChange={(e)=>setVal(e.target.value)}
            placeholder="wachtwoord"
            autoComplete="off"
          />
          {error && (
            <p style={{ color:'var(--danger)', fontSize: 18, marginTop: -8, marginBottom: 14 }}>
              {error}
            </p>
          )}
          <div className="modal-actions">
            <button type="button" className="btn-pixel ghost" onClick={onCancel}>Annuleer</button>
            <button type="submit" className="btn-pixel violet">Ontgrendel</button>
          </div>
        </div>
      </form>
    </div>
  );
}

// ===========================================================
// Toasts
// ===========================================================
function Toasts({ items }) {
  return (
    <div className="toasts">
      {items.map(t => (
        <div key={t.id} className={`toast ${t.kind || 'info'}`}>
          {t.icon && <ItemIcon itemKey={t.icon} size={20} glow/>}
          <span>{t.text}</span>
        </div>
      ))}
    </div>
  );
}

Object.assign(window, {
  Avatar, NavTabs, VillagerCard, RecipeCard, StudentDetail,
  RecipesPage, ChestBanner, DonateModal, ClassCraftModal, GiftModal,
  AdminLoginModal, Toasts, RecipeEditorModal,
});
