// Desktop Kalender — month grid w/ spanning multi-day bars + Plan (Belegungs-
// plan: equipment × week timeline) + side-panel day timeline mirroring mobile.

const mondayOfISO = (iso) => {
  const d = fromISO(iso);
  const dow = (d.getDay() + 6) % 7; // 0 = Mon
  d.setDate(d.getDate() - dow);
  return fmtDateISO(d);
};
const shiftISO = (iso, days) => {const d = fromISO(iso);d.setDate(d.getDate() + days);return fmtDateISO(d);};
const parseTime = (s) => {if (!s || !/^\d{1,2}:\d{2}$/.test(s)) return null;const [h, m] = s.split(':').map(Number);return h + m / 60;};
const fmtHr = (hr) => {const h = Math.floor(hr),m = Math.round((hr - h) * 60);return String(h).padStart(2, '0') + ':' + (m === 60 ? '00' : String(m).padStart(2, '0'));};

// Tint any CSS color (#rgb, #rrggbb, rgb(), rgba()) to rgba with the given alpha.
// Hex-suffix concat (`color + '1a'`) breaks if color isn't a 6-char hex — this is safe.
function tintColor(c, a) {
  if (!c) return `rgba(120,120,128,${a})`;
  if (c[0] === '#') {
    let h = c.slice(1);
    if (h.length === 3) h = h.split('').map((x) => x + x).join('');
    if (h.length === 6) {
      const r = parseInt(h.slice(0, 2), 16);
      const g = parseInt(h.slice(2, 4), 16);
      const b = parseInt(h.slice(4, 6), 16);
      return `rgba(${r},${g},${b},${a})`;
    }
  }
  const m = c.match(/rgba?\(\s*(\d+)[ ,]+(\d+)[ ,]+(\d+)/i);
  if (m) return `rgba(${m[1]},${m[2]},${m[3]},${a})`;
  return c; // unknown format — return as-is
}

// Lane-pack a set of {start,end} intervals so they don't overlap in a row.
function assignLanes(items) {
  const sorted = [...items].sort((a, b) => a.start.localeCompare(b.start) || a.end.localeCompare(b.end));
  const laneEnds = []; // last 'end' of each lane (exclusive: a new item must start AFTER this)
  sorted.forEach((it) => {
    let lane = laneEnds.findIndex((end) => it.start > end);
    if (lane === -1) {lane = laneEnds.length;laneEnds.push(it.end);} else
    laneEnds[lane] = it.end;
    it.lane = lane;
  });
  return { sorted, laneCount: Math.max(1, laneEnds.length) };
}

function ScreenCalendar({ go, equipment, rentals, setRentals, events, setEvents }) {
  const t = useTheme();
  const toast = useToast();
  const today = todayISO();
  const [mode, setMode] = useState('month'); // 'month' | 'plan'
  const [labelMode, setLabelMode] = useLocal('rf-d-cal-labelmode', 'name'); // 'name' | 'equipment' (month view bar text)
  const [cursor, setCursor] = useState(() => {const d = fromISO(today);return { y: d.getFullYear(), m: d.getMonth() };});
  const [weekStart, setWeekStart] = useState(() => mondayOfISO(today));
  const [selDay, setSelDay] = useState(today);
  const [evtSheet, setEvtSheet] = useState(null);
  const [peek, setPeek] = useState(null); // { kind, ref }

  const allBars = [
  ...rentals.map((r) => {
    // Equipment label for the alternative month-view bar text
    const eq = equipment.find((e) => e.id === r.equipmentId);
    const items = Array.isArray(r.items) && r.items.length ? r.items : null;
    const eqName = items ?
    (items[0].equipmentName || eq && eq.name || r.equipmentName) + (items.length > 1 ? ' +' + (items.length - 1) : '') :
    eq && eq.name || r.equipmentName || '';
    const eqTimes = (r.startTime ? '\u2191' + r.startTime : '') + (r.startTime && r.endTime ? ' ' : '') + (r.endTime ? '\u2193' + r.endTime : '');
    return { kind: 'rental', id: r.id, title: r.tenantName, eqName, eqTimes, start: r.start, end: r.end, startTime: r.startTime, endTime: r.endTime, color: r.color || statusMeta(r.status).color, equipmentId: r.equipmentId, ref: r };
  }),
  ...events.map((e) => ({ kind: 'event', id: e.id, title: e.title, eqName: e.title, eqTimes: '', start: e.start, end: e.end, startTime: e.startTime, endTime: e.endTime, color: e.color, equipmentId: e.equipmentId, ref: e }))];


  const move = (d) => {
    if (mode === 'month') setCursor((c) => {let m = c.m + d,y = c.y;if (m < 0) {m = 11;y--;}if (m > 11) {m = 0;y++;}return { y, m };});else
    setWeekStart((w) => shiftISO(w, d * 7));
  };
  const goToday = () => {
    const d = fromISO(today);setCursor({ y: d.getFullYear(), m: d.getMonth() });
    setWeekStart(mondayOfISO(today));setSelDay(today);
  };

  const saveEvent = (ev) => {setEvents((prev) => {const ex = prev.find((x) => x.id === ev.id);return ex ? prev.map((x) => x.id === ev.id ? ev : x) : [...prev, ev];});toast('Termin gespeichert');};
  const delEvent = (id) => {setEvents((prev) => prev.filter((x) => x.id !== id));toast('Termin gelöscht');};

  const openPeek = (bar) => setPeek({ kind: bar.kind, ref: bar.ref });
  const setEntryColor = (color) => {
    if (!peek) return;
    if (peek.kind === 'rental') {
      setRentals && setRentals((prev) => prev.map((x) => x.id === peek.ref.id ? { ...x, color } : x));
      setPeek((p) => p && { ...p, ref: { ...p.ref, color } });
    } else {
      setEvents((prev) => prev.map((x) => x.id === peek.ref.id ? { ...x, color } : x));
      setPeek((p) => p && { ...p, ref: { ...p.ref, color } });
    }
  };
  const editFromPeek = () => {
    if (!peek) return;
    if (peek.kind === 'rental') {const id = peek.ref.id;setPeek(null);go('rentals', { rentalId: id });} else
    {const ev = peek.ref;setPeek(null);setEvtSheet(ev);}
  };

  const subtitle = mode === 'month' ?
  `${DE_MONTHS[cursor.m]} ${cursor.y}` :
  `${fmtDateDE(weekStart)} – ${fmtDateDE(shiftISO(weekStart, 6))}`;

  return (
    <>
      <Toolbar title="Kalender" subtitle={subtitle}>
        <Segmented size="sm" value={mode} onChange={setMode} options={[['month', 'Monat'], ['plan', 'Plan']]} />
        <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
          <IconBtn icon={icons.back} onClick={() => move(-1)} title={mode === 'month' ? 'Vorheriger Monat' : 'Vorherige Woche'} />
          <Button variant="soft" size="sm" onClick={goToday}>Heute</Button>
          <IconBtn icon={icons.chev} onClick={() => move(1)} title={mode === 'month' ? 'Nächster Monat' : 'Nächste Woche'} />
        </div>
        <Button variant="primary" icon={icons.plus} onClick={() => setEvtSheet({ id: '', title: '', equipmentId: '', start: selDay, end: selDay, color: '#5856D6', note: '', startTime: '09:00', endTime: '11:00' })}>Termin</Button>
      </Toolbar>

      <div style={{ flex: 1, display: 'flex', minHeight: 0, minWidth: 0 }}>
        <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column' }}>
          {mode === 'month' ?
          <MonthView t={t} cursor={cursor} bars={allBars} selDay={selDay} today={today} onPickDay={setSelDay} onPickBar={openPeek} labelMode={labelMode} setLabelMode={setLabelMode} /> :

          <PlanView t={t} weekStart={weekStart} bars={allBars} equipment={equipment} today={today} selDay={selDay} onPickDay={setSelDay} onPickBar={openPeek} />
          }
        </div>

        {/* day side panel — vertical timeline */}
        <DaySidePanel t={t} dayISO={selDay} bars={allBars} equipment={equipment} today={today}
        onPickBar={openPeek}
        onAdd={() => setEvtSheet({ id: '', title: '', equipmentId: '', start: selDay, end: selDay, color: '#5856D6', startTime: '09:00', endTime: '11:00', note: '' })} />
      </div>

      <EntryPreviewSheet open={!!peek} entry={peek} equipment={equipment}
      onClose={() => setPeek(null)}
      onColor={setEntryColor}
      onEdit={editFromPeek}
      onDelete={() => {if (peek && peek.kind === 'event') {delEvent(peek.ref.id);setPeek(null);}}} />

      <EventSheet open={!!evtSheet} initial={evtSheet} equipment={equipment} onClose={() => setEvtSheet(null)} onSave={saveEvent} onDelete={delEvent} />
    </>);

}

// ── Month view with spanning multi-day bars ──
function MonthView({ t, cursor, bars, selDay, today, onPickDay, onPickBar, labelMode, setLabelMode }) {
  const firstDow = (new Date(cursor.y, cursor.m, 1).getDay() + 6) % 7;
  const daysInMonth = new Date(cursor.y, cursor.m + 1, 0).getDate();
  const prevDays = new Date(cursor.y, cursor.m, 0).getDate();

  // 6 week rows of 7 days
  const weeks = [];
  for (let w = 0; w < 6; w++) {
    const days = [];
    for (let i = 0; i < 7; i++) {
      const cellIdx = w * 7 + i;
      const dayNum = cellIdx - firstDow + 1;
      let date,inMonth = true;
      if (dayNum < 1) {date = new Date(cursor.y, cursor.m - 1, prevDays + dayNum);inMonth = false;} else
      if (dayNum > daysInMonth) {date = new Date(cursor.y, cursor.m + 1, dayNum - daysInMonth);inMonth = false;} else
      date = new Date(cursor.y, cursor.m, dayNum);
      days.push({ iso: fmtDateISO(date), date, inMonth });
    }
    weeks.push(days);
  }

  const BAR_H = 19,BAR_GAP = 3,HEADER_H = 26;

  return (
    <div style={{ flex: 1, display: 'flex', flexDirection: 'column', padding: '14px 20px 16px', minHeight: 0 }}>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', marginBottom: 6 }}>
        {DE_DAYS_SHORT.slice(1).concat(DE_DAYS_SHORT[0]).map((d) =>
        <div key={d} style={{ textAlign: 'left', fontSize: 11, fontWeight: 700, color: t.textSec, textTransform: 'uppercase', letterSpacing: 0.5, paddingLeft: 8, paddingBottom: 6 }}>{d}</div>
        )}
      </div>
      {/* label-mode toggle (only shown in month view) */}
      <div style={{ flex: 1, display: 'grid', gridTemplateRows: 'repeat(6,1fr)', gap: 6, minHeight: 0 }}>
        {weeks.map((week, wi) => {
          const weekStart = week[0].iso,weekEnd = week[6].iso;
          // Find bars intersecting this week, clipped to week bounds
          const segs = bars.
          filter((b) => b.end >= weekStart && b.start <= weekEnd).
          map((b) => ({
            ...b,
            segStart: b.start < weekStart ? weekStart : b.start,
            segEnd: b.end > weekEnd ? weekEnd : b.end,
            startsHere: b.start >= weekStart,
            endsHere: b.end <= weekEnd
          }));
          // For lane packing, use segment bounds
          const { sorted, laneCount } = assignLanes(segs.map((s) => ({ ...s, start: s.segStart, end: s.segEnd })));

          return (
            <div key={wi} style={{ position: 'relative', display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 6, minHeight: 0 }}>
              {/* day cells (background + day number) */}
              {week.map((c) => {
                const isToday = c.iso === today;
                const isSel = c.iso === selDay;
                return (
                  <Pressable key={c.iso} onClick={() => onPickDay(c.iso)} scale={0.997}>
                    <div style={{
                        height: '100%', minHeight: 110, borderRadius: 10,
                        background: isSel ? t.chip : c.inMonth ? t.card : 'transparent',
                        border: isSel ? `1.5px solid ${t.dark ? 'rgba(255,255,255,0.2)' : 'rgba(0,0,0,0.2)'}` : `0.5px solid ${c.inMonth ? t.sep : 'transparent'}`,
                        boxShadow: c.inMonth && !isSel ? t.shadowSoft : 'none',
                        padding: '6px 8px', transition: 'background 0.12s'
                      }}>
                      <div style={{
                          fontSize: 13, fontWeight: isToday ? 700 : 600,
                          color: !c.inMonth ? t.textTer : isToday ? (t.dark ? '#0a0a0a' : '#fff') : t.text,
                          width: 22, height: 22, borderRadius: 11, display: 'flex', alignItems: 'center', justifyContent: 'center',
                          background: isToday ? (t.dark ? 'rgba(255,255,255,0.8)' : 'rgba(0,0,0,0.8)') : 'transparent', ...NUMS
                        }}>{c.date.getDate()}</div>
                    </div>
                  </Pressable>);

              })}
              {/* spanning bars overlay */}
              <div style={{ position: 'absolute', left: 0, right: 0, top: HEADER_H + 4, pointerEvents: 'none' }}>
                {(() => {
                  const MAX_VIS = 3; // lanes 0..MAX_VIS-1 show bars; lane MAX_VIS reserved for "+N weitere"
                  const visible = sorted.filter((s) => s.lane < MAX_VIS);
                  const hidden = sorted.filter((s) => s.lane >= MAX_VIS);
                  // For each day in the week, count how many hidden bars cover it
                  const hiddenPerDay = week.map((c) => hidden.filter((s) => s.segStart <= c.iso && s.segEnd >= c.iso).length);
                  return (
                    <>
                      {visible.map((s) => {
                  const startCol = (fromISO(s.segStart) - fromISO(weekStart)) / 86400000;
                  const span = (fromISO(s.segEnd) - fromISO(s.segStart)) / 86400000 + 1;
                  const topPx = s.lane * (BAR_H + BAR_GAP);
                  return (
                    <div key={s.id} style={{ position: 'absolute', top: topPx, left: `calc(${startCol / 7 * 100}% + 6px)`, width: `calc(${span / 7 * 100}% - 12px)`, height: BAR_H, pointerEvents: 'auto' }}>
                      <Pressable onClick={(e) => {e.stopPropagation && e.stopPropagation();onPickBar(s);}} scale={0.98}>
                        <div style={{
                          height: BAR_H, borderRadius: 5, background: s.color + '22',
                          padding: '0 7px', display: 'flex', alignItems: 'center', gap: 4,
                          fontSize: 11, color: s.color,
                          whiteSpace: 'nowrap', overflow: 'hidden'
                        }}>{(() => {
                            const prefix = s.startsHere ? '' : '…';
                            if (labelMode === 'equipment') {
                              const name = prefix + (s.eqName || s.title);
                              return (
                                <>
                                <span style={{ fontWeight: 700, overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0, flexShrink: 1 }}>{name}</span>
                                {s.eqTimes && <span style={{ fontWeight: 500, opacity: 0.85, ...NUMS, minWidth: 0, overflow: 'hidden', flexShrink: 9999 }}>{' · ' + s.eqTimes}</span>}
                              </>);

                            }
                            return <span style={{ fontWeight: 700, overflow: 'hidden', textOverflow: 'ellipsis' }}>{prefix + s.title}</span>;
                          })()}</div>
                      </Pressable>
                    </div>);

                })}
                      {/* per-day "+N weitere" pills */}
                      {week.map((c, di) => {
                        const n = hiddenPerDay[di];
                        if (!n) return null;
                        return (
                          <div key={'more-' + c.iso} style={{ position: 'absolute', top: MAX_VIS * (BAR_H + BAR_GAP), left: `calc(${di / 7 * 100}% + 6px)`, width: `calc(${1 / 7 * 100}% - 12px)`, height: BAR_H, pointerEvents: 'auto' }}>
                            <Pressable onClick={(e) => { e.stopPropagation && e.stopPropagation(); onPickDay(c.iso); }} scale={0.96}>
                              <div style={{ height: BAR_H, borderRadius: 5, background: t.chip, border: `0.5px solid ${t.sep}`, padding: '0 7px', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 10.5, fontWeight: 700, color: t.textSec, letterSpacing: 0.2 }}>+{n} weitere</div>
                            </Pressable>
                          </div>
                        );
                      })}
                    </>
                  );
                })()}
              </div>
            </div>);

        })}
      </div>
      {setLabelMode &&
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: 8, marginTop: 10 }}>
          <div style={{ fontSize: 11, color: t.textTer, fontWeight: 500 }}>Beschriftung</div>
          <Segmented size="sm" value={labelMode} onChange={setLabelMode} options={[['name', 'Name'], ['equipment', 'Gerät \u00b7 Zeit']]} />
        </div>
      }
    </div>);

}

