// Desktop Mietvorgänge — master list + detail pane + new/edit dialog.

// ── Blocked-customer helpers ──
// Match by name OR phone OR email (any normalized match counts as the same person).
function _normKey(s) { return (s || '').toString().trim().toLowerCase().replace(/\s+/g, ' '); }
function _normPhone(s) { return (s || '').toString().replace(/[^\d+]/g, ''); }
function findBlockEntry(name, phone, email, blocked) {
  if (!blocked || !blocked.length) return null;
  const nk = _normKey(name), pk = _normPhone(phone), ek = _normKey(email);
  return blocked.find((b) =>
    (nk && _normKey(b.name) === nk) ||
    (pk && pk.length >= 4 && _normPhone(b.phone) === pk) ||
    (ek && _normKey(b.email) === ek)
  ) || null;
}
window.findBlockEntry = findBlockEntry;

// Reusable block toggle + reason editor used inside the rental dialog.
function BlockToggleCard({ form, blocked, setBlocked }) {
  const t = useTheme();
  const trimmed = (form.tenantName || '').trim();
  const be = trimmed ? findBlockEntry(form.tenantName, form.phone, form.email, blocked) : null;
  const isBlocked = !!be;
  const [reasonDraft, setReasonDraft] = useState(null);
  // Reset draft when the entry identity changes (different customer / unblocked).
  useEffect(() => { setReasonDraft(null); }, [be ? be.id : null]);
  const currentReason = reasonDraft != null ? reasonDraft : (be && be.reason) || '';
  const toggle = () => {
    if (!setBlocked || !trimmed) return;
    if (isBlocked) {
      setBlocked((prev) => prev.filter((b) => b.id !== be.id));
      setReasonDraft(null);
    } else {
      const entry = {
        id: 'bl-' + Date.now(),
        name: trimmed,
        phone: form.phone || '',
        email: form.email || '',
        reason: (reasonDraft || '').trim(),
        blockedAt: todayISO()
      };
      setBlocked((prev) => [entry, ...prev]);
    }
  };
  const saveReason = () => {
    if (!isBlocked || reasonDraft == null) return;
    const newReason = reasonDraft.trim();
    setBlocked((prev) => prev.map((b) => b.id === be.id ? { ...b, reason: newReason } : b));
    setReasonDraft(null);
  };
  const dirty = isBlocked && reasonDraft != null && reasonDraft !== (be.reason || '');
  return (
    <>
      <div style={{ fontSize: 11, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, marginTop: 22, marginBottom: 4 }}>Kundenstatus</div>
      <div style={{ background: t.card, borderRadius: 14, border: `0.5px solid ${isBlocked ? (t.red || '#FF3B30') + '55' : t.sep}`, overflow: 'hidden' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '14px 16px' }}>
          <div style={{ width: 32, height: 32, borderRadius: 9, background: isBlocked ? (t.red || '#FF3B30') + '20' : t.chip, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
            <Icon d="M12 2L3 7v6c0 5 3.5 8.5 9 10 5.5-1.5 9-5 9-10V7l-9-5z" color={isBlocked ? (t.red || '#FF3B30') : t.textSec} size={16} sw={1.8} />
          </div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 14, fontWeight: 600, color: isBlocked ? (t.red || '#FF3B30') : t.text }}>{isBlocked ? 'Kunde ist gesperrt' : 'Kunde sperren'}</div>
            <div style={{ fontSize: 11.5, color: t.textSec, marginTop: 2 }}>{isBlocked ? 'Warnung erscheint bei jedem neuen Vorgang dieses Kunden.' : 'Markiert diesen Mieter für künftige Buchungen.'}</div>
          </div>
          <Pressable onClick={toggle} scale={0.95} disabled={!trimmed}>
            <div style={{ width: 46, height: 28, borderRadius: 14, background: isBlocked ? (t.red || '#FF3B30') : t.chipStrong, position: 'relative', transition: 'background 0.15s', opacity: trimmed ? 1 : 0.45 }}>
              <div style={{ position: 'absolute', top: 2, left: isBlocked ? 20 : 2, width: 24, height: 24, borderRadius: 12, background: '#fff', boxShadow: '0 2px 6px rgba(0,0,0,0.18)', transition: 'left 0.15s' }} />
            </div>
          </Pressable>
        </div>
        {isBlocked && (
          <div style={{ borderTop: `0.5px solid ${t.sep}`, padding: '12px 16px', background: t.cardAlt }}>
            <div style={{ fontSize: 11, color: t.textSec, fontWeight: 600, marginBottom: 6 }}>Notiz / Grund</div>
            <textarea
              value={currentReason}
              onChange={(e) => setReasonDraft(e.target.value)}
              placeholder="z.B. Equipment beschädigt zurückgegeben, Zahlungsrückstand …"
              rows={2}
              style={{ width: '100%', boxSizing: 'border-box', padding: '9px 11px', borderRadius: 9, border: `0.5px solid ${t.inputBorder}`, background: t.inputBg, fontSize: 13, color: t.text, fontFamily: 'inherit', resize: 'vertical', outline: 'none' }} />
            {dirty && (
              <div style={{ marginTop: 8, display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
                <Pressable onClick={() => setReasonDraft(null)} scale={0.96}>
                  <div style={{ padding: '6px 12px', borderRadius: 8, fontSize: 12, fontWeight: 600, color: t.textSec }}>Abbrechen</div>
                </Pressable>
                <Pressable onClick={saveReason} scale={0.96}>
                  <div style={{ padding: '6px 12px', borderRadius: 8, fontSize: 12, fontWeight: 700, color: '#fff', background: t.accent }}>Notiz speichern</div>
                </Pressable>
              </div>
            )}
          </div>
        )}
      </div>
    </>
  );
}

// Inline calendar range picker — single tap = single day, second tap = range end.
function MiniRangePicker({ start, end, onChange, anchorISO }) {
  const t = useTheme();
  const anchorDate = anchorISO ? fromISO(anchorISO) : fromISO(start || todayISO());
  const [view, setView] = useState({ y: anchorDate.getFullYear(), m: anchorDate.getMonth() });
  const firstDayCol = (y, m) => (new Date(y, m, 1).getDay() + 6) % 7;
  const daysInMonth = (y, m) => new Date(y, m + 1, 0).getDate();
  const startOffset = firstDayCol(view.y, view.m);
  const dim = daysInMonth(view.y, view.m);
  const totalCells = Math.ceil((startOffset + dim) / 7) * 7;
  const labels = ['MO', 'DI', 'MI', 'DO', 'FR', 'SA', 'SO'];
  const cellISO = (d) => `${view.y}-${String(view.m + 1).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
  const isInRange = (d) => start && end && cellISO(d) >= start && cellISO(d) <= end;
  const isStart = (d) => start && cellISO(d) === start;
  const isEnd = (d) => end && cellISO(d) === end;
  const isToday = (d) => cellISO(d) === todayISO();
  const onDayTap = (d) => {
    const iso = cellISO(d);
    if (!start || start && end && start !== end) {onChange(iso, iso);return;}
    if (iso <= start) {onChange(iso, iso);return;}
    onChange(start, iso);
  };
  const move = (delta) => {const d = new Date(view.y, view.m + delta, 1);setView({ y: d.getFullYear(), m: d.getMonth() });};
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
        <Pressable onClick={() => move(-1)} scale={0.85}>
          <div style={{ width: 32, height: 32, borderRadius: 16, border: `1px solid ${t.sep}`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <Icon d="M15 6l-6 6 6 6" color={t.text} size={14} sw={2} />
          </div>
        </Pressable>
        <div style={{ fontSize: 16, fontWeight: 600, color: t.text, letterSpacing: -0.3 }}>{DE_MONTHS[view.m]} {view.y}</div>
        <Pressable onClick={() => move(1)} scale={0.85}>
          <div style={{ width: 32, height: 32, borderRadius: 16, border: `1px solid ${t.sep}`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <Icon d="M9 6l6 6-6 6" color={t.text} size={14} sw={2} />
          </div>
        </Pressable>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', marginBottom: 6 }}>
        {labels.map((l) => <div key={l} style={{ textAlign: 'center', fontSize: 10, color: t.textSec, fontWeight: 600, letterSpacing: 0.8 }}>{l}</div>)}
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)' }}>
        {Array.from({ length: totalCells }, (_, i) => {
          const d = i - startOffset + 1;
          const valid = d >= 1 && d <= dim;
          if (!valid) return <div key={i} style={{ height: 38 }} />;
          const inR = isInRange(d),sS = isStart(d),sE = isEnd(d),today = isToday(d);
          const singleDay = start && end && start === end && sS;
          const showLeftHalf = inR && !sS;
          const showRightHalf = inR && !sE;
          const isEdge = sS || sE;
          return (
            <Pressable key={i} onClick={() => onDayTap(d)} scale={0.92}>
              <div style={{ height: 38, position: 'relative', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                {inR && !singleDay &&
                <div style={{ position: 'absolute', top: '50%', transform: 'translateY(-50%)', left: showLeftHalf || isEdge ? sS ? '50%' : 0 : '50%', right: showRightHalf || isEdge ? sE ? '50%' : 0 : '50%', height: 28, background: t.chipStrong }} />
                }
                {(isEdge || singleDay) &&
                <div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', width: 28, height: 28, borderRadius: 14, background: t.solidBg }} />
                }
                {today && !singleDay && !isEdge &&
                <div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', width: 28, height: 28, borderRadius: 14, border: `1.5px solid ${t.text}` }} />
                }
                <span style={{ position: 'relative', fontSize: 13.5, fontWeight: 500, color: isEdge || singleDay ? '#fff' : today ? t.text : t.textSec, ...NUMS }}>{d}</span>
              </div>
            </Pressable>);

        })}
      </div>
      <div style={{ marginTop: 12, display: 'flex', gap: 18, fontSize: 11, color: t.textSec }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}><div style={{ width: 8, height: 8, borderRadius: 4, background: t.solidBg }} /> Ausgewählt</div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}><div style={{ width: 8, height: 8, borderRadius: 4, border: `1.5px solid ${t.text}` }} /> Heute</div>
      </div>
    </div>);

}

// Downscale an uploaded image to a JPEG data URL so it stays small in localStorage.
function scaleImageToDataURL(file, maxDim, cb) {
  const reader = new FileReader();
  reader.onload = (e) => {
    const img = new Image();
    img.onload = () => {
      let { width: w, height: h } = img;
      if (w > h && w > maxDim) { h = Math.round(h * maxDim / w); w = maxDim; }
      else if (h > maxDim) { w = Math.round(w * maxDim / h); h = maxDim; }
      const cv = document.createElement('canvas');
      cv.width = w; cv.height = h;
      cv.getContext('2d').drawImage(img, 0, 0, w, h);
      cb(cv.toDataURL('image/jpeg', 0.82));
    };
    img.onerror = () => cb('');
    img.src = e.target.result;
  };
  reader.onerror = () => cb('');
  reader.readAsDataURL(file);
}

// One ID-card photo slot — empty drop-zone or filled thumbnail with replace/remove.
function IdPhotoSlot({ label, hint, value, onChange, t }) {
  const ref = useRef(null);
  const [busy, setBusy] = useState(false);
  const pick = (e) => {
    const file = e.target.files && e.target.files[0];
    e.target.value = '';
    if (!file || !/^image\//.test(file.type)) return;
    setBusy(true);
    scaleImageToDataURL(file, 1280, (url) => { setBusy(false); if (url) onChange(url); });
  };
  return (
    <div style={{ flex: 1, minWidth: 0 }}>
      <div style={{ fontSize: 11, color: t.textSec, fontWeight: 600, marginBottom: 6 }}>{label}</div>
      <input ref={ref} type="file" accept="image/*" capture="environment" onChange={pick} style={{ display: 'none' }} />
      {value ? (
        <div style={{ position: 'relative', borderRadius: 12, overflow: 'hidden', border: `0.5px solid ${t.sep}`, aspectRatio: '1.586 / 1', background: t.cardAlt }}>
          <img src={value} alt={label} style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
          <div style={{ position: 'absolute', top: 6, right: 6, display: 'flex', gap: 6 }}>
            <Pressable onClick={() => ref.current && ref.current.click()} scale={0.9}>
              <div title="Ersetzen" style={{ width: 28, height: 28, borderRadius: 8, background: 'rgba(0,0,0,0.55)', backdropFilter: 'blur(8px)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon d={icons.camera || icons.upload} color="#fff" size={14} sw={2} /></div>
            </Pressable>
            <Pressable onClick={() => onChange('')} scale={0.9}>
              <div title="Entfernen" style={{ width: 28, height: 28, borderRadius: 8, background: 'rgba(0,0,0,0.55)', backdropFilter: 'blur(8px)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon d={icons.trash} color="#fff" size={14} sw={2} /></div>
            </Pressable>
          </div>
        </div>
      ) : (
        <Pressable onClick={() => ref.current && ref.current.click()} scale={0.98}>
          <div style={{ aspectRatio: '1.586 / 1', borderRadius: 12, border: `1.5px dashed ${t.sep}`, background: t.cardAlt, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 7, textAlign: 'center', padding: 12 }}>
            {busy ? (
              <span className="rf-spin" style={{ width: 18, height: 18, borderRadius: 9, border: '2px solid ' + t.accent, borderTopColor: 'transparent', display: 'inline-block' }} />
            ) : (
              <>
                <div style={{ width: 36, height: 36, borderRadius: 10, background: t.chip, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon d={icons.camera || icons.upload} color={t.textSec} size={17} sw={1.8} /></div>
                <div style={{ fontSize: 12, fontWeight: 600, color: t.text }}>Foto hochladen</div>
                <div style={{ fontSize: 10.5, color: t.textTer }}>{hint}</div>
              </>
            )}
          </div>
        </Pressable>
      )}
    </div>
  );
}

// Collapsible list of equipment that can still be added to the rental.
// Header shows "X verfügbar" and a chevron; expanded body is a list with
// avatar, name, category, free-in-range badge, and a "+" affordance.
function AddEquipmentList({ equipment, allEquipment, rentals, form, addItem }) {
  const t = useTheme();
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');
  const enriched = equipment.map((e) => ({ e, av: eqAvailabilityInRange(allEquipment, e.id, form.start, form.end, rentals, form.id) }));
  const freeCount = enriched.filter((x) => x.av.available > 0).length;
  const filtered = enriched.filter(({ e }) => {
    if (!query.trim()) return true;
    const q = query.trim().toLowerCase();
    return (e.name || '').toLowerCase().includes(q) || (e.cat || '').toLowerCase().includes(q) || (e.sub || '').toLowerCase().includes(q);
  });
  return (
    <div style={{ marginTop: 8, background: t.card, borderRadius: 12, border: `0.5px solid ${t.sep}`, overflow: 'hidden' }}>
      <Pressable onClick={() => setOpen((v) => !v)} scale={0.998} hoverBg={t.cardAlt}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '11px 14px' }}>
          <div style={{ width: 28, height: 28, borderRadius: 8, background: t.chip, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
            <Icon d={icons.plus} color={t.text} size={14} sw={2.4} />
          </div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 13.5, fontWeight: 600, color: t.text }}>Equipment hinzufügen</div>
            <div style={{ fontSize: 11.5, color: t.textSec, marginTop: 1, ...NUMS }}>{freeCount} von {equipment.length} im Zeitraum verfügbar</div>
          </div>
          <Icon d={open ? 'M5 15l7-7 7 7' : 'M5 9l7 7 7-7'} color={t.textSec} size={15} sw={2} />
        </div>
      </Pressable>
      {open && (
        <div style={{ borderTop: `0.5px solid ${t.sep}`, background: t.cardAlt }}>
          {equipment.length > 4 && (
            <div style={{ padding: '8px 12px', borderBottom: `0.5px solid ${t.sep}`, background: t.card }}>
              <input
                value={query}
                onChange={(e) => setQuery(e.target.value)}
                placeholder="Suchen …"
                style={{ width: '100%', boxSizing: 'border-box', padding: '7px 10px', borderRadius: 8, border: `0.5px solid ${t.inputBorder}`, background: t.inputBg, fontSize: 12.5, color: t.text, fontFamily: 'inherit', outline: 'none' }} />
            </div>
          )}
          <div style={{ maxHeight: 260, overflowY: 'auto' }}>
            {filtered.length === 0 ? (
              <div style={{ padding: '16px 12px', textAlign: 'center', fontSize: 12, color: t.textSec }}>Keine Treffer.</div>
            ) : filtered.map(({ e, av }, i) => {
              const free = av.available;
              const isFull = av.exists && free === 0;
              const pillColor = isFull ? (t.red || '#FF3B30') : free < av.total ? (t.orange || '#FF9500') : (t.green || '#34C759');
              return (
                <Pressable key={e.id} onClick={() => addItem(e)} scale={0.998} hoverBg={t.card}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '9px 14px', borderTop: i === 0 ? 'none' : `0.5px solid ${t.sep}`, opacity: isFull ? 0.75 : 1 }}>
                    <EqAvatar item={e} size={32} radius={7} />
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 13, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{e.name}</div>
                      <div style={{ fontSize: 11, color: t.textSec, marginTop: 1, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{e.cat || e.kind}{e.sub ? ' · ' + e.sub : ''}</div>
                    </div>
                    <span style={{ fontSize: 10.5, fontWeight: 700, padding: '3px 8px', borderRadius: 100, background: pillColor + '22', color: pillColor, ...NUMS, flexShrink: 0 }}>{free}/{av.total} frei</span>
                    <div style={{ width: 26, height: 26, borderRadius: 7, background: t.chip, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                      <Icon d={icons.plus} color={t.text} size={13} sw={2.4} />
                    </div>
                  </div>
                </Pressable>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

// ── Conflicts alert — clean, organized view of all booking conflicts ──
// Shows WHICH other rentals are using each over-booked equipment, in the same
// date range. Used in the rental form (while editing) and the detail pane.
//   props.conflicts  : [{ it, qty, av }]  — output of the conflict filter
//   props.range      : { start, end, excludeId }
//   props.onOpenRental(id?) — if provided, conflicting-rental rows are clickable
//   props.onAction()  — optional CTA on the right (e.g. "Anpassen")
function ConflictsAlert({ conflicts, equipment, rentals, range, onOpenRental, onAction, actionLabel = 'Anpassen', tightTop = false }) {
  const t = useTheme();
  if (!conflicts || !conflicts.length) return null;
  const red = t.red || '#FF3B30';
  const involvedIds = new Set();
  const enriched = conflicts.map((x) => {
    const eq = equipment.find((q) => q.id === x.it.equipmentId) || null;
    const others = eqConflictsInRange(x.it.equipmentId, range.start, range.end, rentals, range.excludeId);
    others.forEach((o) => involvedIds.add(o.rental.id));
    return { x, eq, others };
  });

  return (
    <div style={{ marginTop: tightTop ? 8 : 12, borderRadius: 13, background: red + '14', border: `1px solid ${red}40`, overflow: 'hidden' }}>
      {/* Header */}
      <div style={{ padding: '11px 14px', display: 'flex', alignItems: 'center', gap: 12, background: red + '0e', borderBottom: `1px solid ${red}26` }}>
        <div style={{ width: 28, height: 28, borderRadius: 14, background: red, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, color: '#fff', fontWeight: 800, fontSize: 14 }}>!</div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13.5, fontWeight: 700, color: red, letterSpacing: -0.1 }}>Belegungs-Konflikt im Zeitraum</div>
          <div style={{ fontSize: 11.5, color: t.textSec, marginTop: 1, ...NUMS }}>
            {conflicts.length} {conflicts.length === 1 ? 'Gerät' : 'Geräte'} überbucht · betrifft {involvedIds.size} {involvedIds.size === 1 ? 'Mietvorgang' : 'Mietvorgänge'}
          </div>
        </div>
        {onAction && (
          <Pressable onClick={onAction} scale={0.96}>
            <div style={{ padding: '7px 12px', borderRadius: 9, background: red, color: '#fff', fontSize: 12, fontWeight: 700, whiteSpace: 'nowrap' }}>{actionLabel}</div>
          </Pressable>
        )}
      </div>

      {/* Per-equipment groups */}
      <div>
        {enriched.map(({ x, eq, others }, i) => {
          const over = Math.max(0, x.qty - x.av.available);
          return (
            <div key={i} style={{ padding: '11px 14px 12px', borderTop: i === 0 ? 'none' : `0.5px solid ${red}22` }}>
              {/* Equipment summary row */}
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <EqAvatar item={eq || {}} size={30} radius={7} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13.5, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                    {eq ? eq.name : x.it.equipmentName}
                  </div>
                  <div style={{ fontSize: 11.5, color: t.textSec, marginTop: 2, ...NUMS }}>
                    {x.qty} angefragt · nur {x.av.available} von {x.av.total} verfügbar
                  </div>
                </div>
                <div style={{ padding: '4px 9px', borderRadius: 100, background: red, color: '#fff', fontSize: 11, fontWeight: 700, ...NUMS, flexShrink: 0 }}>
                  {over} zu viel
                </div>
              </div>

              {/* WHERE it's in use: list of conflicting rentals */}
              {others.length > 0 && (
                <div style={{ marginTop: 10, marginLeft: 40 }}>
                  <div style={{ fontSize: 10, fontWeight: 700, color: t.textSec, textTransform: 'uppercase', letterSpacing: 0.6, marginBottom: 6 }}>
                    Im Einsatz bei
                  </div>
                  <div style={{ background: t.card, borderRadius: 10, border: `0.5px solid ${t.sep}`, overflow: 'hidden' }}>
                    {others.map((o, j) => {
                      const oR = o.rental;
                      const clickable = !!onOpenRental;
                      const sameDay = oR.start === oR.end;
                      const range = sameDay ? fmtDateDE(oR.start) : `${fmtDateDE(oR.start).slice(0, 6)}–${fmtDateDE(oR.end).slice(0, 6)}.${fmtDateDE(oR.end).slice(6)}`;
                      const inner = (
                        <div style={{ display: 'flex', alignItems: 'center', gap: 9, padding: '8px 10px', borderTop: j === 0 ? 'none' : `0.5px solid ${t.sep}` }}>
                          <Avatar name={oR.tenantName} size={24} />
                          <div style={{ flex: 1, minWidth: 0 }}>
                            <div style={{ fontSize: 12.5, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{oR.tenantName}</div>
                            <div style={{ fontSize: 10.5, color: t.textSec, marginTop: 1, ...NUMS }}>{range}</div>
                          </div>
                          <div style={{ padding: '2px 7px', borderRadius: 100, background: t.chip, fontSize: 10.5, fontWeight: 700, color: t.text, ...NUMS, flexShrink: 0 }}>×{o.qty}</div>
                          <StatusPill status={oR.status} />
                          {clickable && <Icon d={icons.chev} color={t.textTer} size={11} sw={2.2} />}
                        </div>
                      );
                      return clickable ? (
                        <Pressable key={oR.id + '-' + j} onClick={() => onOpenRental(oR.id)} scale={0.998} hoverBg={t.cardAlt}>{inner}</Pressable>
                      ) : <div key={oR.id + '-' + j}>{inner}</div>;
                    })}
                  </div>
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ── New / Edit rental dialog ──
function RentalSheet({ open, onClose, initial, equipment, onSave, blocked = [], setBlocked, rentals = [] }) {
  const t = useTheme();
  const isEdit = !!(initial && initial.id);
  const blank = {
    id: '', status: 'reserviert', tenantName: '', address: '', email: '', phone: '', idCard: '', idFront: '', idBack: '',
    items: equipment[0] ? [{ equipmentId: equipment[0].id, equipmentName: equipment[0].name, quantity: 1, dailyRate: equipment[0].price }] : [],
    purpose: '',
    start: todayISO(), end: tomorrowISO(), startTime: '14:00', endTime: '11:00',
    deposit: 100, discount: 0,
    depositStatus: 'offen', paymentStatus: 'offen',
    delivery: { enabled: false, address: '', km: 0, tripFactor: LOGISTIK_DEFAULTS.tripFactor }
  };
  const [form, setForm] = useState(blank);
  const [showPicker, setShowPicker] = useState(false);
  const [addrLooking, setAddrLooking] = useState(false);
  const [addrErr, setAddrErr] = useState('');
  useEffect(() => {
    if (!open) return;
    if (!initial) {setForm(blank);return;}
    let next = { ...blank, ...initial };
    if (!next.items || !next.items.length) {
      // Migrate legacy single-equipment rental to items[]
      const e = equipment.find((x) => x.id === initial.equipmentId);
      next.items = initial.equipmentId ? [{ equipmentId: initial.equipmentId, equipmentName: e && e.name || initial.equipmentName, quantity: Math.max(1, Number(initial.quantity) || 1), dailyRate: Number(initial.dailyRate) || e && e.price || 0 }] : [];
    }
    setForm(next);
  }, [open, initial]);
  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));
  const setItems = (next) => setForm((f) => ({ ...f, items: typeof next === 'function' ? next(f.items || []) : next }));
  const updateItem = (idx, k, v) => setItems((its) => its.map((it, i) => i === idx ? { ...it, [k]: v } : it));
  const removeItem = (idx) => setItems((its) => its.filter((_, i) => i !== idx));
  const addItem = (e) => setItems((its) => [...its, { equipmentId: e.id, equipmentName: e.name, quantity: 1, dailyRate: e.price || 0 }]);
  const total = rentalTotal(form);
  const days = daysBetween(form.start, form.end);
  const itemsCount = (form.items || []).length;
  const valid = form.tenantName.trim() && itemsCount > 0 && form.start && form.end && form.end >= form.start;

  const save = () => {
    if (!valid) return;
    const status = autoRentalStatus(form.start, form.end);
    const items = (form.items || []).map((it) => ({ ...it, quantity: Math.max(1, Number(it.quantity) || 1), dailyRate: Number(it.dailyRate) || 0 }));
    const first = items[0];
    const summaryName = items.length === 1 ?
    first.equipmentName + (first.quantity > 1 ? ' ×' + first.quantity : '') :
    first.equipmentName + ' + ' + (items.length - 1) + ' weitere';
    // Auto-flip payment & deposit status from rental status
    const paymentStatus = status === 'aktiv' || status === 'abgeschlossen' ? 'bezahlt' : form.paymentStatus || 'offen';
    const depositStatus = status === 'aktiv' ? 'erhalten' : status === 'abgeschlossen' ? 'zurueckgezahlt' : form.depositStatus || 'offen';
    onSave({
      ...form, items, id: form.id || 'r-' + Date.now(), status,
      paymentStatus, depositStatus,
      startTime: form.allDay ? '' : form.startTime,
      endTime: form.allDay ? '' : form.endTime,
      // Legacy mirror fields so existing screens keep working
      equipmentId: first.equipmentId, equipmentName: summaryName,
      dailyRate: first.dailyRate, quantity: first.quantity,
      deposit: Number(form.deposit) || 0
    });
    onClose();
  };

  return (
    <Sheet open={open} onClose={onClose} width={640}>
      <div style={{ padding: '4px 28px 26px' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 4 }}>
          <div>
            <div style={{ fontSize: 22, fontWeight: 700, color: t.text, letterSpacing: -0.5 }}>{isEdit ? 'Mietvorgang bearbeiten' : 'Neuer Mietvorgang'}</div>
            <div style={{ fontSize: 13, color: t.textSec, marginTop: 3 }}>{isEdit ? 'Daten anpassen und speichern' : 'Mieter, Zeitraum und Equipment erfassen'}</div>
          </div>
          <Pressable onClick={onClose}><div style={{ fontSize: 14, color: t.textSec, fontWeight: 500 }}>Abbrechen</div></Pressable>
        </div>

        <div style={{ fontSize: 11, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, marginTop: 20, marginBottom: 4 }}>Mieter</div>
        {(() => {
          const be = findBlockEntry(form.tenantName, form.phone, form.email, blocked);
          if (!be) return null;
          return (
            <div style={{ marginTop: 8, padding: '11px 13px', borderRadius: 11, background: (t.red || '#FF3B30') + '18', border: `1px solid ${(t.red || '#FF3B30')}55`, display: 'flex', gap: 11, alignItems: 'flex-start' }}>
              <div style={{ width: 26, height: 26, borderRadius: 13, background: t.red || '#FF3B30', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, color: '#fff', fontWeight: 800, fontSize: 14 }}>!</div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13.5, fontWeight: 700, color: t.red || '#FF3B30' }}>Achtung — Kunde ist gesperrt</div>
                <div style={{ fontSize: 12, color: t.text, marginTop: 3, lineHeight: 1.4 }}>
                  {be.reason ? <><b>Grund:</b> {be.reason}</> : 'Kein Grund hinterlegt.'}
                  {be.blockedAt && <span style={{ color: t.textSec, marginLeft: 6, ...NUMS }}>· seit {fmtDateDE(be.blockedAt)}</span>}
                </div>
              </div>
            </div>
          );
        })()}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
          <Field label="Name" required style={{ marginTop: 8 }}><TextInput value={form.tenantName} onChange={(e) => set('tenantName', e.target.value)} placeholder="z.B. Andreas Müller" /></Field>
          <Field label="Telefon" style={{ marginTop: 8 }}><TextInput value={form.phone} onChange={(e) => set('phone', e.target.value)} placeholder="+49 …" /></Field>
          <Field label="E-Mail" style={{ marginTop: 8 }}><TextInput value={form.email} onChange={(e) => set('email', e.target.value)} placeholder="name@example.com" /></Field>
          <Field label="Ausweis-Nr." style={{ marginTop: 8 }}><TextInput value={form.idCard} onChange={(e) => set('idCard', e.target.value)} placeholder="optional" /></Field>
        </div>
        <Field label="Adresse" style={{ marginTop: 14 }}><TextInput value={form.address} onChange={(e) => set('address', e.target.value)} placeholder="Straße, PLZ Ort" /></Field>

        {/* ── Ausweis-Fotos ── */}
        <div style={{ fontSize: 11, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, marginTop: 22, marginBottom: 4 }}>Personalausweis</div>
        <div style={{ fontSize: 11.5, color: t.textTer, marginBottom: 12 }}>Vorder- und Rückseite fotografieren oder hochladen – wird sicher beim Mietvorgang gespeichert.</div>
        <div style={{ display: 'flex', gap: 14 }}>
          <IdPhotoSlot label="Vorderseite" hint="Foto- &amp; Datenseite" value={form.idFront} onChange={(v) => set('idFront', v)} t={t} />
          <IdPhotoSlot label="Rückseite" hint="Anschrift &amp; Behörde" value={form.idBack} onChange={(v) => set('idBack', v)} t={t} />
        </div>

        {/* ── Kundenstatus / Sperre ── */}
        <BlockToggleCard form={form} blocked={blocked} setBlocked={setBlocked} />

        {/* ── MIETDATEN ── */}
        {(() => {
          const computedStatus = autoRentalStatus(form.start, form.end);
          const isReserved = computedStatus === 'reserviert';
          const effPayment = !isReserved ? 'bezahlt' : form.paymentStatus || 'offen';
          const effDeposit = computedStatus === 'aktiv' ? 'erhalten' : computedStatus === 'abgeschlossen' ? 'zurueckgezahlt' : form.depositStatus || 'offen';
          const allDay = !!form.allDay;
          const PAYMENT_META = { offen: { color: t.orange, label: 'Mietbetrag offen' }, bezahlt: { color: t.green, label: 'Mietbetrag bezahlt' } };
          const rowStyle = { display: 'flex', alignItems: 'center', gap: 14, padding: '14px 16px' };
          const labelTxt = { fontSize: 14, color: t.text, fontWeight: 500 };
          const subTxt = { fontSize: 11.5, color: t.textSec, marginTop: 2, ...NUMS };
          const numInp = { width: 110, padding: '8px 10px', borderRadius: 8, border: `0.5px solid ${t.inputBorder}`, background: t.inputBg, fontSize: 14, color: t.text, fontFamily: 'inherit', fontWeight: 600, textAlign: 'right', boxSizing: 'border-box' };
          const Toggle = ({ on, onClick }) =>
          <Pressable onClick={onClick} scale={0.95}>
              <div style={{ width: 46, height: 28, borderRadius: 14, background: on ? t.green : t.chipStrong, position: 'relative', transition: 'background 0.15s' }}>
                <div style={{ position: 'absolute', top: 2, left: on ? 20 : 2, width: 24, height: 24, borderRadius: 12, background: '#fff', boxShadow: '0 2px 6px rgba(0,0,0,0.18)', transition: 'left 0.15s' }} />
              </div>
            </Pressable>;

          const fmtShort = (iso) => {if (!iso) return '';const d = fromISO(iso);return `${String(d.getDate()).padStart(2, '0')}.${String(d.getMonth() + 1).padStart(2, '0')}`;};
          return (
            <>
              <div style={{ fontSize: 11, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, marginTop: 22, marginBottom: 8 }}>Mietdaten</div>
              <div style={{ background: t.card, borderRadius: 14, border: `0.5px solid ${t.sep}`, overflow: 'hidden' }}>
                {/* Zweck */}
                <div style={rowStyle}>
                  <div style={{ ...labelTxt, flexShrink: 0 }}>Zweck</div>
                  <div style={{ flex: 1 }} />
                  <input value={form.purpose || ''} onChange={(e) => set('purpose', e.target.value)} placeholder="z.B. Hochzeit" style={{ minWidth: 0, flex: '0 1 320px', padding: '8px 10px', borderRadius: 8, border: `0.5px solid ${t.inputBorder}`, background: t.inputBg, fontSize: 14, color: t.text, fontFamily: 'inherit', fontWeight: 500, textAlign: 'right', boxSizing: 'border-box' }} />
                </div>
                {/* Zeitraum (expandable inline calendar) */}
                <Pressable onClick={() => setShowPicker((s) => !s)} scale={0.995}>
                  <div style={{ ...rowStyle, borderTop: `0.5px solid ${t.sep}`, cursor: 'pointer' }}>
                    <div>
                      <div style={{ fontSize: 15, fontWeight: 600, color: t.text, ...NUMS }}>{fmtRange(form.start, form.end)}</div>
                      <div style={subTxt}>{days} Tag{days > 1 ? 'e' : ''}</div>
                    </div>
                    <div style={{ flex: 1 }} />
                    <Icon d={showPicker ? 'M5 15l7-7 7 7' : 'M5 9l7 7 7-7'} color={t.textSec} size={16} sw={2} />
                  </div>
                </Pressable>
                {showPicker &&
                <div style={{ padding: '8px 16px 16px', borderTop: `0.5px solid ${t.sep}`, background: t.cardAlt }}>
                    <MiniRangePicker
                    start={form.start} end={form.end}
                    onChange={(s, e) => {set('start', s);set('end', e);}}
                    anchorISO={form.start} />
                  
                  </div>
                }
                {/* Ganzer Tag */}
                <div style={{ ...rowStyle, borderTop: `0.5px solid ${t.sep}` }}>
                  <div>
                    <div style={{ fontSize: 14, color: t.text, fontWeight: 600 }}>Ganzer Tag</div>
                    <div style={subTxt}>Uhrzeiten werden nicht erfasst</div>
                  </div>
                  <div style={{ flex: 1 }} />
                  <Toggle on={allDay} onClick={() => {set('allDay', !allDay);if (!allDay) {set('startTime', '');set('endTime', '');}}} />
                </div>
                {/* Abholung */}
                {!allDay &&
                <div style={{ ...rowStyle, borderTop: `0.5px solid ${t.sep}` }}>
                    <div>
                      <div style={labelTxt}>Abholung</div>
                      <div style={subTxt}>{fmtShort(form.start)}</div>
                    </div>
                    <div style={{ flex: 1 }} />
                    <input type="time" value={form.startTime || ''} onChange={(e) => set('startTime', e.target.value)} style={numInp} />
                  </div>
                }
                {/* Rückgabe */}
                {!allDay &&
                <div style={{ ...rowStyle, borderTop: `0.5px solid ${t.sep}` }}>
                    <div>
                      <div style={labelTxt}>Rückgabe</div>
                      <div style={subTxt}>{fmtShort(form.end)}</div>
                    </div>
                    <div style={{ flex: 1 }} />
                    <input type="time" value={form.endTime || ''} onChange={(e) => set('endTime', e.target.value)} style={numInp} />
                  </div>
                }
                {/* Kaution */}
                <div style={{ ...rowStyle, borderTop: `0.5px solid ${t.sep}` }}>
                  <div style={labelTxt}>Kaution €</div>
                  <div style={{ flex: 1 }} />
                  <input type="number" value={form.deposit} onChange={(e) => set('deposit', e.target.value)} style={numInp} />
                </div>
                {/* Rabatt */}
                <div style={{ ...rowStyle, borderTop: `0.5px solid ${t.sep}` }}>
                  <div>
                    <div style={labelTxt}>Rabatt €</div>
                    <div style={subTxt}>Wird vom Gesamtpreis abgezogen</div>
                  </div>
                  <div style={{ flex: 1 }} />
                  <input type="number" value={form.discount || 0} onChange={(e) => set('discount', e.target.value)} style={numInp} />
                </div>
              </div>
            </>);

        })()}

        <div style={{ fontSize: 11, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, marginTop: 22, marginBottom: 4 }}>Equipment</div>
        {(() => {
          // Per-item date-range availability (excludes self when editing).
          const itemsAvail = (form.items || []).map((it) => ({
            it,
            qty: Math.max(1, Number(it.quantity) || 1),
            av: eqAvailabilityInRange(equipment, it.equipmentId, form.start, form.end, rentals, form.id)
          }));
          const conflicts = itemsAvail.filter((x) => x.av.exists && x.qty > x.av.available);
          if (!conflicts.length) return null;
          return (
            <ConflictsAlert
              conflicts={conflicts}
              equipment={equipment}
              rentals={rentals}
              range={{ start: form.start, end: form.end, excludeId: form.id }}
              tightTop />
          );
        })()}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginTop: 8 }}>
          {(form.items || []).map((it, idx) => {
            const e = equipment.find((q) => q.id === it.equipmentId);
            const qty = Math.max(1, Number(it.quantity) || 1);
            const av = eqAvailabilityInRange(equipment, it.equipmentId, form.start, form.end, rentals, form.id);
            const conflict = av.exists && qty > av.available;
            const tight = av.exists && !conflict && qty >= av.available && av.available > 0;
            const availColor = !av.exists ? t.textTer : conflict ? (t.red || '#FF3B30') : tight ? (t.orange || '#FF9500') : (t.green || '#34C759');
            const availLabel = !av.exists ? 'Equipment nicht gefunden' :
              conflict ? `Nur ${av.available} von ${av.total} frei · ${qty - av.available} zu viel` :
              `${av.available} von ${av.total} frei im Zeitraum`;
            return (
              <div key={it.equipmentId + '-' + idx} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 10px', background: t.cardAlt, borderRadius: 11, border: conflict ? `1px solid ${(t.red || '#FF3B30')}66` : '1px solid transparent' }}>
                <EqAvatar item={e || {}} size={34} radius={8} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13.5, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{e && e.name || it.equipmentName}</div>
                  {e && <div style={{ fontSize: 11, color: t.textSec, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{e.cat}{e.sub ? ' · ' + e.sub : ''}</div>}
                  <div style={{ display: 'inline-flex', alignItems: 'center', gap: 5, marginTop: 3, fontSize: 10.5, fontWeight: 600, color: availColor, ...NUMS }}>
                    <span style={{ width: 6, height: 6, borderRadius: 3, background: availColor }} />{availLabel}
                  </div>
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1 }}>
                  <span style={{ fontSize: 10, color: t.textSec, fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0.4 }}>Anzahl</span>
                  <input type="number" min={1} value={it.quantity} onChange={(ev) => updateItem(idx, 'quantity', Number(ev.target.value) || 1)} style={{ width: 54, padding: '5px 6px', borderRadius: 7, border: `1px solid ${conflict ? (t.red || '#FF3B30') : t.sep}`, background: t.inputBg, color: conflict ? (t.red || '#FF3B30') : t.text, fontSize: 13, textAlign: 'center', outline: 'none', fontWeight: conflict ? 700 : 400, ...NUMS }} />
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1 }}>
                  <span style={{ fontSize: 10, color: t.textSec, fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0.4 }}>€/Tag</span>
                  <input type="number" min={0} value={it.dailyRate} onChange={(ev) => updateItem(idx, 'dailyRate', Number(ev.target.value) || 0)} style={{ width: 70, padding: '5px 6px', borderRadius: 7, border: `1px solid ${t.sep}`, background: t.inputBg, color: t.text, fontSize: 13, textAlign: 'right', outline: 'none', ...NUMS }} />
                </div>
                <Pressable onClick={() => removeItem(idx)} scale={0.9}>
                  <div title="Entfernen" style={{ width: 28, height: 28, borderRadius: 7, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon d={icons.trash} color={t.textSec} size={14} sw={1.8} /></div>
                </Pressable>
              </div>);

          })}
          {itemsCount === 0 &&
          <div style={{ padding: '16px 12px', textAlign: 'center', fontSize: 13, color: t.textSec, background: t.cardAlt, borderRadius: 11 }}>Noch kein Equipment ausgewählt</div>
          }
          {(() => {
            const used = new Set((form.items || []).map((it) => it.equipmentId));
            const available = equipment.filter((e) => !used.has(e.id));
            if (!available.length) return null;
            return <AddEquipmentList equipment={available} allEquipment={equipment} rentals={rentals} form={form} addItem={addItem} />;
          })()}
        </div>
        {/* ── Mietbetrag- & Kaution-Status ── */}
        {(() => {
          const computedStatus = autoRentalStatus(form.start, form.end);
          const isReserved = computedStatus === 'reserviert';
          const effPayment = !isReserved ? 'bezahlt' : form.paymentStatus || 'offen';
          const effDeposit = computedStatus === 'aktiv' ? 'erhalten' : computedStatus === 'abgeschlossen' ? 'zurueckgezahlt' : form.depositStatus || 'offen';
          const PAYMENT_META = { offen: { color: t.orange, label: 'Mietbetrag offen' }, bezahlt: { color: t.green, label: 'Mietbetrag bezahlt' } };
          return (
            <>
              <div style={{ fontSize: 11, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, marginTop: 22, marginBottom: 8 }}>Zahlungsstatus</div>

              {/* Mietbetrag-Status */}
              <div style={{ fontSize: 12.5, color: t.textSec, fontWeight: 600, marginBottom: 8 }}>Mietbetrag-Status</div>
              {isReserved ?
                <>
                  <div style={{ display: 'flex', gap: 6 }}>
                    {['offen', 'bezahlt'].map((s) => {
                      const pm = PAYMENT_META[s];
                      const sel = (form.paymentStatus || 'offen') === s;
                      return (
                        <Pressable key={s} onClick={() => set('paymentStatus', s)} scale={0.96} style={{ flex: 1 }}>
                          <div style={{ padding: '10px 0', textAlign: 'center', borderRadius: 10, fontSize: 12.5, fontWeight: 600, background: sel ? pm.color : t.chip, color: sel ? '#fff' : t.textSec }}>{pm.label}</div>
                        </Pressable>);
                    })}
                  </div>
                  <div style={{ fontSize: 11, color: t.textTer, marginTop: 8 }}>Manuell auf „Bezahlt" setzen, wenn der Mieter vorab überweist. Sobald die Miete startet, wechselt sie automatisch.</div>
                </> :
                (() => { const pm = PAYMENT_META[effPayment]; return (
                  <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '12px 14px', borderRadius: 10, background: pm.color + '20' }}>
                    <div style={{ width: 9, height: 9, borderRadius: 5, background: pm.color }} />
                    <div style={{ fontSize: 13.5, fontWeight: 700, color: pm.color }}>{pm.label}</div>
                    <div style={{ flex: 1 }} />
                    <div style={{ fontSize: 11, color: t.textSec, fontWeight: 500 }}>automatisch · aus Mietstatus</div>
                  </div>); })()
              }

              {/* Kaution-Status */}
              <div style={{ fontSize: 12.5, color: t.textSec, fontWeight: 600, marginTop: 18, marginBottom: 8 }}>Kaution-Status</div>
              {isReserved ?
                <>
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                    {['offen', 'bezahlt'].map((s) => {
                      const dm = depositMeta(s);
                      const sel = (form.depositStatus || 'offen') === s;
                      return (
                        <Pressable key={s} onClick={() => set('depositStatus', s)} scale={0.96} style={{ flex: 1 }}>
                          <div style={{ padding: '10px 0', textAlign: 'center', borderRadius: 10, fontSize: 12.5, fontWeight: 600, background: sel ? dm.color : t.chip, color: sel ? '#fff' : t.textSec }}>{dm.label}</div>
                        </Pressable>);
                    })}
                  </div>
                  <div style={{ fontSize: 11, color: t.textTer, marginTop: 8 }}>Manuell auf „Bezahlt" setzen, wenn Mieter vorab zahlt. Sobald die Miete startet, wechselt sie automatisch auf „Aktiv".</div>
                </> :
                (() => { const dm = depositMeta(effDeposit); return (
                  <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '12px 14px', borderRadius: 10, background: dm.color + '20' }}>
                    <div style={{ width: 9, height: 9, borderRadius: 5, background: dm.color }} />
                    <div style={{ fontSize: 13.5, fontWeight: 700, color: dm.color }}>{dm.label}</div>
                    <div style={{ flex: 1 }} />
                    <div style={{ fontSize: 11, color: t.textSec, fontWeight: 500 }}>automatisch · aus Mietstatus</div>
                  </div>); })()
              }
            </>
          );
        })()}

        {/* ── Lieferung ── */}
        {(() => {
          const d = form.delivery || { enabled: false, address: '', km: 0, tripFactor: LOGISTIK_DEFAULTS.tripFactor };
          const setD = (patch) => set('delivery', { ...d, ...patch });
          const factor = d.tripFactor || LOGISTIK_DEFAULTS.tripFactor;
          const calc = calcDelivery(d.km, factor);
          const lookup = async () => {
            const q = (d.address || '').trim();
            if (!q) {setAddrErr('Adresse eintragen');return;}
            setAddrLooking(true);setAddrErr('');
            try {
              const from = await geocodeAddress(LOGISTIK_DEFAULTS.lagerAddress);
              const to = await geocodeAddress(q);
              const km = await routeDistanceKm(from, to);
              setD({ km: Math.round(km * 10) / 10 });
            } catch (err) {
              setAddrErr(err && err.message ? err.message : 'Fehler bei der Berechnung');
            } finally {
              setAddrLooking(false);
            }
          };
          const tabBtn = (on, icon, label, sel) =>
          <Pressable onClick={() => setD({ enabled: on })} scale={0.96} style={{ flex: 1 }}>
              <div style={{ padding: '11px 14px', textAlign: 'center', borderRadius: 11, fontSize: 13, fontWeight: 600, background: sel ? t.card : 'transparent', color: sel ? t.text : t.textSec, boxShadow: sel ? '0 1px 3px rgba(0,0,0,0.08)' : 'none', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8 }}>
                <span style={{ fontSize: 16 }}>{icon}</span>{label}
              </div>
            </Pressable>;

          // Existing rental created with Selbstabholung → compact "+ Hinzufügen" row
          // (per request: only show this affordance when editing an existing contract).
          if (isEdit && !d.enabled) {
            return (
              <div style={{ marginTop: 22 }}>
                <div style={{ fontSize: 11, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 8 }}>Abholung & Rückgabe</div>
                <div style={{ background: t.card, borderRadius: 14, border: `0.5px solid ${t.sep}`, padding: '14px 16px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
                  <div>
                    <div style={{ fontSize: 14, color: t.text, fontWeight: 600 }}>Lieferung</div>
                    <div style={{ fontSize: 11.5, color: t.textSec, marginTop: 2 }}>Bei Vertragsabschluss: Selbstabholung · jetzt nachträglich hinzufügen</div>
                  </div>
                  <Pressable onClick={() => setD({ enabled: true })} scale={0.96}>
                    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '6px 10px', borderRadius: 8, color: t.accent, fontSize: 13, fontWeight: 600 }}>
                      <span style={{ fontSize: 15, lineHeight: 1, fontWeight: 500 }}>+</span> Hinzufügen
                    </div>
                  </Pressable>
                </div>
              </div>);

          }
          return (
            <div style={{ marginTop: 22 }}>
              <div style={{ fontSize: 11, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 8 }}>Abholung & Rückgabe</div>
              <div style={{ display: 'flex', gap: 4, background: t.chip, borderRadius: 13, padding: 4, marginBottom: d.enabled ? 12 : 0 }}>
                {tabBtn(false, '🏠', 'Kunde holt & bringt', !d.enabled)}
                {tabBtn(true, '🚚', 'Wir liefern & holen ab', d.enabled)}
              </div>
              {d.enabled &&
              <div style={{ background: t.card, borderRadius: 14, border: `0.5px solid ${t.sep}`, padding: 14 }}>
                  <textarea
                  value={d.address || ''}
                  onChange={(e) => {setD({ address: e.target.value });setAddrErr('');}}
                  placeholder="Lieferadresse — Straße, PLZ Ort"
                  rows={2}
                  style={{ width: '100%', boxSizing: 'border-box', padding: '10px 12px', borderRadius: 10, border: `0.5px solid ${t.inputBorder}`, background: t.inputBg, fontSize: 13.5, color: t.text, fontFamily: 'inherit', resize: 'vertical', outline: 'none' }} />
                
                  <Pressable onClick={lookup} scale={0.98} disabled={addrLooking || !(d.address || '').trim()}>
                    <div style={{ marginTop: 8, padding: '11px 0', textAlign: 'center', borderRadius: 11, background: (d.address || '').trim() && !addrLooking ? t.solidBg : t.chip, color: (d.address || '').trim() && !addrLooking ? t.solidFg : t.textTer, fontSize: 13, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8 }}>
                      {addrLooking ?
                    <><span className="rf-spin" style={{ width: 12, height: 12, borderRadius: 6, border: '1.6px solid currentColor', borderTopColor: 'transparent', display: 'inline-block' }} /> Berechne …</> :
                    <>Entfernung aus Adresse berechnen</>
                    }
                    </div>
                  </Pressable>
                  {addrErr && <div style={{ marginTop: 6, fontSize: 11, color: t.red, fontWeight: 500 }}>{addrErr}</div>}

                  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.4fr', gap: 10, marginTop: 12, alignItems: 'flex-start' }}>
                    <div>
                      <div style={{ fontSize: 11, color: t.textSec, fontWeight: 600, marginBottom: 4 }}>Entfernung (einf.)</div>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '10px 12px', border: `0.5px solid ${t.inputBorder}`, borderRadius: 10, background: t.inputBg }}>
                        <input type="number" value={d.km || ''} onChange={(e) => setD({ km: e.target.value })} placeholder="0" style={{ flex: 1, minWidth: 0, border: 'none', outline: 'none', background: 'transparent', fontSize: 15, fontWeight: 600, color: t.text, fontFamily: 'inherit', ...NUMS }} />
                        <span style={{ fontSize: 12, color: t.textSec, fontWeight: 500 }}>km</span>
                      </div>
                    </div>
                    <div>
                      <div style={{ fontSize: 11, color: t.textSec, fontWeight: 600, marginBottom: 4 }}>Fahrten · nur intern</div>
                      <div style={{ display: 'flex', gap: 4, background: t.chip, borderRadius: 10, padding: 3 }}>
                        {TRIP_OPTIONS.map((opt) => {
                        const sel = factor === opt.f;
                        return (
                          <Pressable key={opt.f} onClick={() => setD({ tripFactor: opt.f })} scale={0.94} style={{ flex: 1 }}>
                              <div title={opt.sub} style={{ padding: '8px 0', textAlign: 'center', borderRadius: 8, fontSize: 13, fontWeight: 700, background: sel ? t.card : 'transparent', color: sel ? t.text : t.textSec, boxShadow: sel ? '0 1px 2px rgba(0,0,0,0.07)' : 'none' }}>{opt.label}</div>
                            </Pressable>);

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

                  <div style={{ marginTop: 12, padding: '12px 14px', borderRadius: 11, background: t.accentSoft, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                    <div style={{ fontSize: 12, color: t.textSec, fontWeight: 500, ...NUMS }}>
                      {calc.totalKm > 0 ?
                    <>{String(calc.tripKm).replace('.', ',')} km × {calc.factor} · {LOGISTIK_DEFAULTS.kmRate.toFixed(2).replace('.', ',')} €/km + {LOGISTIK_DEFAULTS.pauschale.toFixed(0)} € Pauschale</> :
                    <>Pauschale + km × Satz</>
                    }
                    </div>
                    <div style={{ fontSize: 18, fontWeight: 700, color: t.accent, ...NUMS }}>+ {calc.total.toFixed(2).replace('.', ',')} €</div>
                  </div>
                </div>
              }
            </div>);

        })()}
        <Field label="Farbe (Kalender-Anzeige)" style={{ marginTop: 12 }}>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' }}>
            {['#34C759', '#FF9500', '#5856D6', '#FF2D55', '#AF52DE', '#007AFF', '#1c1c1e', '#8E8E93'].map((c) =>
            <Pressable key={c} onClick={() => set('color', c)} scale={0.86}><div style={{ width: 28, height: 28, borderRadius: 14, background: c, border: form.color === c ? `2.5px solid ${t.text}` : '2.5px solid transparent', boxShadow: `0 0 0 1px ${t.sep}` }} /></Pressable>
            )}
            {form.color && <Pressable onClick={() => set('color', '')} scale={0.95}><div style={{ fontSize: 11.5, color: t.textSec, fontWeight: 600, padding: '4px 10px' }}>Status-Farbe</div></Pressable>}
          </div>
        </Field>

        {/* total preview */}
        {(() => {
          const fee = rentalDeliveryFee(form);
          return (
            <div style={{ marginTop: 20, padding: '14px 18px', borderRadius: 12, background: t.cardAlt, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
              <div>
                <div style={{ fontSize: 13, color: t.text, fontWeight: 600 }}>Gesamt ({days} Tag{days > 1 ? 'e' : ''})</div>
                <div style={{ fontSize: 11, color: t.textSec, marginTop: 2 }}>Equipment{fee > 0 ? ' + ' + fee.toFixed(2).replace('.', ',') + ' € Lieferung' : ''}{Number(form.discount) ? ` − ${form.discount} € Rabatt` : ''}</div>
              </div>
              <div style={{ fontSize: 22, fontWeight: 700, color: t.text, ...NUMS }}>{total.toFixed(2).replace('.', ',')} €</div>
            </div>);

        })()}

        <Pressable onClick={save} scale={0.98} style={{ marginTop: 18 }}>
          {(() => {
            const hasConflict = (form.items || []).some((it) => {
              const av = eqAvailabilityInRange(equipment, it.equipmentId, form.start, form.end, rentals, form.id);
              return av.exists && Math.max(1, Number(it.quantity) || 1) > av.available;
            });
            const bg = !valid ? t.chip : hasConflict ? (t.orange || '#FF9500') : t.solidBg;
            const fg = !valid ? t.textTer : hasConflict ? '#fff' : t.solidFg;
            const lbl = !valid ? (isEdit ? 'Änderungen speichern' : 'Mietvorgang anlegen') :
              hasConflict ? (isEdit ? 'Trotz Konflikt speichern' : 'Trotz Konflikt anlegen') :
              (isEdit ? 'Änderungen speichern' : 'Mietvorgang anlegen');
            return (
              <div style={{ padding: '14px 0', textAlign: 'center', borderRadius: 12, background: bg, color: fg, fontSize: 15, fontWeight: 700, boxShadow: valid ? '0 6px 16px rgba(0,0,0,0.22)' : 'none', transition: 'all 0.15s' }}>{lbl}</div>
            );
          })()}
        </Pressable>
      </div>
    </Sheet>);

}

// ── Detail pane for a blocked customer ──
function BlockedCustomerDetail({ blk, rentals, blocked, setBlocked, toast, setSelId, setFilter, go }) {
  const t = useTheme();
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState(blk.reason || '');
  useEffect(() => { setDraft(blk.reason || ''); setEditing(false); }, [blk.id]);
  const save = () => {
    setBlocked((prev) => prev.map((b) => b.id === blk.id ? { ...b, reason: draft.trim() } : b));
    setEditing(false);
    if (toast) toast('Notiz gespeichert');
  };
  const unblock = () => {
    setBlocked((prev) => prev.filter((b) => b.id !== blk.id));
    if (toast) toast('Sperre aufgehoben');
    setSelId(null);
    setFilter('alle');
  };
  return (
    <Scroll padding={0}>
      <div style={{ padding: '26px 30px' }}>
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 16 }}>
          <div style={{ width: 56, height: 56, borderRadius: 14, background: (t.red || '#FF3B30') + '22', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
            <Icon d="M12 2L3 7v6c0 5 3.5 8.5 9 10 5.5-1.5 9-5 9-10V7l-9-5z" color={t.red || '#FF3B30'} size={26} sw={1.8} />
          </div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 24, fontWeight: 700, color: t.text, letterSpacing: -0.5 }}>{blk.name}</div>
            <div style={{ fontSize: 13.5, color: t.textSec, marginTop: 3 }}>Gesperrter Kunde · seit {blk.blockedAt ? fmtDateDE(blk.blockedAt) : '–'}</div>
            <div style={{ display: 'flex', gap: 8, marginTop: 10 }}>
              <Tag color={t.red || '#FF3B30'}>Gesperrt</Tag>
            </div>
          </div>
          <Button variant="soft" size="sm" onClick={unblock}>Sperre aufheben</Button>
        </div>

        {/* Kontakt */}
        <div style={{ marginTop: 22, background: t.card, borderRadius: 12, border: `0.5px solid ${t.sep}`, padding: '4px 16px' }}>
          <div style={{ fontSize: 10.5, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, padding: '12px 0 8px', borderBottom: `0.5px solid ${t.sep}` }}>Kontakt</div>
          {[
            { icon: icons.user, label: 'Telefon', value: blk.phone || '', mono: true },
            { icon: icons.mail, label: 'E-Mail',  value: blk.email || '' }
          ].map((row, i, arr) => (
            <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 0', borderBottom: i === arr.length - 1 ? 'none' : `0.5px solid ${t.sep}` }}>
              <div style={{ width: 22, height: 22, borderRadius: 6, background: t.chip, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                <Icon d={row.icon} color={t.textSec} size={12} sw={1.8} />
              </div>
              <div style={{ fontSize: 12, color: t.textSec, fontWeight: 500, width: 88, flexShrink: 0 }}>{row.label}</div>
              <div style={{ flex: 1, fontSize: 13.5, color: t.text, fontWeight: 600, textAlign: 'right', ...(row.mono ? NUMS : {}) }}>{row.value || <span style={{ color: t.textTer, fontWeight: 500 }}>–</span>}</div>
            </div>
          ))}
        </div>

        {/* Notiz / Grund */}
        <div style={{ marginTop: 18, background: t.card, borderRadius: 12, border: `0.5px solid ${t.sep}`, padding: 16 }}>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 8 }}>
            <div style={{ fontSize: 10.5, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5 }}>Notiz / Grund der Sperre</div>
            {!editing && (
              <Pressable onClick={() => setEditing(true)} scale={0.96}>
                <div style={{ fontSize: 11.5, fontWeight: 600, color: t.accent }}>Bearbeiten</div>
              </Pressable>
            )}
          </div>
          {editing ? (
            <>
              <textarea value={draft} onChange={(e) => setDraft(e.target.value)} rows={3} placeholder="Grund der Sperre eintragen …"
                style={{ width: '100%', boxSizing: 'border-box', padding: '10px 12px', borderRadius: 10, border: `0.5px solid ${t.inputBorder}`, background: t.inputBg, fontSize: 13.5, color: t.text, fontFamily: 'inherit', resize: 'vertical', outline: 'none' }} />
              <div style={{ marginTop: 10, display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
                <Pressable onClick={() => { setDraft(blk.reason || ''); setEditing(false); }} scale={0.96}>
                  <div style={{ padding: '7px 14px', borderRadius: 9, fontSize: 12.5, fontWeight: 600, color: t.textSec }}>Abbrechen</div>
                </Pressable>
                <Pressable onClick={save} scale={0.96}>
                  <div style={{ padding: '7px 14px', borderRadius: 9, fontSize: 12.5, fontWeight: 700, color: '#fff', background: t.accent }}>Speichern</div>
                </Pressable>
              </div>
            </>
          ) : (
            <div style={{ fontSize: 13.5, color: blk.reason ? t.text : t.textTer, lineHeight: 1.5, whiteSpace: 'pre-wrap', fontWeight: blk.reason ? 500 : 400 }}>
              {blk.reason || 'Kein Grund hinterlegt — auf „Bearbeiten" klicken, um eine Notiz zu ergänzen.'}
            </div>
          )}
        </div>

        {/* Verlauf */}
        <div style={{ marginTop: 18 }}>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 8 }}>
            <div style={{ fontSize: 13, fontWeight: 700, color: t.text, textTransform: 'uppercase', letterSpacing: 0.4 }}>Bisherige Mietvorgänge</div>
            <div style={{ fontSize: 11.5, color: t.textSec, fontWeight: 500 }}>{rentals.length} {rentals.length === 1 ? 'Vorgang' : 'Vorgänge'}</div>
          </div>
          {rentals.length === 0 ? (
            <div style={{ padding: '18px 16px', background: t.cardAlt, borderRadius: 12, border: `0.5px dashed ${t.sep}`, fontSize: 12.5, color: t.textSec, textAlign: 'center' }}>
              Keine Mietvorgänge mit diesem Kunden.
            </div>
          ) : (
            <div style={{ background: t.card, borderRadius: 12, border: `0.5px solid ${t.sep}`, overflow: 'hidden' }}>
              {rentals.map((r, i) => (
                <Pressable key={r.id} onClick={() => { setFilter('alle'); setSelId(r.id); }} scale={0.998} hoverBg={t.cardAlt}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '10px 12px', borderTop: i === 0 ? 'none' : `0.5px solid ${t.sep}` }}>
                    <StatusPill status={r.status} />
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 13, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{r.equipmentName}</div>
                      <div style={{ fontSize: 11, color: t.textSec, marginTop: 1, ...NUMS }}>{fmtRange(r.start, r.end)}</div>
                    </div>
                    <div style={{ fontSize: 13, fontWeight: 700, color: t.text, ...NUMS }}>{rentalTotal(r)} €</div>
                    <Icon d={icons.chev} color={t.textTer} size={13} sw={2} />
                  </div>
                </Pressable>
              ))}
            </div>
          )}
        </div>
      </div>
    </Scroll>
  );
}

// ── Detail pane ──
function RentalDetail({ rental, equipment, onEdit, onDelete, onPatch, go, docs = [], setDocs, blocked = [], rentals = [] }) {
  const t = useTheme();
  const toast = useToast();
  const [lightbox, setLightbox] = useState(null); // null | { src, label }
  const [confirmDelDoc, setConfirmDelDoc] = useState(null); // null | doc
  const r = rental;
  const items = getRentalItems(r, equipment);
  const eq = items[0] ? equipment.find((e) => e.id === items[0].equipmentId) : null;
  const dep = depositMeta(r.depositStatus);
  const days = daysBetween(r.start, r.end);
  const total = rentalTotal(r);
  const blockEntry = findBlockEntry(r.tenantName, r.phone, r.email, blocked);
  // Per-item: how many units are over-booked across other rentals in this date range.
  const conflictItems = items.map((it) => {
    const av = eqAvailabilityInRange(equipment, it.equipmentId, r.start, r.end, rentals, r.id);
    const qty = Math.max(1, Number(it.quantity) || 1);
    return { it, av, qty, over: av.exists ? Math.max(0, qty - av.available) : 0 };
  }).filter((x) => x.over > 0);
  const eqSummary = items.length === 0 ? r.equipmentName : items.length === 1 ?
  items[0].equipmentName + (items[0].quantity > 1 ? ' ×' + items[0].quantity : '') :
  items.length + ' Geräte';

  return (
    <Scroll padding={0}>
      <div style={{ padding: '26px 30px' }}>
        {/* header */}
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 16 }}>
          <Avatar name={r.tenantName} size={56} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 24, fontWeight: 700, color: t.text, letterSpacing: -0.5 }}>{r.tenantName}</div>
            <div style={{ fontSize: 13.5, color: t.textSec, marginTop: 3 }}>{r.purpose || 'Mietvorgang'} · {eqSummary}</div>
            <div style={{ display: 'flex', gap: 8, marginTop: 10 }}>
              <StatusPill status={r.status} />
            </div>
          </div>
          <div style={{ display: 'flex', gap: 8 }}>
            <Button variant="soft" size="sm" icon={icons.edit} onClick={onEdit}>Bearbeiten</Button>
            <IconBtn icon={icons.trash} color={t.red} onClick={onDelete} title="Löschen" />
          </div>
        </div>

        {blockEntry && (
          <div style={{ marginTop: 18, padding: '12px 14px', borderRadius: 11, background: (t.red || '#FF3B30') + '15', border: `1px solid ${(t.red || '#FF3B30')}40`, display: 'flex', gap: 11, alignItems: 'flex-start' }}>
            <div style={{ width: 28, height: 28, borderRadius: 14, background: t.red || '#FF3B30', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, color: '#fff', fontWeight: 800, fontSize: 14 }}>!</div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 13.5, fontWeight: 700, color: t.red || '#FF3B30' }}>Kunde ist gesperrt</div>
              <div style={{ fontSize: 12, color: t.text, marginTop: 3, lineHeight: 1.45 }}>
                {blockEntry.reason ? <><b>Grund:</b> {blockEntry.reason}</> : 'Kein Grund hinterlegt.'}
                {blockEntry.blockedAt && <span style={{ color: t.textSec, marginLeft: 6, ...NUMS }}>· seit {fmtDateDE(blockEntry.blockedAt)}</span>}
              </div>
            </div>
          </div>
        )}

        {conflictItems.length > 0 && (
          <ConflictsAlert
            conflicts={conflictItems}
            equipment={equipment}
            rentals={rentals}
            range={{ start: r.start, end: r.end, excludeId: r.id }}
            onOpenRental={(id) => go && go('rentals', { rentalId: id })}
            onAction={onEdit}
            actionLabel="Anpassen" />
        )}

        {/* totals row */}
        <div style={{ marginTop: 22, display: 'flex', alignItems: 'stretch', gap: 0, borderTop: `0.5px solid ${t.sep}`, borderBottom: `0.5px solid ${t.sep}`, padding: '14px 2px' }}>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 10.5, color: t.textSec, fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0.6 }}>Mietsumme</div>
            <div style={{ fontSize: 26, fontWeight: 600, color: t.text, letterSpacing: -0.6, marginTop: 4, ...NUMS }}>{total} €</div>
            <div style={{ fontSize: 11.5, color: t.textSec, marginTop: 2 }}>{days} Tag{days > 1 ? 'e' : ''} · {items.length} {items.length === 1 ? 'Position' : 'Positionen'}</div>
          </div>
          <div style={{ width: 1, background: t.sep, margin: '2px 20px' }} />
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 10.5, color: t.textSec, fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0.6 }}>Kaution</div>
            <div style={{ fontSize: 26, fontWeight: 600, color: t.text, letterSpacing: -0.6, marginTop: 4, ...NUMS }}>{r.deposit} €</div>
            <div style={{ fontSize: 11.5, color: t.textSec, marginTop: 2, display: 'inline-flex', alignItems: 'center', gap: 5 }}><span style={{ width: 6, height: 6, borderRadius: 3, background: dep.color }} />{dep.label}</div>
          </div>
        </div>

        {(() => {
          const InfoCard = ({ title, rows }) => (
            <div style={{ background: t.card, borderRadius: 12, border: `0.5px solid ${t.sep}`, padding: '4px 16px' }}>
              {title && <div style={{ fontSize: 10.5, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, padding: '12px 0 8px', borderBottom: `0.5px solid ${t.sep}` }}>{title}</div>}
              {rows.filter(Boolean).map((row, i, arr) => (
                <div key={i} style={{ display: 'flex', alignItems: row.multiline ? 'flex-start' : 'center', gap: 12, padding: '10px 0', borderBottom: i === arr.length - 1 ? 'none' : `0.5px solid ${t.sep}` }}>
                  <div style={{ width: 22, height: 22, borderRadius: 6, background: t.chip, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, marginTop: row.multiline ? 1 : 0 }}>
                    <Icon d={row.icon} color={t.textSec} size={12} sw={1.8}/>
                  </div>
                  <div style={{ fontSize: 12, color: t.textSec, fontWeight: 500, width: 110, flexShrink: 0 }}>{row.label}</div>
                  <div style={{ flex: 1, minWidth: 0, fontSize: 13.5, color: t.text, fontWeight: 600, textAlign: 'right', whiteSpace: row.multiline ? 'pre-line' : 'nowrap', overflow: row.multiline ? 'visible' : 'hidden', textOverflow: row.multiline ? 'clip' : 'ellipsis', lineHeight: row.multiline ? 1.45 : 1.3, ...(row.mono ? NUMS : {}) }}>{row.value || <span style={{ color: t.textTer, fontWeight: 500 }}>–</span>}</div>
                </div>
              ))}
            </div>
          );
          const TimePill = ({ time }) => (
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, marginLeft: 8, padding: '2px 7px', borderRadius: 6, background: t.chip, fontSize: 11.5, fontWeight: 600, color: t.text, ...NUMS }}>
              <Icon d={icons.clock} color={t.textSec} size={10} sw={2}/>{time}
            </span>
          );
          const equipmentSum = items.reduce((s, it) => s + (Number(it.quantity) || 1) * (Number(it.dailyRate) || 0) * days, 0);
          const d = r.delivery || {};
          const deliveryEnabled = !!d.enabled;
          const dCalc = deliveryEnabled ? calcDelivery(d.km, d.tripFactor || LOGISTIK_DEFAULTS.tripFactor) : null;
          const tripOpt = TRIP_OPTIONS.find((x) => x.f === (d.tripFactor || LOGISTIK_DEFAULTS.tripFactor)) || TRIP_OPTIONS[1];

          // Payment / deposit row data (used in Zahlungsstatus card)
          const pm = r.paymentStatus === 'bezahlt' ?
            { color: t.green, label: 'Bezahlt', next: 'offen', nextLabel: 'als offen markieren' } :
            { color: t.orange, label: 'Offen', next: 'bezahlt', nextLabel: 'als bezahlt markieren' };
          const dm = depositMeta(r.depositStatus || 'offen');
          const depCycle = { offen: 'erhalten', erhalten: 'zurueckgezahlt', zurueckgezahlt: 'offen' };
          const nextDep = depCycle[r.depositStatus || 'offen'] || 'offen';
          const nextDepLabel = depositMeta(nextDep).label;
          const PayRow = ({ icon, label, color, value, sub, onClick, last }) => (
            <Pressable onClick={onClick} scale={0.998} hoverBg={t.cardAlt}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 16px', borderBottom: last ? 'none' : `0.5px solid ${t.sep}` }}>
                <div style={{ width: 26, height: 26, borderRadius: 7, background: color + '22', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                  <Icon d={icon} color={color} size={14} sw={1.8} />
                </div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: t.text }}>{label}</div>
                  <div style={{ fontSize: 11, color: t.textSec, marginTop: 1 }}>{sub}</div>
                </div>
                <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '5px 11px', borderRadius: 100, background: color + '20' }}>
                  <span style={{ width: 7, height: 7, borderRadius: 4, background: color }} />
                  <span style={{ fontSize: 12, fontWeight: 700, color: color }}>{value}</span>
                </div>
                <Icon d={icons.chev} color={t.textTer} size={12} sw={2} />
              </div>
            </Pressable>
          );

          return (
            <>
              {/* ── 1. Mieter ── */}
              <div style={{ marginTop: 22 }}>
                <InfoCard title="Mieter" rows={[
                  { icon: icons.user, label: 'Name',    value: r.tenantName || '' },
                  { icon: icons.pin,  label: 'Adresse', value: r.address || '', multiline: true },
                  { icon: icons.mail, label: 'E-Mail',  value: r.email || '' },
                  { icon: icons.user, label: 'Telefon', value: r.phone || '', mono: true },
                ]}/>
              </div>

              {/* ── 2. Personalausweis ── */}
              <div style={{ marginTop: 22 }}>
                <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 8 }}>
                  <div style={{ fontSize: 13, fontWeight: 700, color: t.text, textTransform: 'uppercase', letterSpacing: 0.4 }}>Personalausweis</div>
                  {r.idCard && r.idCard !== '–' && <div style={{ fontSize: 11.5, color: t.textSec, fontWeight: 500, ...NUMS }}>Nr. {r.idCard}</div>}
                </div>
                <div style={{ display: 'flex', gap: 14 }}>
                  {[{ src: r.idFront, label: 'Vorderseite' }, { src: r.idBack, label: 'Rückseite' }].map((p) => (
                    <div key={p.label} style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 11, color: t.textSec, fontWeight: 600, marginBottom: 6 }}>{p.label}</div>
                      {p.src ? (
                        <Pressable onClick={() => setLightbox(p)} scale={0.99}>
                          <div style={{ aspectRatio: '1.586 / 1', borderRadius: 12, overflow: 'hidden', border: `0.5px solid ${t.sep}`, background: t.cardAlt }}>
                            <img src={p.src} alt={p.label} style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                          </div>
                        </Pressable>
                      ) : (
                        <div style={{ aspectRatio: '1.586 / 1', borderRadius: 12, border: `1.5px dashed ${t.sep}`, background: t.cardAlt, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 11.5, color: t.textTer, fontWeight: 500 }}>Nicht hinterlegt</div>
                      )}
                    </div>
                  ))}
                </div>
              </div>

              {/* ── 3. Mietdaten ── */}
              <div style={{ marginTop: 22 }}>
                <InfoCard title="Mietdaten" rows={[
                  { icon: icons.bolt,  label: 'Verwendung',  value: r.purpose || '' },
                  { icon: icons.cal,   label: 'Zeitraum',    value: fmtRange(r.start, r.end) },
                  { icon: icons.arrow, label: 'Abholung',    value: <span style={{ ...NUMS }}>{fmtDateDE(r.start)}{r.startTime && <TimePill time={r.startTime}/>}</span> },
                  { icon: icons.back,  label: 'Rückgabe',    value: <span style={{ ...NUMS }}>{fmtDateDE(r.end)}{r.endTime && <TimePill time={r.endTime}/>}</span> },
                  { icon: icons.euro,  label: 'Kaution €',   value: <span style={{ ...NUMS }}>{r.deposit} €</span>, mono: true },
                ]}/>
              </div>

              {/* ── 4. Equipment ── */}
              {items.length > 0 && (
                <div style={{ marginTop: 22 }}>
                  <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 8 }}>
                    <div style={{ fontSize: 13, fontWeight: 700, color: t.text, textTransform: 'uppercase', letterSpacing: 0.4 }}>Equipment</div>
                    <div style={{ fontSize: 11.5, color: t.textSec, fontWeight: 500 }}>{items.length} {items.length === 1 ? 'Position' : 'Positionen'}</div>
                  </div>
                  <div style={{ background: t.card, borderRadius: 10, border: `0.5px solid ${t.sep}`, overflow: 'hidden' }}>
                    {items.map((it, idx) => {
                      const e = equipment.find((x) => x.id === it.equipmentId);
                      const qty = Number(it.quantity) || 1;
                      const rate = Number(it.dailyRate) || 0;
                      const lineTotal = qty * rate * days;
                      return (
                        <Pressable key={idx} onClick={() => e && go('equipment', { equipmentId: e.id })} scale={0.998} hoverBg={t.cardAlt}>
                          <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 12px', borderTop: idx === 0 ? 'none' : `0.5px solid ${t.sep}` }}>
                            <EqAvatar item={e || {}} size={28} radius={6} />
                            <div style={{ flex: 1, minWidth: 0 }}>
                              <div style={{ fontSize: 13, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{e && e.name || it.equipmentName}</div>
                              {e && e.cat && <div style={{ fontSize: 11, color: t.textSec, marginTop: 1 }}>{e.cat}</div>}
                            </div>
                            <div style={{ fontSize: 11.5, color: t.textSec, fontWeight: 500, width: 110, textAlign: 'right', ...NUMS }}>{qty} × {rate} €/Tag</div>
                            <div style={{ fontSize: 13, fontWeight: 600, color: t.text, width: 70, textAlign: 'right', ...NUMS }}>{lineTotal} €</div>
                            {e ? <Icon d={icons.chev} color={t.textTer} size={13} sw={2} /> : <div style={{ width: 13 }} />}
                          </div>
                        </Pressable>);
                    })}
                    <div style={{ display: 'flex', alignItems: 'center', padding: '8px 12px', borderTop: `0.5px solid ${t.sep}`, background: t.cardAlt }}>
                      <div style={{ flex: 1, fontSize: 11.5, color: t.textSec, fontWeight: 500 }}>Equipment-Summe · {days} Tag{days > 1 ? 'e' : ''}</div>
                      <div style={{ fontSize: 13, fontWeight: 700, color: t.text, ...NUMS }}>{equipmentSum} €</div>
                      <div style={{ width: 13, marginLeft: 10 }} />
                    </div>
                  </div>
                </div>
              )}

              {/* ── 5. Zahlungsstatus ── */}
              <div style={{ marginTop: 22 }}>
                <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 8 }}>
                  <div style={{ fontSize: 13, fontWeight: 700, color: t.text, textTransform: 'uppercase', letterSpacing: 0.4 }}>Zahlungsstatus</div>
                  <div style={{ fontSize: 11, color: t.textTer, fontWeight: 500 }}>klicken zum Ändern</div>
                </div>
                <div style={{ background: t.card, borderRadius: 12, border: `0.5px solid ${t.sep}`, overflow: 'hidden' }}>
                  <PayRow
                    icon={icons.euro}
                    label="Mietbetrag"
                    color={pm.color}
                    value={pm.label}
                    sub={pm.nextLabel}
                    onClick={() => { onPatch({ paymentStatus: pm.next }); toast(pm.next === 'bezahlt' ? 'Mietbetrag als bezahlt markiert' : 'Mietbetrag wieder offen'); }}
                  />
                  <PayRow
                    icon={icons.shield || icons.check}
                    label="Kaution"
                    color={dm.color}
                    value={dm.label}
                    sub={`→ ${nextDepLabel}`}
                    onClick={() => { onPatch({ depositStatus: nextDep }); toast(`Kaution: ${nextDepLabel}`); }}
                    last
                  />
                </div>
              </div>

              {/* ── 6. Lieferung ── */}
              <div style={{ marginTop: 22 }}>
                <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 8 }}>
                  <div style={{ fontSize: 13, fontWeight: 700, color: t.text, textTransform: 'uppercase', letterSpacing: 0.4 }}>Lieferung</div>
                  <Pressable onClick={() => { onPatch({ delivery: { ...d, enabled: !deliveryEnabled } }); toast(!deliveryEnabled ? 'Lieferung aktiviert' : 'Auf Selbstabholung umgestellt'); }} scale={0.96}>
                    <div style={{ fontSize: 11.5, fontWeight: 600, color: t.accent }}>{deliveryEnabled ? 'Selbstabholung' : 'Lieferung hinzufügen'}</div>
                  </Pressable>
                </div>
                {deliveryEnabled ? (
                  <InfoCard title={null} rows={[
                    { icon: icons.pin,   label: 'Lieferadresse', value: d.address || r.address || '', multiline: true },
                    { icon: icons.arrow, label: 'Entfernung',    value: <span style={{ ...NUMS }}>{d.km || 0} km · {tripOpt.label} {tripOpt.sub}</span> },
                    { icon: icons.euro,  label: 'Pauschale',     value: <span style={{ ...NUMS }}>{dCalc.pauschale} €</span> },
                    { icon: icons.euro,  label: 'km-Kosten',     value: <span style={{ ...NUMS }}>{dCalc.totalKm} km · {dCalc.kmCost.toFixed(2)} €</span> },
                    { icon: icons.euro,  label: 'Liefergebühr',  value: <span style={{ ...NUMS, fontWeight: 700 }}>{dCalc.total.toFixed(2)} €</span> },
                  ].filter(Boolean)}/>
                ) : (
                  <div style={{ padding: '14px 16px', background: t.cardAlt, borderRadius: 12, border: `0.5px solid ${t.sep}`, display: 'flex', alignItems: 'center', gap: 11 }}>
                    <Icon d={icons.pin} color={t.textSec} size={14} sw={1.8}/>
                    <div style={{ fontSize: 13, color: t.text, fontWeight: 500 }}>Selbstabholung im Lager</div>
                    <div style={{ flex: 1 }}/>
                    <div style={{ fontSize: 11.5, color: t.textSec }}>{LOGISTIK_DEFAULTS.lagerAddress}</div>
                  </div>
                )}
              </div>
            </>
          );
        })()}

        {/* ── Dokumente (linked to this rental) ── */}
        {(() => {
          const rentalDocs = (docs || []).filter((d) => d.rentalId === r.id).sort((a, b) => (b.createdISO || '').localeCompare(a.createdISO || ''));
          const kindMeta = (k) => (typeof docKindMeta === 'function' ? docKindMeta(k) : { label: k, icon: 'fileText', color: t.text });
          return (
            <div style={{ marginTop: 24 }}>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 8 }}>
                <div style={{ fontSize: 13, fontWeight: 700, color: t.text, textTransform: 'uppercase', letterSpacing: 0.4 }}>Dokumente</div>
                <div style={{ display: 'flex', gap: 8 }}>
                  <Pressable onClick={() => go('documents', { rentalId: r.id, docsTab: 'schnelltexte' })} scale={0.96}>
                    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '5px 10px', borderRadius: 8, background: t.chip, fontSize: 11.5, fontWeight: 600, color: t.text }}>
                      <Icon d={icons.mail} color={t.text} size={11} sw={2}/>Schnelltext
                    </div>
                  </Pressable>
                  <Pressable onClick={() => go('documents', { rentalId: r.id, docsTab: 'vorlagen' })} scale={0.96}>
                    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '5px 10px', borderRadius: 8, background: t.accent, fontSize: 11.5, fontWeight: 600, color: '#fff' }}>
                      <Icon d={icons.plus} color="#fff" size={11} sw={2.4}/>Neu erstellen
                    </div>
                  </Pressable>
                </div>
              </div>
              {rentalDocs.length === 0 ? (
                <div style={{ padding: '18px 16px', background: t.cardAlt, borderRadius: 12, border: `0.5px dashed ${t.sep}`, fontSize: 12.5, color: t.textSec, textAlign: 'center' }}>
                  Noch keine Dokumente · Vertrag, Rechnung oder Schnelltext oben erstellen.
                </div>
              ) : (
                <div style={{ background: t.card, borderRadius: 12, border: `0.5px solid ${t.sep}`, overflow: 'hidden' }}>
                  {rentalDocs.map((d, i) => {
                    const km = kindMeta(d.kind);
                    return (
                      <Pressable key={d.id} onClick={() => go('documents', { docsTab: 'archiv', docId: d.id })} scale={0.998} hoverBg={t.cardAlt}>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '9px 12px', borderTop: i === 0 ? 'none' : `0.5px solid ${t.sep}` }}>
                          <div style={{ width: 32, height: 40, borderRadius: 6, background: km.color + '1e', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                            <Icon d={icons[km.icon] || icons.fileText} color={km.color} size={15} sw={1.7}/>
                            <div style={{ fontSize: 7.5, color: km.color, fontWeight: 800, marginTop: 1, letterSpacing: 0.3 }}>{d.format === 'text' ? 'TXT' : 'PDF'}</div>
                          </div>
                          <div style={{ flex: 1, minWidth: 0 }}>
                            <div style={{ fontSize: 13, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{d.title}</div>
                            <div style={{ fontSize: 11, color: t.textSec, marginTop: 1 }}>{km.label}{d.createdISO ? ' · ' + fmtDateDE(d.createdISO) : ''}</div>
                          </div>
                          <div
                            role="button"
                            title="Dokument löschen"
                            onClick={(e) => { e.stopPropagation(); setConfirmDelDoc(d); }}
                            style={{ width: 28, height: 28, borderRadius: 7, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' }}
                            onMouseEnter={(e) => { e.currentTarget.style.background = (t.red || '#FF3B30') + '18'; }}
                            onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; }}
                          >
                            <Icon d={icons.trash} color={t.red || '#FF3B30'} size={13} sw={1.8}/>
                          </div>
                          <Icon d={icons.chev} color={t.textTer} size={13} sw={2}/>
                        </div>
                      </Pressable>
                    );
                  })}
                </div>
              )}
            </div>
          );
        })()}
      </div>

      {lightbox && (
        <div onClick={() => setLightbox(null)} style={{ position: 'fixed', inset: 0, zIndex: 200, background: 'rgba(0,0,0,0.82)', backdropFilter: 'blur(8px)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 16, padding: 40, cursor: 'zoom-out' }}>
          <div style={{ fontSize: 13, fontWeight: 600, color: 'rgba(255,255,255,0.85)' }}>{r.tenantName} · {lightbox.label}</div>
          <img src={lightbox.src} alt={lightbox.label} onClick={(e) => e.stopPropagation()} style={{ maxWidth: 'min(900px, 90vw)', maxHeight: '78vh', borderRadius: 14, boxShadow: '0 24px 80px rgba(0,0,0,0.6)', cursor: 'default' }} />
          <div style={{ fontSize: 12, color: 'rgba(255,255,255,0.55)' }}>Klicken zum Schließen</div>
        </div>
      )}

      <Confirm
        open={!!confirmDelDoc}
        title="Dokument löschen?"
        message={confirmDelDoc ? `„${confirmDelDoc.title}“ wird unwiderruflich aus dem Archiv entfernt.` : ''}
        onConfirm={() => {
          if (!confirmDelDoc) return;
          const id = confirmDelDoc.id;
          setDocs((prev) => (prev || []).filter((x) => x.id !== id));
          toast('Dokument gelöscht');
          setConfirmDelDoc(null);
        }}
        onClose={() => setConfirmDelDoc(null)}
      />
    </Scroll>);

}

// ── Screen: master-detail ──
function ScreenRentals({ go, nav, equipment, rentals, setRentals, docs, setDocs, company, blocked = [], setBlocked }) {
  const t = useTheme();
  const toast = useToast();
  const [filter, setFilter] = useState('alle');
  const [query, setQuery] = useState('');
  const [selId, setSelId] = useState(rentals[0] ? rentals[0].id : null);
  const [sheet, setSheet] = useState(null); // null | {} (new) | rental (edit)
  const [confirmDel, setConfirmDel] = useState(null);
  const [analyseOpen, setAnalyseOpen] = useState(false);

  // react to nav params
  useEffect(() => {
    if (nav && nav.rentalId) {setSelId(nav.rentalId);}
    if (nav && nav.newRental) {setSheet({});}
  }, [nav]);

  const counts = {
    alle: rentals.length,
    aktiv: rentals.filter((r) => r.status === 'aktiv').length,
    reserviert: rentals.filter((r) => r.status === 'reserviert').length,
    abgeschlossen: rentals.filter((r) => r.status === 'abgeschlossen').length
  };
  const filtered = rentals.
  filter((r) => filter === 'alle' || r.status === filter).
  filter((r) => !query || (r.tenantName + ' ' + r.equipmentName + ' ' + (r.purpose || '')).toLowerCase().includes(query.toLowerCase())).
  sort((a, b) => b.start.localeCompare(a.start));

  const selected = rentals.find((r) => r.id === selId);

  const saveRental = (r) => {
    setRentals((prev) => {const exists = prev.find((x) => x.id === r.id);return exists ? prev.map((x) => x.id === r.id ? r : x) : [r, ...prev];});
    setSelId(r.id);
    toast(rentals.find((x) => x.id === r.id) ? 'Gespeichert' : 'Mietvorgang angelegt');
  };
  const patchRental = (patch) => setRentals((prev) => prev.map((x) => x.id === selId ? { ...x, ...patch } : x));
  const del = (r) => {setRentals((prev) => prev.filter((x) => x.id !== r.id));if (selId === r.id) setSelId(null);toast('Gelöscht');};

  return (
    <>
      <Toolbar title="Mietaufträge" subtitle={`${rentals.length} Verträge`}>
        <SearchField value={query} onChange={setQuery} placeholder="Mieter, Equipment…" />
        <Button variant="soft" size="sm" icon={icons.chart || icons.bolt} onClick={() => setAnalyseOpen(true)}>Analyse</Button>
        <Button variant="primary" icon={icons.plus} onClick={() => setSheet({})}>Neu</Button>
      </Toolbar>
      <div style={{ flex: 1, display: 'flex', minHeight: 0 }}>
        {/* master list */}
        <div style={{ width: 360, flexShrink: 0, borderRight: `0.5px solid ${t.sep}`, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
          <div style={{ padding: '12px 16px', borderBottom: `0.5px solid ${t.sep}` }}>
            <Segmented size="sm" value={filter} onChange={setFilter} style={{ display: 'flex', width: '100%' }}
            options={[['alle', 'Alle'], ['aktiv', 'Aktiv'], ['reserviert', 'Reserv.'], ['abgeschlossen', 'Fertig'], ['gesperrt', 'Gesperrt']]} />
          </div>
          <div className="rf-scroll" style={{ flex: 1, overflow: 'auto', padding: 8 }}>
            {filter === 'gesperrt' ? (
              blocked.length === 0 ? (
                <div style={{ padding: '40px 20px', textAlign: 'center', color: t.textSec, fontSize: 13 }}>
                  Keine gesperrten Kunden.
                  <div style={{ marginTop: 6, fontSize: 11.5, color: t.textTer }}>Im Bearbeiten-Dialog eines Mietvorgangs kannst du Kunden sperren.</div>
                </div>
              ) : (
                blocked.slice().sort((a, b) => (b.blockedAt || '').localeCompare(a.blockedAt || '')).map((b) => {
                  const rentalCount = rentals.filter((r) => _normKey(r.tenantName) === _normKey(b.name)).length;
                  const sel = selId === 'blk-' + b.id;
                  return (
                    <Pressable key={b.id} onClick={() => setSelId('blk-' + b.id)} scale={0.995} hoverBg={sel ? undefined : t.cardAlt} style={{ borderRadius: 11, marginBottom: 2 }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '11px 12px', borderRadius: 11, background: sel ? t.chip : 'transparent', border: sel ? `1px solid ${t.sep}` : '1px solid transparent' }}>
                        <div style={{ width: 42, height: 42, borderRadius: 10, background: (t.red || '#FF3B30') + '22', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                          <Icon d="M12 2L3 7v6c0 5 3.5 8.5 9 10 5.5-1.5 9-5 9-10V7l-9-5z" color={t.red || '#FF3B30'} size={18} sw={1.8} />
                        </div>
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ fontSize: 14, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{b.name}</div>
                          <div style={{ fontSize: 11.5, color: t.textSec, marginTop: 1, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{b.reason || 'Kein Grund hinterlegt'}</div>
                          <div style={{ fontSize: 11, color: t.textTer, marginTop: 4, ...NUMS }}>seit {b.blockedAt ? fmtDateDE(b.blockedAt) : '–'} · {rentalCount} Vorgang{rentalCount === 1 ? '' : 'e'}</div>
                        </div>
                      </div>
                    </Pressable>
                  );
                })
              )
            ) : (
              <>
                {filtered.length === 0 && <div style={{ padding: '40px 20px', textAlign: 'center', color: t.textSec, fontSize: 13 }}>Keine Treffer.</div>}
                {filtered.map((r) => {
                  const eq = equipment.find((e) => e.id === r.equipmentId);
                  const sel = r.id === selId;
                  const rBlocked = !!findBlockEntry(r.tenantName, r.phone, r.email, blocked);
                  const rItems = getRentalItems(r, equipment);
                  const rConflict = r.status !== 'abgeschlossen' && rItems.some((it) => {
                    const av = eqAvailabilityInRange(equipment, it.equipmentId, r.start, r.end, rentals, r.id);
                    return av.exists && (Math.max(1, Number(it.quantity) || 1) > av.available);
                  });
                  return (
                    <Pressable key={r.id} onClick={() => setSelId(r.id)} scale={0.995} hoverBg={sel ? undefined : t.cardAlt} style={{ borderRadius: 11, marginBottom: 2 }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '11px 12px', borderRadius: 11, background: sel ? t.chip : 'transparent', border: sel ? `1px solid ${t.sep}` : '1px solid transparent' }}>
                        <EqAvatar item={eq || {}} size={42} radius={10} />
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ fontSize: 14, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', display: 'flex', alignItems: 'center', gap: 6 }}>
                            {rBlocked && <span title="Kunde gesperrt" style={{ width: 7, height: 7, borderRadius: 4, background: t.red || '#FF3B30', flexShrink: 0 }} />}
                            {rConflict && <span title="Belegungs-Konflikt" style={{ width: 7, height: 7, borderRadius: 4, background: t.orange || '#FF9500', flexShrink: 0 }} />}
                            <span style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>{r.tenantName}</span>
                          </div>
                          <div style={{ fontSize: 11.5, color: t.textSec, marginTop: 1, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{eq ? eq.name : r.equipmentName}</div>
                          <div style={{ fontSize: 11, color: t.textSec, marginTop: 4, ...NUMS }}>{fmtRange(r.start, r.end)}</div>
                        </div>
                        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 6, flexShrink: 0 }}>
                          <StatusPill status={r.status} />
                          <div style={{ fontSize: 13, fontWeight: 700, color: t.text, ...NUMS }}>{rentalTotal(r)} €</div>
                        </div>
                      </div>
                    </Pressable>);

                })}
              </>
            )}
          </div>
        </div>
        {/* detail */}
        <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column' }}>
          {filter === 'gesperrt' && selId && String(selId).startsWith('blk-') ? (() => {
            const blk = blocked.find((b) => 'blk-' + b.id === selId);
            if (!blk) return <Empty icon={icons.doc} title="Kunde nicht gefunden" sub="Wähle links einen Eintrag." />;
            const custRentals = rentals.filter((r) => _normKey(r.tenantName) === _normKey(blk.name)).sort((a, b) => b.start.localeCompare(a.start));
            return <BlockedCustomerDetail blk={blk} rentals={custRentals} blocked={blocked} setBlocked={setBlocked} toast={toast} setSelId={setSelId} setFilter={setFilter} go={go} />;
          })() : selected ?
          <RentalDetail rental={selected} equipment={equipment} go={go} docs={docs} setDocs={setDocs} blocked={blocked} rentals={rentals}
          onEdit={() => setSheet(selected)} onDelete={() => setConfirmDel(selected)} onPatch={patchRental} /> :

          <Empty icon={icons.doc} title="Kein Mietvorgang gewählt" sub="Wähle links einen Eintrag oder lege einen neuen Mietvorgang an." action="Neuer Mietvorgang" onAction={() => setSheet({})} />
          }
        </div>
      </div>

      <RentalSheet open={sheet !== null} initial={sheet && sheet.id ? sheet : null} equipment={equipment} onClose={() => setSheet(null)} onSave={saveRental} blocked={blocked} setBlocked={setBlocked} rentals={rentals} />
      <RentalsAnalyseSheet open={analyseOpen} onClose={() => setAnalyseOpen(false)} rentals={rentals} equipment={equipment} go={go} />
      <Confirm open={!!confirmDel} title="Mietvorgang löschen?" message={confirmDel ? `„${confirmDel.tenantName}" wird unwiderruflich entfernt.` : ''} onConfirm={() => del(confirmDel)} onClose={() => setConfirmDel(null)} />
    </>);

}

Object.assign(window, { ScreenRentals, RentalSheet, RentalDetail });