// ============================================================================
// /uprav — public stránka pro úpravy karet (foto, jméno, věk, IG, bio, …)
// ============================================================================
// Vypadá jako /edit panel ale je VEŘEJNÝ (žádný login). Submission jdou do
// contributions queue (admin v /edit reviewuje a klikem aplikuje).
// ============================================================================

const { useState: useStateU, useEffect: useEffectU, useRef: useRefU } = React;

// ──────────────────────────────────────────────
// Helper: porovná draft s originálem, vrátí jen změněná pole
// ──────────────────────────────────────────────
function diffParticipant(original, draft) {
  const changes = {};
  const fields = ["name", "real_name", "nick", "alt_name", "age", "city", "height", "bio", "fact", "instagram", "job", "info", "photo", "photo_position"];
  for (const f of fields) {
    const a = original ? original[f] : null;
    const b = draft[f];
    if (Array.isArray(a) || Array.isArray(b)) {
      const ja = JSON.stringify(a || []), jb = JSON.stringify(b || []);
      if (ja !== jb && (b || []).length > 0) changes[f] = b;
    } else if ((a == null ? "" : String(a)) !== (b == null ? "" : String(b))) {
      if (b !== "" && b != null) changes[f] = b;
    }
  }
  return changes;
}

// ──────────────────────────────────────────────
// PhotoCropper — Discord-style modal s drag + zoom (vrací cropnutý File)
// ──────────────────────────────────────────────
function PhotoCropper({ file, onConfirm, onCancel }) {
  const [imgSrc, setImgSrc] = useStateU("");
  const [zoom, setZoom] = useStateU(1);
  const [defaultZoom, setDefaultZoom] = useStateU(1);
  const [offset, setOffset] = useStateU({ x: 0, y: 0 });
  const [imgLoaded, setImgLoaded] = useStateU(false);
  const draggingRef = useRefU(false);
  const lastPosRef = useRefU(null);
  const imgRef = useRefU(null);
  const containerRef = useRefU(null);

  // File → data URL
  useEffectU(() => {
    if (!file) return;
    const reader = new FileReader();
    reader.onload = (ev) => setImgSrc(ev.target.result);
    reader.readAsDataURL(file);
  }, [file]);

  function getEventPos(e) {
    if (e.touches && e.touches[0]) return { x: e.touches[0].clientX, y: e.touches[0].clientY };
    return { x: e.clientX, y: e.clientY };
  }

  // Clamp offset: když je image větší než container, drž v něm; když menší, drž v boundu containeru (bars OK)
  function clampOffset(o, currentZoom) {
    const img = imgRef.current, container = containerRef.current;
    if (!img || !container || !img.naturalWidth) return o;
    const cropW = container.clientWidth, cropH = container.clientHeight;
    const naturalW = img.naturalWidth, naturalH = img.naturalHeight;
    const baseScale = Math.max(cropW / naturalW, cropH / naturalH);
    const totalScale = baseScale * currentZoom;
    const scaledW = naturalW * totalScale, scaledH = naturalH * totalScale;
    const maxX = Math.abs(scaledW - cropW) / 2;
    const maxY = Math.abs(scaledH - cropH) / 2;
    return {
      x: Math.min(maxX, Math.max(-maxX, o.x)),
      y: Math.min(maxY, Math.max(-maxY, o.y)),
    };
  }

  function startDrag(e) {
    draggingRef.current = true;
    lastPosRef.current = getEventPos(e);
  }
  function moveDrag(e) {
    if (!draggingRef.current || !lastPosRef.current) return;
    e.preventDefault();
    const pos = getEventPos(e);
    const dx = pos.x - lastPosRef.current.x;
    const dy = pos.y - lastPosRef.current.y;
    lastPosRef.current = pos;
    setOffset(o => clampOffset({ x: o.x + dx, y: o.y + dy }, zoom));
  }
  function endDrag() { draggingRef.current = false; lastPosRef.current = null; }

  function reset() { setZoom(defaultZoom); setOffset({ x: 0, y: 0 }); }

  // Když se zoom zmenší, offset může být mimo bounds → re-clamp
  useEffectU(() => { setOffset(o => clampOffset(o, zoom)); }, [zoom]);

  // Po načtení obrázku: spočítej fit-zoom tak aby celá fotka byla vidět (cover=1 → fit=fitScale/coverScale)
  function onImageLoad() {
    setImgLoaded(true);
    requestAnimationFrame(() => {
      const img = imgRef.current, container = containerRef.current;
      if (!img || !container || !img.naturalWidth) return;
      const cropW = container.clientWidth, cropH = container.clientHeight;
      const fit = Math.min(cropW / img.naturalWidth, cropH / img.naturalHeight);
      const cover = Math.max(cropW / img.naturalWidth, cropH / img.naturalHeight);
      const fitZoom = cover > 0 ? fit / cover : 1;
      setDefaultZoom(fitZoom);
      setZoom(fitZoom);
      setOffset({ x: 0, y: 0 });
    });
  }

  async function apply() {
    const img = imgRef.current;
    const container = containerRef.current;
    if (!img || !container) return;

    const cropW = container.clientWidth, cropH = container.clientHeight;
    const naturalW = img.naturalWidth, naturalH = img.naturalHeight;
    const baseScale = Math.max(cropW / naturalW, cropH / naturalH);
    const totalScale = baseScale * zoom;

    const sourceW = cropW / totalScale, sourceH = cropH / totalScale;
    let sourceX = (naturalW - sourceW) / 2 - offset.x / totalScale;
    let sourceY = (naturalH - sourceH) / 2 - offset.y / totalScale;

    // Output: cap to source visible (no upscale of small photos)
    const OUT_W = Math.min(800, Math.max(200, Math.round(Math.min(sourceW, naturalW))));
    const OUT_H = Math.round(OUT_W * cropH / cropW);
    const canvas = document.createElement("canvas");
    canvas.width = OUT_W; canvas.height = OUT_H;
    const ctx = canvas.getContext("2d");
    ctx.fillStyle = "#000";
    ctx.fillRect(0, 0, OUT_W, OUT_H);

    // Clip source rect to natural bounds, adjust dest rect proportionally
    const dstScaleX = OUT_W / sourceW, dstScaleY = OUT_H / sourceH;
    let sx = sourceX, sy = sourceY, sw = sourceW, sh = sourceH;
    let dx = 0, dy = 0, dw = OUT_W, dh = OUT_H;
    if (sx < 0) { dx = -sx * dstScaleX; dw += sx * dstScaleX; sw += sx; sx = 0; }
    if (sy < 0) { dy = -sy * dstScaleY; dh += sy * dstScaleY; sh += sy; sy = 0; }
    if (sx + sw > naturalW) { const cut = sx + sw - naturalW; sw -= cut; dw -= cut * dstScaleX; }
    if (sy + sh > naturalH) { const cut = sy + sh - naturalH; sh -= cut; dh -= cut * dstScaleY; }
    if (sw > 0 && sh > 0 && dw > 0 && dh > 0) ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);

    canvas.toBlob((blob) => {
      if (!blob) { onCancel(); return; }
      const ext = (file.type === "image/png") ? "png" : "jpg";
      const cropped = new File([blob], `cropped.${ext}`, { type: blob.type });
      onConfirm(cropped, file); // 2. arg = original (necropnutý) soubor
    }, "image/jpeg", 0.92);
  }

  return (
    <div className="ed-cropper-backdrop" onClick={onCancel}>
      <div className="ed-cropper" onClick={(e) => e.stopPropagation()}>
        <header className="ed-cropper-head">
          <h3>Upravit obrázek</h3>
          <button type="button" className="ed-cropper-x" onClick={onCancel}>✕</button>
        </header>

        <div
          ref={containerRef}
          className="ed-cropper-area"
          onMouseDown={startDrag}
          onMouseMove={moveDrag}
          onMouseUp={endDrag}
          onMouseLeave={endDrag}
          onTouchStart={startDrag}
          onTouchMove={moveDrag}
          onTouchEnd={endDrag}
        >
          {imgSrc && (
            <img
              ref={imgRef}
              src={imgSrc}
              alt=""
              draggable={false}
              onLoad={onImageLoad}
              style={{
                transform: `translate(calc(-50% + ${offset.x}px), calc(-50% + ${offset.y}px)) scale(${zoom})`,
                opacity: imgLoaded ? 1 : 0,
              }}
            />
          )}
          {!imgLoaded && <div className="ed-cropper-loading">Načítám…</div>}
        </div>

        <div className="ed-cropper-controls">
          <span className="ed-cropper-icon-min">🌄</span>
          <input type="range" min="0.4" max="4" step="0.02" value={zoom} onChange={(e) => setZoom(parseFloat(e.target.value))} />
          <span className="ed-cropper-icon-max">🖼️</span>
        </div>

        <footer className="ed-cropper-foot">
          <button type="button" className="ed-cropper-reset" onClick={reset}>Obnovit</button>
          <div className="ed-cropper-actions">
            <button type="button" className="ed-btn" onClick={onCancel}>Zrušit</button>
            <button type="button" className="ed-btn ed-btn-primary" onClick={apply}>Použít</button>
          </div>
        </footer>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// PhotoPositionPicker — 2 slidery (X, Y) + live preview crop (jen pro existující fotky bez re-uploadu)
// ──────────────────────────────────────────────
function PhotoPositionPicker({ photoUrl, position, onChange, isNew = false }) {
  // Position string "x% y%" (default "center 25%" = "50% 25%")
  const parsed = (position || "50% 25%").replace(/center/g, "50%").split(/\s+/);
  const x = parseInt(parsed[0]) || 50;
  const y = parseInt(parsed[1]) || 25;

  function update(newX, newY) {
    onChange(`${newX}% ${newY}%`);
  }

  if (!photoUrl) return null;

  return (
    <div className={`ed-pos-picker ${isNew ? "is-new" : ""}`}>
      {isNew && <div className="ed-pos-new-banner">📷 Nová fotka — vycentruj před odesláním</div>}
      <div className="ed-pos-preview">
        <img src={photoUrl} alt="" style={{ objectPosition: `${x}% ${y}%` }} />
        <div className="ed-pos-crosshair" style={{ left: `${x}%`, top: `${y}%` }}>+</div>
      </div>
      <div className="ed-pos-sliders">
        <label>
          <span>Horizontálně: {x}%</span>
          <input type="range" min="0" max="100" value={x} onChange={(e) => update(Number(e.target.value), y)} />
        </label>
        <label>
          <span>Vertikálně: {y}%</span>
          <input type="range" min="0" max="100" value={y} onChange={(e) => update(x, Number(e.target.value))} />
        </label>
        <div className="ed-pos-presets">
          {[
            { l: "Centrum", x: 50, y: 50 },
            { l: "Obličej", x: 50, y: 25 },
            { l: "Top", x: 50, y: 10 },
            { l: "Bottom", x: 50, y: 85 },
          ].map(p => (
            <button key={p.l} type="button" className="ed-btn ed-btn-sm ed-btn-ghost" onClick={() => update(p.x, p.y)}>
              {p.l}
            </button>
          ))}
        </div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// Mini photo upload — vybere soubor → otevře cropper → vrátí cropnutý File
// ──────────────────────────────────────────────
function UpravPhotoPicker({ value, onChange }) {
  const fileRef = useRefU(null);
  const [preview, setPreview] = useStateU("");
  const [cropFile, setCropFile] = useStateU(null);  // soubor čekající na crop

  function pickFile(e) {
    const f = e.target.files && e.target.files[0];
    if (!f) return;
    if (f.size > 15 * 1024 * 1024) {
      alert("Fotka je moc velká (max 15 MB).");
      return;
    }
    setCropFile(f);  // → otevře cropper
  }

  function onCropConfirm(croppedFile, originalFile) {
    setCropFile(null);
    const reader = new FileReader();
    reader.onload = (ev) => setPreview(ev.target.result);
    reader.readAsDataURL(croppedFile);
    onChange(croppedFile, originalFile);
  }

  function onCropCancel() {
    setCropFile(null);
    if (fileRef.current) fileRef.current.value = "";
  }

  function clear() {
    setPreview("");
    onChange(null, null);
    if (fileRef.current) fileRef.current.value = "";
  }

  return (
    <>
      <div className="ed-photo">
        {preview ? (
          <img src={preview} alt="náhled" className="ed-photo-img" />
        ) : value ? (
          <img src={value} alt="současná" className="ed-photo-img" />
        ) : (
          <div className="ed-photo-placeholder">Bez fotky</div>
        )}
        <div className="ed-photo-actions">
          <button type="button" className="ed-btn ed-btn-sm" onClick={() => fileRef.current && fileRef.current.click()}>
            {preview ? "Změnit" : "Nahrát novou"}
          </button>
          {preview && (
            <button type="button" className="ed-btn ed-btn-sm ed-btn-ghost" onClick={clear}>Zrušit</button>
          )}
          <input ref={fileRef} type="file" accept="image/*" onChange={pickFile} style={{ display: "none" }} />
        </div>
      </div>
      {cropFile && (
        <PhotoCropper file={cropFile} onConfirm={onCropConfirm} onCancel={onCropCancel} />
      )}
    </>
  );
}

// ──────────────────────────────────────────────
// Field helpers (reused from /edit styling)
// ──────────────────────────────────────────────
function UField({ label, hint, children }) {
  return (
    <label className="ed-field">
      <span className="ed-field-label">{label}</span>
      {children}
      {hint && <span className="ed-field-hint">{hint}</span>}
    </label>
  );
}
function UInput({ value, onChange, type = "text", placeholder }) {
  return (
    <input
      type={type}
      className="ed-input"
      value={value == null ? "" : value}
      onChange={(e) => onChange(type === "number" ? (e.target.value === "" ? null : Number(e.target.value)) : e.target.value)}
      placeholder={placeholder}
    />
  );
}
function UTextarea({ value, onChange, rows = 3, placeholder }) {
  return (
    <textarea
      className="ed-input ed-textarea"
      value={value == null ? "" : value}
      onChange={(e) => onChange(e.target.value)}
      rows={rows}
      placeholder={placeholder}
    />
  );
}
function UInfoArray({ value, onChange }) {
  const arr = Array.isArray(value) ? value : [];
  const [draft, setDraft] = useStateU("");
  function add() {
    const v = draft.trim();
    if (!v) return;
    onChange([...arr, v]);
    setDraft("");
  }
  function remove(i) { onChange(arr.filter((_, idx) => idx !== i)); }
  function edit(i, v) { const next = [...arr]; next[i] = v; onChange(next); }
  return (
    <div className="ed-array">
      {arr.map((item, i) => (
        <div key={i} className="ed-array-row">
          <input className="ed-input" value={item} onChange={(e) => edit(i, e.target.value)} />
          <button type="button" className="ed-btn ed-btn-icon ed-btn-danger" onClick={() => remove(i)}>✕</button>
        </div>
      ))}
      <div className="ed-array-add">
        <input className="ed-input" value={draft} onChange={(e) => setDraft(e.target.value)} placeholder="Nový bullet (např. 'Praha · 22 · LoL')…"
          onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); add(); } }} />
        <button type="button" className="ed-btn ed-btn-sm" onClick={add}>+ Přidat</button>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// EditableRow — jeden účastník s možností úpravy + submit
// ──────────────────────────────────────────────
function EditableRow({ p, contributorRequired, onSubmitChanges }) {
  const [open, setOpen] = useStateU(false);
  const [draft, setDraft] = useStateU(p);
  const [photoFile, setPhotoFile] = useStateU(null);
  const [photoOriginalFile, setPhotoOriginalFile] = useStateU(null);  // necropnutý originál pro admin re-crop
  const [photoPreviewUrl, setPhotoPreviewUrl] = useStateU("");  // data URL pro náhled NOVÉ fotky
  const [busy, setBusy] = useStateU(false);
  const [msg, setMsg] = useStateU("");

  useEffectU(() => { setDraft(p); setPhotoFile(null); setPhotoOriginalFile(null); setPhotoPreviewUrl(""); }, [p]);

  // Když user vybere nový soubor, vyrob data URL preview pro position picker
  useEffectU(() => {
    if (!photoFile) { setPhotoPreviewUrl(""); return; }
    const reader = new FileReader();
    reader.onload = (ev) => setPhotoPreviewUrl(ev.target.result);
    reader.readAsDataURL(photoFile);
  }, [photoFile]);

  function set(key, val) { setDraft({ ...draft, [key]: val }); }

  async function submit() {
    // Contributor info je volitelné — kdo chce vyplní, ale nebráníme submitu
    const changes = diffParticipant(p, draft);
    if (photoFile) changes._photoFile = photoFile;
    if (photoOriginalFile) changes._photoOriginalFile = photoOriginalFile;

    if (Object.keys(changes).length === 0) {
      setMsg("Nezměnil jsi nic — ulož něco nebo zruš.");
      return;
    }
    setBusy(true); setMsg("");
    try {
      await onSubmitChanges(p.id, changes);
      setMsg("✓ Odesláno k review");
      setTimeout(() => { setOpen(false); setMsg(""); setDraft(p); setPhotoFile(null); setPhotoOriginalFile(null); }, 1500);
    } catch (e) { setMsg("Chyba: " + e.message); }
    finally { setBusy(false); }
  }

  // Spočítáme kolik polí změněno (na hlavě řádku zobrazíme badge)
  const liveDiff = (() => {
    const c = diffParticipant(p, draft);
    return Object.keys(c).length + (photoFile ? 1 : 0);
  })();

  // Co chybí na profilu (zvýrazníme v UI ať uživatelé vidí co doplnit)
  const missing = [];
  if (!p.photo) missing.push("foto");
  if (!p.instagram) missing.push("IG");
  if (!p.bio) missing.push("bio");
  if (!p.age) missing.push("věk");
  if (!p.info || p.info.length === 0) missing.push("info");

  return (
    <div className={`ed-row up-card ${open ? "is-open" : ""} ${missing.length >= 3 ? "up-needs-info" : ""}`}>
      <div className="ed-row-head up-card-head" onClick={() => setOpen(!open)}>
        <div className="up-card-photo">
          {p.photo
            ? <img src={p.photo} alt={p.name} loading="lazy" />
            : <div className="up-card-photo-empty">{p.gender === "girl" ? "♀" : "♂"}<small>bez fotky</small></div>}
          {missing.length > 0 && !open && (
            <div className="up-card-missing-overlay">
              <strong>⚠️ POMOZ DOPLNIT</strong>
              <span>{missing.join(" · ")}</span>
            </div>
          )}
        </div>
        <div className="up-card-meta">
          <div className="up-card-name">
            {p.name}
            {p.tbd && <span className="ed-tag ed-tag-grey">TBD</span>}
            {liveDiff > 0 && <span className="ed-tag ed-tag-pink">{liveDiff} změn</span>}
          </div>
          <div className="up-card-sub">
            {p.gender === "girl" ? "♀" : "♂"}
            {p.age != null && ` · ${p.age}`}
            {p.city && ` · ${p.city}`}
          </div>
          {p.instagram && <div className="up-card-ig">{p.instagram}</div>}
          {!open && (
            <button type="button" className="up-card-edit-btn" onClick={(e) => { e.stopPropagation(); setOpen(true); }}>
              ✎ Upravit
            </button>
          )}
        </div>
      </div>

      {open && (
        <div className="ed-row-body">
          <div className="ed-form-row">
            <UpravPhotoPicker value={p.photo} onChange={(c, o) => { setPhotoFile(c); setPhotoOriginalFile(o); }} />
            <div className="ed-form-fields">
              <div className="ed-grid-2">
                <UField label="Jméno"><UInput value={draft.name} onChange={(v) => set("name", v)} /></UField>
                <UField label="Real name"><UInput value={draft.real_name || draft.realName} onChange={(v) => set("real_name", v)} /></UField>
                <UField label="Nick"><UInput value={draft.nick} onChange={(v) => set("nick", v)} /></UField>
                <UField label="Alt name"><UInput value={draft.alt_name || draft.altName} onChange={(v) => set("alt_name", v)} /></UField>
                <UField label="Věk"><UInput type="number" value={draft.age} onChange={(v) => set("age", v)} /></UField>
                <UField label="Výška (cm)"><UInput type="number" value={draft.height} onChange={(v) => set("height", v)} /></UField>
                <UField label="Město"><UInput value={draft.city} onChange={(v) => set("city", v)} /></UField>
                <UField label="Instagram" hint="ve formátu @nick"><UInput value={draft.instagram} onChange={(v) => set("instagram", v)} placeholder="@nick" /></UField>
                <UField label="Job"><UInput value={draft.job} onChange={(v) => set("job", v)} /></UField>
              </div>
              <UField label="Bio (krátký popis)"><UTextarea value={draft.bio} onChange={(v) => set("bio", v)} rows={3} /></UField>
              <UField label="Fact (krátká hláška)"><UInput value={draft.fact} onChange={(v) => set("fact", v)} /></UField>
              <UField label="Info bullets" hint="Krátké bodíky co se zobrazí na kartě v Best Energy">
                <UInfoArray value={draft.info} onChange={(v) => set("info", v)} />
              </UField>
            </div>
          </div>
          <div className="ed-actions">
            <button type="button" className="ed-btn ed-btn-primary" onClick={submit} disabled={busy}>
              {busy ? "Odesílám…" : `✓ Odeslat změny ${liveDiff > 0 ? `(${liveDiff})` : ""}`}
            </button>
            <button type="button" className="ed-btn ed-btn-ghost" onClick={() => { setDraft(p); setPhotoFile(null); setOpen(false); }} disabled={busy}>
              Zrušit
            </button>
            {msg && <span className="ed-msg">{msg}</span>}
          </div>
        </div>
      )}
    </div>
  );
}

// ──────────────────────────────────────────────
// MAIN
// ──────────────────────────────────────────────
function UpravApp() {
  const [data, setData] = useStateU(null);
  const [loadError, setLoadError] = useStateU("");
  const [contributorName, setContributorName] = useStateU("");
  const [contributorContact, setContributorContact] = useStateU("");
  const [submittedCount, setSubmittedCount] = useStateU(0);
  const [search, setSearch] = useStateU("");

  // Persist contributor info v localStorage — kdyby submitnul víc karet, nemusí znovu psát
  useEffectU(() => {
    try {
      const cn = localStorage.getItem("ds-contrib-name");
      const cc = localStorage.getItem("ds-contrib-contact");
      if (cn) setContributorName(cn);
      if (cc) setContributorContact(cc);
    } catch {}
  }, []);
  useEffectU(() => { try { localStorage.setItem("ds-contrib-name", contributorName); } catch {} }, [contributorName]);
  useEffectU(() => { try { localStorage.setItem("ds-contrib-contact", contributorContact); } catch {} }, [contributorContact]);

  useEffectU(() => {
    if (!window.dsAPI || !window.dsAPI.loadAllData) {
      setLoadError("Připojení k databázi selhalo.");
      return;
    }
    window.dsAPI.loadAllData().then(setData).catch(err => setLoadError(err.message || String(err)));
  }, []);

  async function submitChanges(participantId, changes) {
    return await window.dsAPI.submitContribution({
      participantId,
      changes,
      // Pokud uživatel nic nevyplnil, použij "anonym" placeholder
      contributorName: contributorName.trim() || "anonym",
      contributorContact: contributorContact.trim() || "—",
    }).then((r) => { setSubmittedCount(c => c + 1); return r; });
  }

  if (loadError) return <div className="ed-fatal">⚠️ {loadError}</div>;
  if (!data) return <div className="ed-loading">Načítám karty…</div>;

  const cast = [...(data.girls || []), ...(data.boys || [])].filter(p => !p.tbd);
  const beOnly = (data.allParticipants || []).filter(p => !cast.find(c => c.id === p.id));
  const allSearchable = [...cast, ...beOnly];

  const q = search.trim().toLowerCase();
  const filtered = q ? allSearchable.filter(p =>
    (p.name || "").toLowerCase().includes(q) ||
    (p.real_name || "").toLowerCase().includes(q) ||
    (p.nick || "").toLowerCase().includes(q) ||
    (p.id || "").toLowerCase().includes(q)
  ) : null;

  const contributorRequired = { name: contributorName, contact: contributorContact };

  return (
    <div className="ed-app">
      <header className="ed-topbar">
        <div className="ed-topbar-brand">
          <svg viewBox="0 0 24 24" fill="currentColor" width="22" height="22"><path d="M12 21s-7.5-4.6-9.5-9.4C1 7.5 4 4 7.5 4c2 0 3.4 1 4.5 2.6C13.1 5 14.5 4 16.5 4 20 4 23 7.5 21.5 11.6 19.5 16.4 12 21 12 21z" /></svg>
          <span>UPRAV KARTU</span>
          {submittedCount > 0 && <span className="ed-topbar-ep">{submittedCount} odesláno</span>}
        </div>
        <div className="ed-topbar-actions">
          <a href="/" className="ed-btn ed-btn-sm ed-btn-ghost">↗ Zpět na web</a>
        </div>
      </header>

      <main className="ed-main">
        {/* CONTRIBUTOR INFO — volitelné, pomáhá adminovi rozeznat původce */}
        <section className="ed-section is-open">
          <header className="ed-section-head" style={{ cursor: "default" }}>
            <div>
              <h2 className="ed-section-title">👤 Kdo jsi? <small style={{ fontSize: 12, fontWeight: 400, opacity: 0.6, marginLeft: 6 }}>(volitelné)</small></h2>
              <p className="ed-section-desc">Pokud chceš, vyplň jméno + kontakt — pomůže adminovi rozeznat tvé úpravy. Údaje se NIKDE nezobrazí publicky.</p>
            </div>
          </header>
          <div className="ed-section-body">
            <div className="ed-grid-2">
              <UField label="Tvoje jméno" hint="cokoliv — třeba prezdívka">
                <UInput value={contributorName} onChange={setContributorName} placeholder="např. Honza, anonym…" />
              </UField>
              <UField label="Kontakt na sebe" hint="IG / Discord / mail">
                <UInput value={contributorContact} onChange={setContributorContact} placeholder="@tvuj.handle, discord#1234, …" />
              </UField>
            </div>
            <p className="ed-msg" style={{ marginTop: 4 }}>
              Úpravy se <strong>NEZOBRAZÍ ihned</strong> — admin je projde a aplikuje.
              Můžeš upravit fotku, jméno, věk, IG handle, popis — cokoli.
            </p>
          </div>
        </section>

        {/* SEARCH */}
        <section className="ed-section is-open">
          <div className="ed-section-body" style={{ paddingTop: 16, paddingBottom: 16 }}>
            <UInput value={search} onChange={setSearch} placeholder="🔍 Hledat účastníka podle jména, nicku, ID…" />
          </div>
        </section>

        {/* CARDS */}
        {filtered ? (
          <Section title={`Hledání — ${filtered.length} výsledků`}>
            <div className="ed-list">
              {filtered.map(p => <EditableRow key={p.id} p={p} contributorRequired={contributorRequired} onSubmitChanges={submitChanges} />)}
              {filtered.length === 0 && <div className="ed-msg">Nikdo nenalezen.</div>}
            </div>
          </Section>
        ) : (
          <>
            <Section title={`👯 Aktuální cast (${cast.length})`} desc="Holky + kluci pro nadcházející díl. Klikni na kartu a uprav.">
              <div className="ed-list">
                {cast.map(p => <EditableRow key={p.id} p={p} contributorRequired={contributorRequired} onSubmitChanges={submitChanges} />)}
              </div>
            </Section>

            <Section title={`🔥 Best Energy — ostatní (${beOnly.length})`} desc="Účastníci z minulých dílů.">
              <div className="ed-list">
                {beOnly.map(p => <EditableRow key={p.id} p={p} contributorRequired={contributorRequired} onSubmitChanges={submitChanges} />)}
              </div>
            </Section>
          </>
        )}
      </main>
    </div>
  );
}

// ──────────────────────────────────────────────
// Section wrapper (collapsible) — reused style
// ──────────────────────────────────────────────
function Section({ title, desc, children }) {
  const [open, setOpen] = useStateU(true);
  return (
    <section className={`ed-section ${open ? "is-open" : "is-collapsed"}`}>
      <header className="ed-section-head" onClick={() => setOpen(!open)}>
        <div>
          <h2 className="ed-section-title">{title}</h2>
          {desc && <p className="ed-section-desc">{desc}</p>}
        </div>
        <span className="ed-section-toggle">{open ? "−" : "+"}</span>
      </header>
      {open && <div className="ed-section-body">{children}</div>}
    </section>
  );
}

window.UpravApp = UpravApp;