// ── Plan view: equipment × week timeline (Belegungsplan) ──
function PlanView({ t, weekStart, bars, equipment, today, selDay, onPickDay, onPickBar }) {
  const days = Array.from({ length: 7 }, (_, i) => {
    const iso = shiftISO(weekStart, i);
    return { iso, date: fromISO(iso) };
  });
  const COL_LABEL_W = 200;
  const BAR_H = 22,BAR_GAP = 4,ROW_PAD = 10,BASE_ROW_H = 50;

  const planByEq = {};
  equipment.forEach((eq) => {
    const eqBars = bars.filter((b) => b.equipmentId === eq.id && b.end >= weekStart && b.start <= shiftISO(weekStart, 6)).
    map((b) => ({
      ...b,
      segStart: b.start < weekStart ? weekStart : b.start,
      segEnd: b.end > shiftISO(weekStart, 6) ? shiftISO(weekStart, 6) : b.end,
      startsHere: b.start >= weekStart
    }));
    planByEq[eq.id] = assignLanes(eqBars.map((b) => ({ ...b, start: b.segStart, end: b.segEnd })));
  });
  const rowH = (eqId) => {
    const lc = (planByEq[eqId] || { laneCount: 1 }).laneCount;
    return Math.max(BASE_ROW_H, ROW_PAD * 2 + lc * BAR_H + (lc - 1) * BAR_GAP);
  };

  return (
    <div className="rf-scroll" style={{ flex: 1, minHeight: 0, minWidth: 0, overflow: 'auto', padding: '14px 20px 16px' }}>
      <div style={{ minWidth: 880 }}>
        {/* day header */}
        <div style={{ display: 'flex', position: 'sticky', top: 0, background: t.card, zIndex: 2, paddingBottom: 6, borderBottom: `0.5px solid ${t.sep}`, marginBottom: 6 }}>
          <div style={{ width: COL_LABEL_W, flexShrink: 0, fontSize: 11, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, paddingLeft: 4 }}>Equipment</div>
          <div style={{ flex: 1, display: 'grid', gridTemplateColumns: 'repeat(7,1fr)' }}>
            {days.map((d) => {
              const isToday = d.iso === today,isSel = d.iso === selDay;
              return (
                <Pressable key={d.iso} onClick={() => onPickDay(d.iso)} scale={0.98}>
                  <div style={{ textAlign: 'center', padding: '4px 0', borderRadius: 8, background: isSel ? t.chip : 'transparent' }}>
                    <div style={{ fontSize: 10.5, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5 }}>{DE_DAYS_SHORT[d.date.getDay()]}</div>
                    <div style={{ fontSize: 16, fontWeight: 700, color: isToday ? t.dark ? '#0a0a0a' : '#fff' : t.text, background: isToday ? t.text : 'transparent', width: 26, height: 26, lineHeight: '26px', borderRadius: 13, margin: '2px auto 0', ...NUMS }}>{d.date.getDate()}</div>
                  </div>
                </Pressable>);

            })}
          </div>
        </div>

        {/* rows */}
        {equipment.map((eq) => {
          const { sorted } = planByEq[eq.id] || { sorted: [] };
          const h = rowH(eq.id);
          return (
            <div key={eq.id} style={{ display: 'flex', borderBottom: `0.5px solid ${t.sep}` }}>
              <div style={{ width: COL_LABEL_W, flexShrink: 0, padding: '10px 6px 10px 4px', display: 'flex', alignItems: 'center', gap: 8 }}>
                <EqAvatar item={eq} size={28} radius={7} />
                <div style={{ minWidth: 0 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{eq.name}</div>
                  <div style={{ fontSize: 11, color: t.textSec, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{eq.cat}</div>
                </div>
              </div>
              <div style={{ flex: 1, position: 'relative', height: h, background: 'transparent' }}>
                {/* day column separators */}
                {days.map((d, i) =>
                <div key={d.iso} style={{ position: 'absolute', top: 0, bottom: 0, left: `${i / 7 * 100}%`, width: `${100 / 7}%`, borderLeft: i === 0 ? 'none' : `0.5px dashed ${t.sep}`, background: d.iso === today ? t.chip : 'transparent' }} />
                )}
                {/* bars */}
                {sorted.map((s) => {
                  const startCol = (fromISO(s.segStart) - fromISO(weekStart)) / 86400000;
                  const span = (fromISO(s.segEnd) - fromISO(s.segStart)) / 86400000 + 1;
                  return (
                    <Pressable key={s.id} onClick={() => onPickBar(s)} scale={0.98} style={{
                      position: 'absolute', top: ROW_PAD + s.lane * (BAR_H + BAR_GAP), height: BAR_H,
                      left: `calc(${startCol / 7 * 100}% + 3px)`, width: `calc(${span / 7 * 100}% - 6px)`
                    }}>
                      <div style={{
                        height: BAR_H, borderRadius: 6, background: s.color + '22',
                        padding: '0 9px', display: 'flex', alignItems: 'center', gap: 5,
                        fontSize: 11.5, color: s.color,
                        whiteSpace: 'nowrap', overflow: 'hidden'
                      }}>{(() => {
                        const prefix = s.startsHere ? '' : '…';
                        const fromISOD = (iso) => { const d = fromISO(iso); return `${d.getDate()}.${d.getMonth() + 1}.`; };
                        const pickup = s.startTime ? `↑${fromISOD(s.start)} ${s.startTime}` : '';
                        const ret = s.endTime ? `↓${fromISOD(s.end)} ${s.endTime}` : '';
                        const meta = [pickup, ret].filter(Boolean).join(' ');
                        return (
                          <>
                            <span style={{ fontWeight: 700, overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0, flexShrink: 1 }}>{prefix + s.title}</span>
                            {meta && <span style={{ fontWeight: 500, opacity: 0.85, ...NUMS, minWidth: 0, overflow: 'hidden', flexShrink: 9999 }}>{' · ' + meta}</span>}
                          </>
                        );
                      })()}</div>
                    </Pressable>);

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

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

}

// ── Day side panel: vertical hour timeline + multi-day strip ──
// Mirrors the mobile day view: colored icon-circle nodes sit ON a central
// strand at each event's start; pill cards extend to the right, height ∝ duration.
function DaySidePanel({ t, dayISO, bars, equipment, today, onPickBar, onAdd }) {
  const dayBars = bars.filter((b) => dayISO >= b.start && dayISO <= b.end);
  const timed = [],multi = [];
  dayBars.forEach((b) => {
    const isFirst = b.start === dayISO,isLast = b.end === dayISO;
    const sHr = isFirst ? parseTime(b.startTime) : null;
    const eHr = isLast ? parseTime(b.endTime) : null;
    const sameDay = b.start === b.end;
    if (sameDay && sHr != null && eHr != null && eHr > sHr) timed.push({ b, sHr, eHr });else
    if (sameDay) multi.push({ b, isFirst: true, isLast: true, untimed: true });else
    multi.push({ b, isFirst, isLast });
  });
  timed.sort((a, c) => a.sHr - c.sHr || c.eHr - a.eHr);

  // Lane-pack timed events
  const tLaneEnds = [];
  timed.forEach((s) => {
    let lane = tLaneEnds.findIndex((end) => s.sHr >= end - 0.001);
    if (lane === -1) {lane = tLaneEnds.length;tLaneEnds.push(s.eHr);} else
    tLaneEnds[lane] = s.eHr;
    s.lane = lane;
  });
  const LANE_COUNT = Math.max(1, tLaneEnds.length);

  const minHr = timed.length ? Math.max(0, Math.floor(Math.min(...timed.map((s) => s.sHr))) - 1) : 8;
  const maxHr = timed.length ? Math.min(24, Math.ceil(Math.max(...timed.map((s) => s.eHr))) + 1) : 18;
  const HOUR_H = 64;
  const TIMELINE_H = (maxHr - minHr) * HOUR_H + 32;
  const LINE_X = 78; // central strand x
  const NODE_R = 20; // node radius
  const PILL_LEFT = LINE_X + NODE_R + 4;
  const PILL_RIGHT_PAD = 14;

  const isToday = dayISO === today;
  const nowFrac = isToday ? new Date().getHours() + new Date().getMinutes() / 60 : -1;
  const day = fromISO(dayISO);
  const iconFor = (ev) => ev.kind === 'rental' ? icons.doc : icons.cal;

  return (
    <div style={{ width: 360, flexShrink: 0, borderLeft: `0.5px solid ${t.sep}`, display: 'flex', flexDirection: 'column', minHeight: 0, background: t.card }}>
      <div style={{ padding: '16px 18px 14px', borderBottom: `0.5px solid ${t.sep}`, display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 8 }}>
        <div>
          <div style={{ fontSize: 12, color: t.textSec, fontWeight: 600 }}>{DE_DAYS[day.getDay()]}{isToday ? ' · Heute' : ''}</div>
          <div style={{ fontSize: 22, fontWeight: 700, color: t.text, letterSpacing: -0.4, marginTop: 1, ...NUMS }}>{day.getDate()}. {DE_MONTHS[day.getMonth()]}</div>
          <div style={{ fontSize: 11, color: t.textSec, marginTop: 5, display: 'flex', alignItems: 'center', gap: 6, fontWeight: 600 }}>
            <span>{dayBars.length} {dayBars.length === 1 ? 'Eintrag' : 'Einträge'}</span>
            {timed.length > 0 && <><span style={{ color: t.textTer }}>·</span><span>{timed.length} mit Uhrzeit</span></>}
            {multi.length > 0 && <><span style={{ color: t.textTer }}>·</span><span>{multi.length} mehrtägig</span></>}
          </div>
        </div>
        <IconBtn icon={icons.plus} onClick={onAdd} title="Termin hinzufügen" />
      </div>

      <div className="rf-scroll" style={{ flex: 1, overflow: 'auto', padding: '14px 0 18px' }}>
        {/* ── Timed strand ── */}
        {(timed.length > 0 || dayBars.length === 0) &&
        <div style={{ position: 'relative', height: TIMELINE_H }}>
            {/* Hour rail labels + dashed grid */}
            {Array.from({ length: maxHr - minHr + 1 }, (_, i) => {
            const h = minHr + i,top = i * HOUR_H + 16;
            return (
              <div key={h} style={{ position: 'absolute', top, left: 0, right: 0, height: 0 }}>
                  <div style={{ position: 'absolute', left: 14, top: -8, fontSize: 11, color: t.textSec, fontWeight: 600, ...NUMS }}>{String(h).padStart(2, '0')}:00</div>
                  <div style={{ position: 'absolute', left: LINE_X + NODE_R + 2, right: PILL_RIGHT_PAD, top: 0, height: 0, borderTop: `0.5px dashed ${t.dark ? 'rgba(255,255,255,0.07)' : 'rgba(0,0,0,0.07)'}` }} />
                </div>);

          })}

            {/* Central vertical strand */}
            <div style={{ position: 'absolute', left: LINE_X - 1, top: 8, bottom: 8, width: 2, background: t.dark ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.08)', borderRadius: 2 }} />

            {/* Now-marker */}
            {nowFrac >= minHr && nowFrac <= maxHr &&
          <div style={{ position: 'absolute', top: (nowFrac - minHr) * HOUR_H + 16, left: LINE_X - 16, right: PILL_RIGHT_PAD, height: 0, display: 'flex', alignItems: 'center', gap: 4, pointerEvents: 'none', zIndex: 3 }}>
                <div style={{ width: 9, height: 9, borderRadius: 5, background: t.red, marginTop: -4.5 }} />
                <div style={{ flex: 1, height: 1.5, background: t.red, opacity: 0.7 }} />
              </div>
          }

            {/* Event pills + nodes */}
            {timed.map((s) => {
            const ev = s.b;
            const eq = equipment.find((e) => e.id === ev.equipmentId);
            const top = (s.sHr - minHr) * HOUR_H + 16;
            const dur = s.eHr - s.sHr;
            const minutes = Math.round(dur * 60);
            const durLabel = minutes < 60 ? minutes + ' min' : dur % 1 === 0 ? dur + ' h' : dur.toFixed(1).replace('.', ',') + ' h';
            const PILL_MIN_H = 60;
            const pillH = Math.max(dur * HOUR_H, PILL_MIN_H);
            const lanePct = 100 / LANE_COUNT;
            return (
              <div key={ev.id} style={{ position: 'absolute', top: top - NODE_R, left: 0, right: 0 }}>
                  {/* Node on the strand */}
                  <div style={{ position: 'absolute', left: LINE_X - NODE_R, top: 0, width: NODE_R * 2, height: NODE_R * 2, borderRadius: NODE_R, background: tintColor(ev.color, 1), border: `3px solid ${t.card}`, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 2px 6px rgba(0,0,0,0.18)', zIndex: 4 }}>
                    <Icon d={iconFor(ev)} color="#fff" size={16} sw={2} />
                  </div>
                  {/* Pill, lane-split */}
                  <Pressable onClick={() => onPickBar(ev)} scale={0.99} style={{
                  position: 'absolute', top: 0, height: pillH,
                  left: `calc(${PILL_LEFT}px + ${s.lane * lanePct}% - ${s.lane * (PILL_LEFT + PILL_RIGHT_PAD) / LANE_COUNT}px)`,
                  width: `calc(${lanePct}% - ${(PILL_LEFT + PILL_RIGHT_PAD) / LANE_COUNT}px - 4px)`
                }}>
                    <div style={{
                    height: '100%', borderRadius: 14,
                    background: tintColor(ev.color, t.dark ? 0.22 : 0.1),
                    border: `1.5px solid ${tintColor(ev.color, 0.33)}`,
                    display: 'flex', flexDirection: 'column', justifyContent: 'center',
                    padding: '8px 12px', gap: 2, overflow: 'hidden'
                  }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 5, minWidth: 0 }}>
                        <span style={{ fontSize: 10.5, color: t.textSec, fontWeight: 600, ...NUMS, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0 }}>
                          {fmtHr(s.sHr)}–{fmtHr(s.eHr)} · {durLabel}
                        </span>
                        {ev.kind === 'rental' && <span style={{ fontSize: 8, fontWeight: 700, color: tintColor(ev.color, 1), background: tintColor(ev.color, 0.13), padding: '1px 5px', borderRadius: 100, letterSpacing: 0.3, flexShrink: 0 }}>MIETE</span>}
                      </div>
                      <div style={{ fontSize: 13.5, fontWeight: 700, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{ev.title}</div>
                      {eq && <div style={{ fontSize: 10.5, color: t.textSec, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{eq.name}</div>}
                    </div>
                  </Pressable>
                </div>);

          })}

            {timed.length === 0 &&
          <div style={{ position: 'absolute', top: 100, left: 0, right: 0, textAlign: 'center', color: t.textSec, fontSize: 12.5 }}>Keine Termine an diesem Tag.</div>
          }
          </div>
        }

        {/* ── Mehrtägig / Ganztägig strand ── */}
        {multi.length > 0 && (() => {
          const heading = multi.every((s) => s.untimed) ? 'Ganztägig' :
          multi.some((s) => s.untimed) ? 'Mehrtägig & ganztägig' : 'Mehrtägig';
          return (
            <div style={{ marginTop: timed.length > 0 ? 8 : 0, padding: '14px 16px 0' }}>
              <div style={{ fontSize: 10.5, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 10 }}>
                {heading} · {multi.length} {multi.length === 1 ? 'Eintrag' : 'Einträge'}
              </div>
              <div style={{ position: 'relative', paddingLeft: 34 }}>
                <div style={{ position: 'absolute', left: 13, top: 6, bottom: 6, width: 2, background: t.dark ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.08)', borderRadius: 2 }} />
                {multi.map((s) => {
                  const ev = s.b;
                  const eq = equipment.find((e) => e.id === ev.equipmentId);
                  const totalDays = daysBetween(ev.start, ev.end);
                  const curIdx = daysBetween(ev.start, dayISO);
                  return (
                    <div key={ev.id} style={{ position: 'relative', marginBottom: 8 }}>
                      <div style={{ position: 'absolute', left: -27, top: 10, width: 26, height: 26, borderRadius: 13, background: tintColor(ev.color, 1), border: `3px solid ${t.card}`, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 2px 6px rgba(0,0,0,0.18)' }}>
                        <Icon d={iconFor(ev)} color="#fff" size={13} sw={2.2} />
                      </div>
                      <Pressable onClick={() => onPickBar(ev)} scale={0.99}>
                        <div style={{
                          borderRadius: 12,
                          background: tintColor(ev.color, t.dark ? 0.2 : 0.09),
                          border: `1.5px solid ${tintColor(ev.color, 0.27)}`,
                          padding: '9px 12px'
                        }}>
                          <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 10.5, color: t.textSec, fontWeight: 600 }}>
                            {s.untimed ? 'Ganztägig' : `Tag ${curIdx + 1} / ${totalDays}`}
                            {ev.kind === 'rental' && <span style={{ fontSize: 8, fontWeight: 700, color: tintColor(ev.color, 1), background: tintColor(ev.color, 0.13), padding: '1px 5px', borderRadius: 100, letterSpacing: 0.3 }}>MIETE</span>}
                          </div>
                          <div style={{ fontSize: 13.5, fontWeight: 700, color: t.text, marginTop: 2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{ev.title}</div>
                          <div style={{ fontSize: 11, color: t.textSec, marginTop: 2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                            {eq ? eq.name : ''}{s.untimed ? '' : (eq ? ' · ' : '') + fmtRange(ev.start, ev.end)}
                          </div>
                        </div>
                      </Pressable>
                    </div>);

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

        })()}

        {/* Add-entry CTA */}
        <div style={{ padding: '16px 16px 0' }}>
          <Pressable onClick={onAdd} scale={0.98}>
            <div style={{
              display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
              padding: '11px 0', borderRadius: 12,
              border: `1.5px dashed ${t.sep}`, background: 'transparent',
              color: t.textSec, fontSize: 12.5, fontWeight: 600
            }}>
              <Icon d={icons.plus} color={t.textSec} size={14} sw={2.2} />
              Eintrag an diesem Tag hinzufügen
            </div>
          </Pressable>
        </div>
      </div>
    </div>);

}

// ── Entry preview sheet — quick info + color picker + "Bearbeiten" ──
function EntryPreviewSheet({ open, entry, equipment, onClose, onColor, onEdit, onDelete }) {
  const t = useTheme();
  if (!entry) return null;
  const isRental = entry.kind === 'rental';
  const ref = entry.ref;
  const eq = equipment.find((e) => e.id === ref.equipmentId);
  const days = daysBetween(ref.start, ref.end);
  const color = ref.color || (isRental ? statusMeta(ref.status).color : '#5856D6');
  const sm = isRental ? statusMeta(ref.status) : null;
  const COLORS = ['#34C759', '#FF9500', '#5856D6', '#FF2D55', '#AF52DE', '#007AFF', '#1c1c1e', '#8E8E93'];
  const hasTime = ref.startTime || ref.endTime;

  // ── Rich rental view ──
  if (isRental) {
    const items = typeof getRentalItems === 'function' ? getRentalItems(ref, equipment) : ref.items || [{ equipmentName: ref.equipmentName, quantity: ref.quantity || 1, dailyRate: ref.dailyRate || 0 }];
    const total = typeof rentalTotal === 'function' ? rentalTotal(ref) : 0;
    const fee = typeof rentalDeliveryFee === 'function' ? rentalDeliveryFee(ref) : 0;
    const paid = ref.paymentStatus === 'bezahlt';
    const payDot = paid ? t.green : t.orange;
    const payLabel = paid ? 'Bezahlt' : 'Offen';
    const dShort = (iso) => {const d = fromISO(iso);return `${d.getDate()}. ${DE_MONTHS[d.getMonth()]}`;};

    const SectionLbl = ({ children, style }) =>
    <div style={{ fontSize: 10.5, fontWeight: 700, color: t.textSec, textTransform: 'uppercase', letterSpacing: 0.6, ...style }}>{children}</div>;


    return (
      <Sheet open={open} onClose={onClose} width={520}>
        <div style={{ padding: '14px 26px 24px' }}>
          {/* Header */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 14 }}>
            <div style={{ width: 36, height: 36, borderRadius: 18, background: color, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
              <Icon d={icons.doc} color="#fff" size={17} sw={2} />
            </div>
            <div style={{ fontSize: 11, fontWeight: 700, color: t.textSec, letterSpacing: 0.8 }}>MIETVERTRAG</div>
            {sm &&
            <div style={{ display: 'flex', alignItems: 'center', gap: 5, padding: '4px 10px', borderRadius: 100, background: sm.color + '22' }}>
                <div style={{ width: 7, height: 7, borderRadius: 4, background: sm.color }} />
                <div style={{ fontSize: 11, fontWeight: 700, color: sm.color, textTransform: 'uppercase', letterSpacing: 0.5 }}>{sm.label}</div>
              </div>
            }
            <div style={{ flex: 1 }} />
            <Pressable onClick={onClose} scale={0.9}>
              <div style={{ width: 30, height: 30, borderRadius: 15, background: t.chip, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <Icon d="M6 6l12 12M18 6L6 18" color={t.textSec} size={13} sw={2.2} />
              </div>
            </Pressable>
          </div>

          {/* Customer name */}
          <div style={{ fontSize: 26, fontWeight: 700, color: t.text, letterSpacing: -0.6, marginBottom: 4 }}>{ref.tenantName}</div>
          {ref.purpose && <div style={{ fontSize: 13.5, color: t.textSec, marginBottom: 18 }}>{ref.purpose}</div>}

          {/* Zeitraum + Gesamtpreis */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 18, marginTop: 14, marginBottom: 22 }}>
            <div>
              <SectionLbl style={{ marginBottom: 6 }}>Zeitraum</SectionLbl>
              <div style={{ fontSize: 18, fontWeight: 700, color: t.text, letterSpacing: -0.2, ...NUMS }}>{fmtRange(ref.start, ref.end)}</div>
              <div style={{ fontSize: 12, color: t.textSec, marginTop: 2 }}>{days} Tag{days > 1 ? 'e' : ''}</div>
            </div>
            <div>
              <SectionLbl style={{ marginBottom: 6 }}>Gesamtpreis</SectionLbl>
              <div style={{ fontSize: 18, fontWeight: 700, color: t.text, letterSpacing: -0.2, ...NUMS }}>{total.toFixed(2).replace('.', ',')} €</div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 4 }}>
                <div style={{ width: 7, height: 7, borderRadius: 4, background: payDot }} />
                <div style={{ fontSize: 12.5, color: payDot, fontWeight: 700 }}>{payLabel}</div>
              </div>
            </div>
          </div>

          {/* Abholung + Rückgabe */}
          {hasTime &&
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 18, marginBottom: 22, padding: '14px 16px', background: t.cardAlt, borderRadius: 12 }}>
              <div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 6 }}>
                  <Icon d="M12 19V5M5 12l7-7 7 7" color={t.green} size={13} sw={2.4} />
                  <SectionLbl>Abholung</SectionLbl>
                </div>
                <div style={{ fontSize: 18, fontWeight: 700, color: t.text, ...NUMS }}>{ref.startTime || '–'}{ref.startTime ? ' Uhr' : ''}</div>
                <div style={{ fontSize: 12, color: t.textSec, marginTop: 2 }}>{dShort(ref.start)}</div>
              </div>
              <div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 6 }}>
                  <Icon d="M12 5v14M5 12l7 7 7-7" color={t.red} size={13} sw={2.4} />
                  <SectionLbl>Rückgabe</SectionLbl>
                </div>
                <div style={{ fontSize: 18, fontWeight: 700, color: t.text, ...NUMS }}>{ref.endTime || '–'}{ref.endTime ? ' Uhr' : ''}</div>
                <div style={{ fontSize: 12, color: t.textSec, marginTop: 2 }}>{dShort(ref.end)}</div>
              </div>
            </div>
          }

          {/* Mieter */}
          <div style={{ marginBottom: 22 }}>
            <SectionLbl style={{ marginBottom: 8 }}>Mieter</SectionLbl>
            <div style={{ fontSize: 15, fontWeight: 700, color: t.text, marginBottom: 4 }}>{ref.tenantName}</div>
            {ref.phone && <div style={{ fontSize: 13, color: t.textSec, marginTop: 2, ...NUMS }}>{ref.phone}</div>}
            {ref.email && <div style={{ fontSize: 13, color: t.textSec, marginTop: 2 }}>{ref.email}</div>}
            {ref.address && <div style={{ fontSize: 13, color: t.textSec, marginTop: 4, whiteSpace: 'pre-line', lineHeight: 1.5 }}>{ref.address}</div>}
          </div>

          {/* Equipment */}
          <div style={{ marginBottom: 18 }}>
            <SectionLbl style={{ marginBottom: 8 }}>Equipment · {items.length} {items.length === 1 ? 'Position' : 'Positionen'}</SectionLbl>
            <div style={{ display: 'flex', flexDirection: 'column', borderRadius: 12, overflow: 'hidden', background: t.card, border: `0.5px solid ${t.sep}` }}>
              {items.map((it, i) => {
                const eqx = it.equipmentId && equipment.find((e) => e.id === it.equipmentId);
                const qty = Math.max(1, Number(it.quantity) || 1);
                const sum = days * (Number(it.dailyRate) || 0) * qty;
                return (
                  <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '11px 14px', borderBottom: i < items.length - 1 ? `0.5px solid ${t.sep}` : 'none' }}>
                    <div style={{ width: 36, height: 36, borderRadius: 9, background: t.chip, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                      <Icon d={eqx && icons[eqx.icon] || icons.folder} color={t.textSec} size={16} sw={1.8} />
                    </div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 13.5, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{eqx && eqx.name || it.equipmentName}</div>
                      <div style={{ fontSize: 11.5, color: t.textSec, marginTop: 1, ...NUMS }}>{qty} Stück · {Number(it.dailyRate || 0).toFixed(2).replace('.', ',')} €/Tag (Stück)</div>
                    </div>
                    <div style={{ fontSize: 14, fontWeight: 700, color: t.text, ...NUMS, flexShrink: 0 }}>{sum.toFixed(2).replace('.', ',')} €</div>
                  </div>);

              })}
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '11px 14px', background: t.cardAlt, borderTop: `0.5px solid ${t.sep}` }}>
                <div style={{ flex: 1, fontSize: 12, color: t.textSec, fontWeight: 500 }}>Summe · {days} Tag{days > 1 ? 'e' : ''}{fee > 0 ? ` · inkl. ${fee.toFixed(2).replace('.', ',')} € Lieferung` : ''}{Number(ref.discount) ? ` · −${Number(ref.discount)} € Rabatt` : ''}</div>
                <div style={{ fontSize: 14, fontWeight: 700, color: t.text, ...NUMS }}>{total.toFixed(2).replace('.', ',')} €</div>
              </div>
            </div>
          </div>

          {/* Lieferung */}
          {ref.delivery && ref.delivery.enabled &&
          <div style={{ marginBottom: 18 }}>
              <SectionLbl style={{ marginBottom: 8 }}>Lieferung</SectionLbl>
              <div style={{ fontSize: 13.5, color: t.text, fontWeight: 500, whiteSpace: 'pre-line', lineHeight: 1.5 }}>{ref.delivery.address || ref.address}</div>
              {(Number(ref.delivery.km) > 0 || fee > 0) &&
            <div style={{ fontSize: 12, color: t.textSec, marginTop: 4, ...NUMS }}>{ref.delivery.km ? `${ref.delivery.km} km · ` : ''}{fee.toFixed(2).replace('.', ',')} € Liefergebühr</div>
            }
            </div>
          }

          {/* Farbe */}
          <div style={{ marginTop: 4, marginBottom: 22 }}>
            <SectionLbl style={{ marginBottom: 10 }}>Farbe</SectionLbl>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
              {COLORS.map((c) =>
              <Pressable key={c} onClick={() => onColor(c)} scale={0.86}>
                  <div style={{ width: 28, height: 28, borderRadius: 14, background: c, border: color === c ? `2.5px solid ${t.text}` : '2.5px solid transparent', boxShadow: `0 0 0 1px ${t.sep}` }} />
                </Pressable>
              )}
            </div>
          </div>

          {/* Action */}
          <div style={{ display: 'flex', gap: 10 }}>
            <Pressable onClick={onEdit} scale={0.98} style={{ flex: 1 }}>
              <div style={{ padding: '13px 0', textAlign: 'center', borderRadius: 11, background: t.solidBg, color: t.solidFg, fontSize: 14, fontWeight: 700, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 7, width: '100%' }}>
                <Icon d={icons.edit} color={t.solidFg} size={14} sw={2} />Im Vermietungen-Tab öffnen
              </div>
            </Pressable>
          </div>
        </div>
      </Sheet>);

  }

  // ── Event (non-rental) view — simpler ──
  return (
    <Sheet open={open} onClose={onClose} width={440}>
      <div style={{ padding: '18px 24px 22px' }}>
          <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 3 }}>
                <span style={{ fontSize: 10.5, fontWeight: 700, color: color, background: color + '22', padding: '3px 8px', borderRadius: 100, letterSpacing: 0.4 }}>TERMIN</span>
              </div>
              <div style={{ fontSize: 21, fontWeight: 700, color: t.text, letterSpacing: -0.4, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{ref.title}</div>
            </div>
            <Pressable onClick={onClose}><div style={{ fontSize: 13, color: t.textSec, fontWeight: 500 }}>Schließen</div></Pressable>
          </div>

          {/* meta rows */}
          <div style={{ marginTop: 16, display: 'flex', flexDirection: 'column', gap: 6 }}>
            <PeekRow t={t} icon={icons.cal} label="Zeitraum" value={`${fmtRange(ref.start, ref.end)} · ${days} Tag${days > 1 ? 'e' : ''}`} />
            {hasTime && <PeekRow t={t} icon={icons.clock} label="Uhrzeit" value={`${ref.startTime || '–'}${ref.endTime ? ' – ' + ref.endTime : ''}`} mono />}
            {eq && <PeekRow t={t} icon={icons.folder} label="Equipment" value={eq.name} />}
            {ref.note && <PeekRow t={t} icon={icons.fileText} label="Notiz" value={ref.note} />}
          </div>

          {/* color picker */}
          <div style={{ marginTop: 20 }}>
            <div style={{ fontSize: 10.5, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 8 }}>Farbe</div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
              {COLORS.map((c) =>
            <Pressable key={c} onClick={() => onColor(c)} scale={0.86}>
                  <div style={{ width: 28, height: 28, borderRadius: 14, background: c, border: color === c ? `2.5px solid ${t.text}` : '2.5px solid transparent', boxShadow: `0 0 0 1px ${t.sep}` }} />
                </Pressable>
            )}
            </div>
          </div>

          {/* actions */}
          <div style={{ display: 'flex', gap: 10, marginTop: 22 }}>
            <Pressable onClick={onDelete} scale={0.97}><div style={{ padding: '12px 18px', borderRadius: 10, background: t.redSoft || t.red + '22', color: t.red, fontSize: 13.5, fontWeight: 600 }}>Löschen</div></Pressable>
            <Pressable onClick={onEdit} scale={0.98} style={{ flex: 1 }}>
              <div style={{ padding: '12px 0', textAlign: 'center', borderRadius: 10, background: t.solidBg, color: t.solidFg, fontSize: 14, fontWeight: 700, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 7, width: '100%' }}>
                <Icon d={icons.edit} color={t.solidFg} size={14} sw={2} />Bearbeiten
              </div>
            </Pressable>
          </div>
        </div>
    </Sheet>);

}

function PeekRow({ t, icon, label, value, mono }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 0' }}>
      <div style={{ width: 22, height: 22, borderRadius: 6, background: t.chip, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
        <Icon d={icon} color={t.textSec} size={12} sw={2} />
      </div>
      <div style={{ fontSize: 11.5, color: t.textSec, fontWeight: 600, width: 80, flexShrink: 0 }}>{label}</div>
      <div style={{ flex: 1, minWidth: 0, fontSize: 13, color: t.text, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', ...(mono ? NUMS : {}) }}>{value}</div>
    </div>);

}

// ── Event dialog ──
function EventSheet({ open, initial, equipment, onClose, onSave, onDelete }) {
  const t = useTheme();
  const [form, setForm] = useState(initial || {});
  useEffect(() => {if (open) setForm(initial || {});}, [open, initial]);
  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));
  const isEdit = !!(initial && initial.id);
  const COLORS = ['#5856D6', '#FF2D55', '#AF52DE', '#34C759', '#FF9500', '#007AFF'];
  const valid = form.title && form.title.trim();
  if (!open) return null;
  return (
    <Sheet open={open} onClose={onClose} width={460}>
      <div style={{ padding: '4px 26px 24px' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
          <div style={{ fontSize: 21, fontWeight: 700, color: t.text, letterSpacing: -0.4 }}>{isEdit ? 'Termin bearbeiten' : 'Neuer Termin'}</div>
          <Pressable onClick={onClose}><div style={{ fontSize: 14, color: t.textSec, fontWeight: 500 }}>Abbrechen</div></Pressable>
        </div>
        <Field label="Titel" required><TextInput value={form.title || ''} onChange={(e) => set('title', e.target.value)} placeholder="z.B. Werkstatt-Termin" /></Field>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
          <Field label="Von"><TextInput type="date" value={form.start || ''} onChange={(e) => set('start', e.target.value)} /></Field>
          <Field label="Bis"><TextInput type="date" value={form.end || ''} onChange={(e) => set('end', e.target.value)} /></Field>
        </div>
        {(() => {
          const allDay = !form.startTime && !form.endTime;
          const toggleAllDay = () => {
            if (allDay) setForm((f) => ({ ...f, startTime: '09:00', endTime: '11:00' }));
            else setForm((f) => ({ ...f, startTime: '', endTime: '' }));
          };
          return (
            <>
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 14, padding: '12px 14px', background: t.cardAlt, borderRadius: 10, marginTop: 14, marginBottom: form.startTime || form.endTime ? 0 : 4 }}>
                <div>
                  <div style={{ fontSize: 14, fontWeight: 600, color: t.text }}>Ganzer Tag</div>
                  <div style={{ fontSize: 11.5, color: t.textSec, marginTop: 2 }}>{allDay ? 'Ohne feste Uhrzeit' : 'Mit Start- & Endzeit'}</div>
                </div>
                <Pressable onClick={toggleAllDay} scale={0.95}>
                  <div style={{ width: 46, height: 28, borderRadius: 14, background: allDay ? t.green : t.chipStrong, position: 'relative', transition: 'background 0.15s' }}>
                    <div style={{ position: 'absolute', top: 2, left: allDay ? 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>
              {!allDay && (
                <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
                  <Field label="Startzeit"><TextInput type="time" value={form.startTime || ''} onChange={(e) => set('startTime', e.target.value)} /></Field>
                  <Field label="Endzeit"><TextInput type="time" value={form.endTime || ''} onChange={(e) => set('endTime', e.target.value)} /></Field>
                </div>
              )}
            </>
          );
        })()}
        <Field label="Equipment (optional)">
          <select value={form.equipmentId || ''} onChange={(e) => set('equipmentId', e.target.value)} style={{ ...inp(t), appearance: 'none', cursor: 'pointer' }}>
            <option value="">— keins —</option>
            {equipment.map((e) => <option key={e.id} value={e.id}>{e.name}</option>)}
          </select>
        </Field>
        <Field label="Notiz"><TextInput value={form.note || ''} onChange={(e) => set('note', e.target.value)} placeholder="optional" /></Field>
        <Field label="Farbe"><div style={{ display: 'flex', gap: 10 }}>
          {COLORS.map((c) => <Pressable key={c} onClick={() => set('color', c)} scale={0.85}><div style={{ width: 30, height: 30, borderRadius: 15, background: c, border: form.color === c ? `2.5px solid ${t.text}` : '2.5px solid transparent', boxShadow: `0 0 0 1px ${t.sep}` }} /></Pressable>)}
        </div></Field>
        <div style={{ display: 'flex', gap: 10, marginTop: 22 }}>
          {isEdit && <Pressable onClick={() => {onDelete(form.id);onClose();}} scale={0.97}><div style={{ padding: '12px 18px', borderRadius: 10, background: t.redSoft, color: t.red, fontSize: 14, fontWeight: 600 }}>Löschen</div></Pressable>}
          <Pressable onClick={() => {if (!valid) return;onSave({ ...form, id: form.id || 'g-' + Date.now(), color: form.color || '#5856D6' });onClose();}} scale={0.98} style={{ flex: 1 }}>
            <div style={{ padding: '12px 0', textAlign: 'center', borderRadius: 10, background: valid ? t.solidBg : t.chip, color: valid ? t.solidFg : t.textTer, fontSize: 14, fontWeight: 700 }}>{isEdit ? 'Speichern' : 'Anlegen'}</div>
          </Pressable>
        </div>
      </div>
    </Sheet>);

}

Object.assign(window, { ScreenCalendar, EventSheet });