// ===== Ausführung → Shopfloor Management (SQCDP-Board) =====
const { useState: useSfS } = React;

// Status-Ampel aus der Design-System-Palette
const SF = {
  green: 'var(--good-ink)', greenBg: 'color-mix(in oklch, var(--good) 62%, var(--surface))',
  amber: 'var(--warn-ink)', amberBg: 'color-mix(in oklch, var(--warn) 60%, var(--surface))',
  red: 'var(--bad-ink)', redBg: 'color-mix(in oklch, var(--bad) 58%, var(--surface))',
  none: 'var(--surface-2)',
};
const catColors = { S: SF.green, Q: SF.amber, C: SF.red, D: '#3269B4', P: 'var(--accent-ink)' };
const SF_CATS = [['S', 'Arbeitssicherheit'], ['Q', 'Qualität'], ['C', 'Kosten/Technik'], ['D', 'Liefertreue'], ['P', 'Personal']];
const SF_STATUS = [['offen', 'Offen'], ['arbeit', 'In Arbeit'], ['erledigt', 'Erledigt']];
const SF_OWNERS = ['SM', 'VM', 'TK', 'AG', 'LB', 'Ingo Instandhaltung', 'Anton AV', 'Lars Logistik'];

// ── Maßnahmen-/Aktivitäten-Store (localStorage) ──
const SfStore = {
  key: 'solver.sfm', list: [], subs: new Set(),
  load() { try { const s = JSON.parse(localStorage.getItem(this.key) || 'null'); this.list = Array.isArray(s) ? s : this.seed(); } catch (e) { this.list = this.seed(); } if (!localStorage.getItem(this.key)) this.persist(); return this.list; },
  persist() { try { localStorage.setItem(this.key, JSON.stringify(this.list)); } catch (e) {} },
  sub(fn) { this.subs.add(fn); return () => this.subs.delete(fn); },
  emit() { this.persist(); this.subs.forEach(fn => fn()); },
  add(a) { this.list = [{ id: 'a' + Date.now() + Math.floor(Math.random() * 999), ts: new Date().toISOString(), ...a }, ...this.list]; this.emit(); },
  update(id, patch) { this.list = this.list.map(a => a.id === id ? { ...a, ...patch } : a); this.emit(); },
  remove(id) { this.list = this.list.filter(a => a.id !== id); this.emit(); },
  seed() {
    const d = (o) => { const x = new Date('2026-07-17T00:00:00Z'); x.setUTCDate(x.getUTCDate() + o); return x.toISOString().slice(0, 10); };
    return [
      { id: 's1', ts: d(-2), cat: 'S', titel: 'Beleuchtung Hallenabschnitt 1 prüfen', owner: 'Ingo Instandhaltung', due: d(0), status: 'arbeit', ref: 'Arbeitssicherheit', note: 'Flackernde Leuchte über Anlage CTX 4' },
      { id: 's2', ts: d(-5), cat: 'Q', titel: 'Arbeitsanweisungen aktualisieren', owner: 'Anton AV', due: d(1), status: 'offen', ref: 'Eskalation', note: '' },
      { id: 's3', ts: d(-1), cat: 'Q', titel: 'Umstellung auf Umlaufbehälter', owner: 'Lars Logistik', due: d(3), status: 'offen', ref: 'Eskalation', note: '' },
      { id: 's4', ts: d(-3), cat: 'C', titel: 'OEE-Abweichung CTX 4 analysieren', owner: 'TK', due: d(2), status: 'arbeit', ref: 'OEE-Abweichung', note: 'Rüstzeiten zu hoch' },
      { id: 's5', ts: d(-4), cat: 'C', titel: 'Technische Störung Fräszentrum C42', owner: 'Ingo Instandhaltung', due: d(0), status: 'offen', ref: 'Technische Störungen', note: 'Spindellager' },
      { id: 's6', ts: d(-8), cat: 'D', titel: 'Liefertreue Mo/Di verbessern', owner: 'AG', due: d(4), status: 'offen', ref: 'Liefertreue', note: '' },
      { id: 's7', ts: d(-10), cat: 'P', titel: 'Schichtplan KW30 abstimmen', owner: 'VM', due: d(-1), status: 'erledigt', ref: 'Anwesenheit', note: '' },
    ];
  },
};
SfStore.load();

function SfCard({ letter, title, badge, children }) {
  return (
    <div style={{ height: '100%', background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 10, boxShadow: 'var(--shadow)', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px', borderBottom: '1px solid var(--line)' }}>
        <span style={{ display: 'grid', placeItems: 'center', width: 26, height: 26, borderRadius: 6, background: catColors[letter] || 'var(--ink-2)', color: '#fff', fontWeight: 700, fontSize: 13, fontFamily: 'var(--mono)' }}>{letter}</span>
        <span style={{ fontWeight: 600, fontSize: 14 }}>{title}</span>
        {badge != null && badge > 0 && <span className="num" style={{ marginLeft: 'auto', display: 'grid', placeItems: 'center', minWidth: 22, height: 22, padding: '0 6px', borderRadius: 99, background: SF.red, color: '#fff', fontSize: 12, fontWeight: 700, fontFamily: 'var(--mono)' }}>{badge}</span>}
      </div>
      <div style={{ flex: 1, padding: 12, minHeight: 0 }}>{children}</div>
    </div>
  );
}

// S — Arbeitssicherheit: Monatskalender mit Ampeltagen
function SafetyCal({ onDay }) {
  const [, force] = useSfS(0);
  const store = window.__sfSafety || (window.__sfSafety = { red: new Set([9]) });
  const days = Array.from({ length: 31 }, (_, i) => i + 1);
  const amber = new Set([3]); const off = new Set([22, 23, 24, 25, 26, 27, 28, 29, 30, 31]);
  const toggleDay = (d, e) => {
    e.stopPropagation();
    if (store.red.has(d)) store.red.delete(d);
    else { store.red.add(d); if (onDay) onDay(d); }
    force(n => n + 1);
  };
  const cell = (d) => {
    const isRed = store.red.has(d);
    const st = isRed ? SF.redBg : amber.has(d) ? SF.amberBg : off.has(d) ? SF.none : SF.greenBg;
    const tc = isRed ? SF.red : amber.has(d) ? SF.amber : off.has(d) ? 'var(--muted)' : SF.green;
    return <div key={d} onClick={(e) => toggleDay(d, e)} onContextMenu={e => window.kikiMenu(e, { id: 'S-Tag-' + d, label: `Arbeitssicherheit · Tag ${d}`, kind: 'SFM' })} title={isRed ? `Tag ${d}: Arbeitsunfall gemeldet — klicken zum Zurücksetzen` : `Tag ${d} — klicken meldet einen Arbeitsunfall`} style={{ aspectRatio: '1', display: 'grid', placeItems: 'center', borderRadius: 4, background: st, color: tc, fontFamily: 'var(--mono)', fontSize: 11.5, fontWeight: 600, cursor: 'pointer' }}>{d}</div>;
  };
  return <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 4 }}>{days.map(cell)}</div>;
}

function SfStat({ icon, value, label, tone }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '8px 4px' }}>
      <span style={{ display: 'grid', placeItems: 'center', width: 34, height: 34, borderRadius: 8, background: 'var(--surface-2)', color: tone || 'var(--ink-2)', flex: '0 0 auto' }}><Icon name={icon} size={19} /></span>
      <span className="num" style={{ fontFamily: 'var(--mono)', fontSize: 30, fontWeight: 700, color: tone || 'var(--ink)', minWidth: 34, textAlign: 'right' }}>{value}</span>
      <span style={{ fontSize: 12.5, color: 'var(--ink-2)', lineHeight: 1.3 }}>{label}</span>
    </div>
  );
}

function EscItem({ title, who, since, onClick }) {
  return (
    <div onClick={(e) => { if (onClick) { e.stopPropagation(); onClick(); } }} onContextMenu={e => window.kikiMenu(e, { id: title, label: 'Eskalation · ' + title, kind: 'SFM' })}
      style={{ display: 'flex', gap: 10, padding: '9px 10px', borderLeft: '3px solid ' + SF.red, background: 'var(--surface-2)', borderRadius: '0 6px 6px 0', marginBottom: 8, cursor: onClick ? 'pointer' : 'default' }}>
      <span style={{ width: 30, height: 30, borderRadius: 99, background: 'var(--line-2)', flex: '0 0 auto' }} />
      <div style={{ minWidth: 0 }}>
        <div style={{ fontSize: 12.5, color: 'var(--ink)', fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{title}</div>
        <div style={{ fontSize: 11.5, color: 'var(--accent-ink)' }}>{who} <span style={{ color: 'var(--muted)' }}>· seit {since}</span></div>
      </div>
    </div>
  );
}

// P — Anwesenheit: Personen × Wochentage, je Arbeitssystem, klickbare Ampel + Kopfzahl
function Attendance({ onCell }) {
  const [, force] = useSfS(0);
  const systems = (window.WORK_SYSTEMS || []).map(w => w.short || w.name);
  const store = window.__sfAtt || (window.__sfAtt = { sys: systems[0] || 'CTX 4', data: {} });
  const [sys, setSysState] = useSfS(store.sys);
  const setSys = (s) => { store.sys = s; setSysState(s); };
  const team = ['SM', 'VM', 'TK', 'AG', 'LB'];
  const wd = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
  const order = ['green', 'amber', 'red', 'off'];
  const bgOf = { green: SF.greenBg, amber: SF.amberBg, red: SF.redBg, off: SF.none };
  const key = (r, c) => sys + ':' + r + ':' + c;
  const stateOf = (r, c) => { const k = key(r, c); if (store.data[k]) return store.data[k]; if (c >= 5) return 'off'; const v = ((sys.length + r * 7 + c * 3) % 10); return v === 2 ? 'red' : v === 5 ? 'amber' : 'green'; };
  const cycle = (r, c, e) => { e.stopPropagation(); const cur = stateOf(r, c); store.data[key(r, c)] = order[(order.indexOf(cur) + 1) % order.length]; force(n => n + 1); };
  // Anwesende je Tag = grüne Zellen
  const presentOn = (c) => team.reduce((n, _, r) => n + (stateOf(r, c) === 'green' ? 1 : 0), 0);

  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
        <select value={sys} onClick={e => e.stopPropagation()} onChange={e => { e.stopPropagation(); setSys(e.target.value); }} style={{ height: 28, padding: '0 8px', borderRadius: 6, border: '1px solid var(--line-2)', background: 'var(--surface)', color: 'var(--ink)', fontSize: 12, fontWeight: 600, maxWidth: '100%' }}>
          {systems.map(s => <option key={s} value={s}>{s}</option>)}
        </select>
        <span className="label" style={{ fontSize: 9.5, marginLeft: 'auto' }}>Klick = Status</span>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '28px repeat(7, 1fr)', gap: 4, marginBottom: 4 }}>
        <span />{wd.map(d => <span key={d} className="label" style={{ fontSize: 9.5, textAlign: 'center' }}>{d}</span>)}
      </div>
      {team.map((p, r) => (
        <div key={p} style={{ display: 'grid', gridTemplateColumns: '28px repeat(7, 1fr)', gap: 4, marginBottom: 4 }}>
          <span style={{ display: 'grid', placeItems: 'center', width: 22, height: 22, borderRadius: 99, background: 'var(--accent)', color: 'var(--accent-ink)', fontSize: 9.5, fontWeight: 700, fontFamily: 'var(--mono)' }}>{p}</span>
          {wd.map((d, c) => <div key={c} onClick={(e) => cycle(r, c, e)} onContextMenu={e => window.kikiMenu(e, { id: 'P-' + sys + '-' + p + '-' + d, label: `Anwesenheit ${sys} · ${p} ${d}`, kind: 'SFM' })} title={`${p} · ${d} (${sys}) — klicken wechselt Status`} style={{ aspectRatio: '1', borderRadius: 4, background: bgOf[stateOf(r, c)], cursor: 'pointer' }} />)}
        </div>
      ))}
      <div style={{ display: 'grid', gridTemplateColumns: '28px repeat(7, 1fr)', gap: 4, marginTop: 6, paddingTop: 6, borderTop: '1px solid var(--line)' }}>
        <span className="label" style={{ fontSize: 8.5, alignSelf: 'center' }}>MA</span>
        {wd.map((d, c) => <span key={c} className="num" style={{ fontFamily: 'var(--mono)', fontSize: 12, fontWeight: 700, textAlign: 'center', color: c >= 5 ? 'var(--muted)' : 'var(--good-ink)' }}>{presentOn(c)}</span>)}
      </div>
    </div>
  );
}

// C — OEE-Abweichung: Tornado je Maschine (Ist − Ziel)
function OeeDeviation() {
  const rows = [
    { m: 'CTX 4', d: -6 }, { m: 'G220', d: -3 }, { m: 'C42', d: -2 },
    { m: 'AS-1', d: 4 }, { m: 'EC-3', d: 6 }, { m: 'QS', d: 8 }, { m: 'Härterei', d: 5 },
  ];
  const max = 12;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {rows.map(r => (
        <div key={r.m} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span className="num" style={{ width: 58, fontSize: 10.5, fontFamily: 'var(--mono)', color: 'var(--ink-2)', textAlign: 'right' }}>{r.m}</span>
          <div style={{ flex: 1, position: 'relative', height: 15, background: 'var(--surface-2)', borderRadius: 3 }}>
            <div style={{ position: 'absolute', left: '50%', top: 0, bottom: 0, borderLeft: '1px solid var(--line-2)' }} />
            <div style={{ position: 'absolute', top: 2, bottom: 2, borderRadius: 2,
              left: r.d < 0 ? (50 + r.d / max * 50) + '%' : '50%', width: Math.abs(r.d) / max * 50 + '%',
              background: r.d < 0 ? SF.red : SF.green }} />
          </div>
          <span className="num" style={{ width: 30, fontSize: 10.5, fontFamily: 'var(--mono)', color: r.d < 0 ? SF.red : SF.green, textAlign: 'right' }}>{r.d > 0 ? '+' : ''}{r.d}</span>
        </div>
      ))}
    </div>
  );
}

// D — Liefertreue: Tagesbalken gegen Zielband
function DeliveryBars() {
  const data = [{ d: 'Mo', v: 88 }, { d: 'Di', v: 91 }, { d: 'Mi', v: 97 }, { d: 'Do', v: 99 }, { d: 'Fr', v: 96 }, { d: 'Mo', v: 84 }, { d: 'Di', v: 90 }];
  const H = 150, top = 12, bot = 22, plot = H - top - bot;
  const col = (v) => v >= 95 ? SF.green : v >= 90 ? SF.amber : SF.red;
  return (
    <svg viewBox={`0 0 300 ${H}`} preserveAspectRatio="none" style={{ width: '100%', height: plot + bot + top, fontFamily: 'var(--mono)' }}>
      <rect x="0" y={top} width="300" height={plot * 0.1} fill="color-mix(in oklch, var(--good) 22%, transparent)" />
      {data.map((b, i) => { const w = 300 / data.length, x = i * w, h = (b.v / 100) * plot; return (
        <g key={i}>
          <rect x={x + w * 0.18} y={top + plot - h} width={w * 0.64} height={h} rx="2" fill={col(b.v)} />
          <text x={x + w / 2} y={H - 7} textAnchor="middle" style={{ fontSize: 11, fill: 'var(--muted)' }}>{b.d}</text>
        </g>
      ); })}
    </svg>
  );
}

// C — Technische Störungen: Verlauf KW-1 vs. aktuell + Tagestabelle
function DisruptionTrend() {
  const kwPrev = [3, 5, 9, 6, 8, 3, 0];
  const kwAkt = [7, 11, 18, null, null, null, null];
  const wd = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
  const max = 20, H = 120, top = 8, bot = 6, plot = H - top - bot, W = 300;
  const x = (i) => 8 + i / 6 * (W - 16), y = (v) => top + plot * (1 - v / max);
  const line = (arr) => arr.map((v, i) => v == null ? null : `${i && arr[i - 1] != null ? 'L' : 'M'}${x(i).toFixed(0)} ${y(v).toFixed(0)}`).filter(Boolean).join(' ');
  return (
    <div>
      <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" style={{ width: '100%', height: H }}>
        <rect x="0" y={top} width={W} height={plot * 0.45} fill="color-mix(in oklch, var(--bad) 16%, transparent)" />
        <rect x="0" y={top + plot * 0.45} width={W} height={plot * 0.55} fill="color-mix(in oklch, var(--good) 16%, transparent)" />
        <path d={line(kwPrev)} fill="none" stroke="var(--muted)" strokeWidth="2" />
        <path d={line(kwAkt)} fill="none" stroke="#3269B4" strokeWidth="2.4" />
        {kwAkt.map((v, i) => v == null ? null : <circle key={i} cx={x(i)} cy={y(v)} r="3" fill="#3269B4" />)}
      </svg>
      <div style={{ display: 'grid', gridTemplateColumns: '34px repeat(7, 1fr)', gap: 3, marginTop: 8 }}>
        <span className="label" style={{ fontSize: 9, alignSelf: 'center' }}>KW</span>
        {wd.map(d => <span key={d} className="num" style={{ fontFamily: 'var(--mono)', fontSize: 10.5, textAlign: 'center', color: 'var(--muted)' }}>{d}</span>)}
        <span className="num" style={{ fontFamily: 'var(--mono)', fontSize: 10.5, background: SF.amberBg, borderRadius: 3, textAlign: 'center', color: SF.amber, fontWeight: 700 }}>-1</span>
        {kwPrev.map((v, i) => <span key={i} className="num" style={{ fontFamily: 'var(--mono)', fontSize: 11, textAlign: 'center', color: 'var(--ink-2)' }}>{v}</span>)}
        <span className="num" style={{ fontFamily: 'var(--mono)', fontSize: 10.5, background: SF.amberBg, borderRadius: 3, textAlign: 'center', color: SF.amber, fontWeight: 700 }}>akt.</span>
        {kwAkt.map((v, i) => <span key={i} className="num" style={{ fontFamily: 'var(--mono)', fontSize: 11, textAlign: 'center', color: v != null && v > 10 ? SF.red : 'var(--ink)', fontWeight: v != null ? 600 : 400 }}>{v == null ? '' : v}</span>)}
      </div>
    </div>
  );
}

function InfoItem({ who, when, text, onRemove }) {
  return (
    <div style={{ display: 'flex', gap: 10, marginBottom: 10 }}>
      <span style={{ width: 30, height: 30, borderRadius: 99, background: 'var(--line-2)', flex: '0 0 auto' }} />
      <div>
        <div style={{ fontSize: 10.5, color: 'var(--accent-ink)', fontWeight: 600 }}>{who} <span style={{ color: 'var(--muted)', fontWeight: 400 }}>· {when}</span></div>
        <div style={{ fontSize: 12.5, color: 'var(--ink)', marginTop: 1 }}>{text}</div>
      </div>
      {onRemove && <button onClick={onRemove} title="Löschen" style={{ marginLeft: 'auto', border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--muted)', flex: '0 0 auto' }}><Icon name="trash" size={13} /></button>}
    </div>
  );
}

const InfoStore = {
  key: 'solver.sfInfo', list: null,
  load() { if (this.list) return this.list; try { const s = JSON.parse(localStorage.getItem(this.key) || 'null'); this.list = Array.isArray(s) ? s : [{ id: 'i1', who: 'Fabienne Facility', when: 'Heute', text: 'Parkplatz C für 2 Wochen gesperrt' }, { id: 'i2', who: 'Max Manager', when: 'seit 1 Tag', text: 'Kundenbesuch nächste Woche' }]; } catch (e) { this.list = []; } return this.list; },
  save() { try { localStorage.setItem(this.key, JSON.stringify(this.list)); } catch (e) {} },
};

function InfoPanel() {
  const [, force] = useSfS(0);
  const [adding, setAdding] = useSfS(false);
  const [who, setWho] = useSfS('');
  const [text, setText] = useSfS('');
  const list = InfoStore.load();
  const add = () => { if (!text.trim()) return; InfoStore.list = [{ id: 'i' + Date.now(), who: who.trim() || 'Team', when: 'Heute', text: text.trim() }, ...InfoStore.list]; InfoStore.save(); setWho(''); setText(''); setAdding(false); force(n => n + 1); };
  const del = (id) => { InfoStore.list = InfoStore.list.filter(x => x.id !== id); InfoStore.save(); force(n => n + 1); };
  const fld = { width: '100%', boxSizing: 'border-box', height: 32, padding: '0 9px', border: '1px solid var(--line-2)', borderRadius: 6, fontSize: 12.5, background: 'var(--surface)', color: 'var(--ink)', marginBottom: 6 };
  return (
    <div>
      {list.map(it => <InfoItem key={it.id} who={it.who} when={it.when} text={it.text} onRemove={() => del(it.id)} />)}
      {adding ? (
        <div onClick={e => e.stopPropagation()} style={{ marginTop: 4 }}>
          <input value={who} onChange={e => setWho(e.target.value)} placeholder="Von (Name)" style={fld} />
          <textarea value={text} onChange={e => setText(e.target.value)} placeholder="Info-Text…" style={{ ...fld, height: 52, padding: 8, resize: 'vertical' }} />
          <div style={{ display: 'flex', gap: 6 }}>
            <button onClick={() => { setAdding(false); setWho(''); setText(''); }} style={{ flex: 1, height: 30, borderRadius: 6, border: '1px solid var(--line-2)', background: 'var(--surface)', color: 'var(--ink-2)', fontSize: 12, cursor: 'pointer' }}>Abbrechen</button>
            <button onClick={add} style={{ flex: 1, height: 30, borderRadius: 6, border: 'none', background: '#3269B4', color: '#fff', fontSize: 12, fontWeight: 600, cursor: 'pointer' }}>Anlegen</button>
          </div>
        </div>
      ) : (
        <button onClick={(e) => { e.stopPropagation(); setAdding(true); }} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, height: 30, padding: '0 11px', borderRadius: 6, border: '1px dashed var(--line-2)', background: 'transparent', color: 'var(--accent-ink)', fontSize: 12.5, cursor: 'pointer' }}><Icon name="plus" size={13} /> Info anlegen</button>
      )}
    </div>
  );
}

function ShopfloorView() {
  const [prefill, setPrefill] = useSfS(null);
  const openMeasure = (cat, ref) => setPrefill({ cat: cat || 'S', ref: ref || '', _open: Date.now() });
  return (
    <React.Fragment>
      <header style={{ flex: '0 0 auto', display: 'flex', alignItems: 'center', gap: 14, padding: '0 18px', height: 56, background: 'var(--panel)', borderBottom: '1px solid var(--line-2)' }}>
        <span style={{ fontSize: 14.5, fontWeight: 600 }}>Shopfloor Management</span>
        <span className="label">Team-Meeting · SQCDP-Board</span>
        <span className="num" style={{ marginLeft: 'auto', fontFamily: 'var(--mono)', fontSize: 12, color: 'var(--muted)' }}>Do, 17. Juli 2026</span>
      </header>
      <ShopfloorBoard onMeasure={openMeasure} />
      {prefill && <SfMeasureQuick prefill={prefill} clear={() => setPrefill(null)} />}
    </React.Fragment>
  );
}

// Schnell-Anlage einer Maßnahme vom Board aus (öffnet direkt das Formular)
function SfMeasureQuick({ prefill, clear }) {
  return <SfMeasureForm rec={{ cat: prefill.cat, ref: prefill.ref, due: '2026-07-17', status: 'offen', owner: 'SM', titel: '', note: '', esk: /eskalation/i.test(prefill.ref || '') }} onClose={clear} />;
}

function ShopfloorBoard({ onMeasure }) {
  const [, force] = useSfS(0);
  React.useEffect(() => window.SfStore.sub(() => force(n => n + 1)), []);
  const cnt = (cat) => window.SfStore.list.filter(a => a.cat === cat && a.status !== 'erledigt').length;
  return (
    <main style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: 14 }}>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gridAutoRows: '340px', gap: 14 }}>
        <div onClick={() => onMeasure('S', 'Arbeitssicherheit')} style={{ cursor: 'default' }}><SfCard letter="S" title="Arbeitssicherheit" badge={cnt('S')}><SafetyCal onDay={(d) => onMeasure('S', 'Arbeitsunfall · Tag ' + d)} /></SfCard></div>
        <div onClick={() => onMeasure('Q', 'Sofortmaßnahmen')} style={{ cursor: 'pointer' }}><SfCard letter="Q" title="Sofortmaßnahmen">
          <SfStat icon="check" value="3" label="Laufende Maßnahmen" tone="var(--ink)" />
          <SfStat icon="alert" value="0" label="Lösung nicht akzeptiert" tone={SF.green} />
          <SfStat icon="clock" value="3" label="Vorgabezeit überschritten" tone={SF.red} />
        </SfCard></div>
        <SfCard letter="Q" title="Eskalation">
          {window.SfStore.list.filter(m => m.esk && m.status !== 'erledigt').map(m => {
            const days = Math.max(0, Math.round((new Date('2026-07-17') - new Date(m.due)) / 86400000));
            return <EscItem key={m.id} title={m.titel} who={m.owner} since={days > 0 ? days + ' Tagen' : 'heute'} onClick={() => onMeasure(m.cat, 'Eskalation')} />;
          })}
          <EscItem title="Beleuchtung Hallenabschnitt 1…" who="Ingo Instandhaltung" since="12 Tagen" onClick={() => onMeasure('S', 'Eskalation')} />
          <EscItem title="Arbeitsanweisungen aktualisieren" who="Anton AV" since="5 Tagen" onClick={() => onMeasure('Q', 'Eskalation')} />
          <EscItem title="Umstellung auf Umlaufbehälter" who="Lars Logistik" since="2 Tagen" onClick={() => onMeasure('Q', 'Eskalation')} />
        </SfCard>
        <div style={{ cursor: 'default' }}><SfCard letter="P" title="Anwesenheit"><Attendance onCell={(p) => onMeasure('P', 'Anwesenheit · ' + p)} /></SfCard></div>

        <div onClick={() => onMeasure('C', 'OEE-Abweichung')} style={{ cursor: 'pointer' }}><SfCard letter="C" title="OEE-Abweichung" badge={cnt('C')}><OeeDeviation /></SfCard></div>
        <div onClick={() => onMeasure('D', 'Liefertreue')} style={{ cursor: 'pointer' }}><SfCard letter="D" title="Liefertreue"><DeliveryBars /></SfCard></div>
        <div onClick={() => onMeasure('C', 'Technische Störungen')} style={{ cursor: 'pointer' }}><SfCard letter="C" title="Technische Störungen" badge={3}><DisruptionTrend /></SfCard></div>
        <SfCard letter="P" title="Info"><InfoPanel /></SfCard>
      </div>
    </main>
  );
}

Object.assign(window, { ShopfloorView, SfStore, SfActivities });
window.SF_CAT_LABELS = { S: 'Arbeitssicherheit', Q: 'Qualität', C: 'Kosten/Technik', D: 'Liefertreue', P: 'Personal' };

// ── Aktivitäten (Maßnahmen) — Liste + Wochenkalender ──
const SF_WD = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
const sfPad = (n) => String(n).padStart(2, '0');
const sfStartOfWeek = (d) => { const x = new Date(d); const off = (x.getDay() + 6) % 7; x.setDate(x.getDate() - off); x.setHours(0, 0, 0, 0); return x; };
const sfSameDay = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();

function SfActivities({ prefill, clearPrefill }) {
  const [, force] = useSfS(0);
  React.useEffect(() => window.SfStore.sub(() => force(n => n + 1)), []);
  const [q, setQ] = useSfS('');
  const [catF, setCatF] = useSfS('alle');
  const [statusF, setStatusF] = useSfS('offen');
  const [mode, setMode] = useSfS('list');
  const [week, setWeek] = useSfS(sfStartOfWeek(new Date('2026-07-17T00:00:00Z')));
  const [edit, setEdit] = useSfS(null);

  React.useEffect(() => { if (prefill && prefill._open) { setEdit({ cat: prefill.cat, ref: prefill.ref, due: new Date('2026-07-17T00:00:00Z').toISOString().slice(0, 10), status: 'offen', owner: 'SM' }); clearPrefill && clearPrefill(); } }, [prefill]);

  let rows = window.SfStore.list.slice();
  if (catF !== 'alle') rows = rows.filter(a => a.cat === catF);
  if (statusF !== 'alle') rows = rows.filter(a => statusF === 'offen' ? a.status !== 'erledigt' : a.status === 'erledigt');
  if (q.trim()) { const s = q.toLowerCase(); rows = rows.filter(a => (a.titel + ' ' + a.owner + ' ' + (a.ref || '')).toLowerCase().includes(s)); }
  rows.sort((a, b) => (a.due < b.due ? -1 : 1));

  const statusPill = (st) => { const c = st === 'erledigt' ? SF.green : st === 'arbeit' ? SF.amber : SF.red; const bg = st === 'erledigt' ? SF.greenBg : st === 'arbeit' ? SF.amberBg : SF.redBg; return <span style={{ padding: '2px 9px', borderRadius: 99, fontSize: 11, fontWeight: 600, background: bg, color: c }}>{(SF_STATUS.find(s => s[0] === st) || [, st])[1]}</span>; };
  const cyc = (a) => window.SfStore.update(a.id, { status: a.status === 'offen' ? 'arbeit' : a.status === 'arbeit' ? 'erledigt' : 'offen' });
  const overdue = (a) => a.status !== 'erledigt' && a.due < '2026-07-17';

  return (
    <main style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: 14 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 12, flexWrap: 'wrap' }}>
        <input value={q} onChange={e => setQ(e.target.value)} placeholder="Maßnahmen durchsuchen …" style={{ flex: 1, minWidth: 200, maxWidth: 320, height: 36, boxSizing: 'border-box', padding: '0 12px', border: '1px solid var(--line-2)', borderRadius: 8, fontSize: 13, background: 'var(--panel)', color: 'var(--ink)' }} />
        <div style={{ display: 'flex', gap: 5 }}>
          <button onClick={() => setCatF('alle')} style={sfChip(catF === 'alle')}>Alle</button>
          {SF_CATS.map(([c, l]) => <button key={c} onClick={() => setCatF(c)} title={l} style={{ ...sfChip(catF === c), display: 'inline-flex', alignItems: 'center', gap: 5 }}><span style={{ width: 8, height: 8, borderRadius: 2, background: catColors[c] }} />{c}</button>)}
        </div>
        <div style={{ display: 'flex', gap: 5 }}>
          {[['offen', 'Offen'], ['erledigt', 'Erledigt'], ['alle', 'Alle']].map(([s, l]) => <button key={s} onClick={() => setStatusF(s)} style={sfChip(statusF === s)}>{l}</button>)}
        </div>
        <div style={{ display: 'flex', gap: 4, marginLeft: 'auto' }}>
          <button onClick={() => setMode('list')} style={sfChip(mode === 'list')}>Liste</button>
          <button onClick={() => setMode('cal')} style={sfChip(mode === 'cal')}>Kalender</button>
        </div>
        <button onClick={() => setEdit({ cat: 'S', status: 'offen', owner: 'SM', due: '2026-07-17', ref: '' })} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, height: 36, padding: '0 14px', borderRadius: 8, border: 'none', background: '#3269B4', color: '#fff', fontWeight: 600, fontSize: 13, cursor: 'pointer' }}><Icon name="plus" size={15} /> Neue Maßnahme</button>
      </div>

      {mode === 'cal' ? <SfCalWeek rows={window.SfStore.list} week={week} setWeek={setWeek} onEdit={setEdit} />
      : (
        <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 8, boxShadow: 'var(--shadow)', overflow: 'hidden' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
            <thead><tr>{['', 'Maßnahme', 'Kategorie', 'Verantw.', 'Fällig', 'Status', ''].map((h, i) => <th key={i} style={{ padding: '8px 12px', textAlign: 'left', fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '.06em', textTransform: 'uppercase', color: 'var(--muted)', borderBottom: '1px solid var(--line-2)' }}>{h}</th>)}</tr></thead>
            <tbody>
              {rows.map(a => (
                <tr key={a.id} onContextMenu={e => window.kikiMenu(e, { id: a.id, label: a.titel, kind: 'Maßnahme' })} style={{ borderBottom: '1px solid var(--line)' }}>
                  <td style={{ padding: '8px 10px', width: 30 }}><button onClick={() => cyc(a)} title="Status wechseln" style={{ width: 20, height: 20, borderRadius: 5, border: '1px solid var(--line-2)', background: a.status === 'erledigt' ? SF.green : 'var(--surface)', color: '#fff', cursor: 'pointer', display: 'grid', placeItems: 'center' }}>{a.status === 'erledigt' ? <Icon name="check" size={12} /> : ''}</button></td>
                  <td style={{ padding: '8px 12px' }}><div style={{ fontWeight: 500 }}>{a.titel}</div>{a.ref && <div style={{ fontSize: 11, color: 'var(--muted)' }}>{a.ref}</div>}</td>
                  <td style={{ padding: '8px 12px' }}><span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 12 }}><span style={{ width: 9, height: 9, borderRadius: 2, background: catColors[a.cat] }} />{(SF_CATS.find(c => c[0] === a.cat) || [, a.cat])[1]}</span></td>
                  <td style={{ padding: '8px 12px', fontSize: 12.5 }}>{a.owner}</td>
                  <td style={{ padding: '8px 12px', fontFamily: 'var(--mono)', fontSize: 12, color: overdue(a) ? SF.red : 'var(--ink-2)', fontWeight: overdue(a) ? 700 : 400 }}>{window.aDe ? window.aDe(a.due) : a.due}</td>
                  <td style={{ padding: '8px 12px' }}>{statusPill(a.status)}</td>
                  <td style={{ padding: '8px 8px', textAlign: 'right', whiteSpace: 'nowrap' }}>
                    <button onClick={() => setEdit(a)} title="Bearbeiten" style={sfIco}><Icon name="settings" size={14} /></button>
                    <button onClick={() => window.SfStore.remove(a.id)} title="Löschen" style={{ ...sfIco, color: 'var(--muted)' }}><Icon name="trash" size={14} /></button>
                  </td>
                </tr>
              ))}
              {rows.length === 0 && <tr><td colSpan={7} style={{ padding: 30, textAlign: 'center', color: 'var(--muted)' }}>Keine Maßnahmen im Filter.</td></tr>}
            </tbody>
          </table>
        </div>
      )}
      {edit && <SfMeasureForm rec={edit} onClose={() => setEdit(null)} />}
    </main>
  );
}

function SfCalWeek({ rows, week, setWeek, onEdit }) {
  const days = Array.from({ length: 7 }, (_, i) => { const d = new Date(week); d.setDate(d.getDate() + i); return d; });
  const nav = (delta) => { const w = new Date(week); w.setDate(w.getDate() + delta * 7); setWeek(w); };
  const today = new Date('2026-07-17T00:00:00Z');
  const label = days[0].getDate() + '. – ' + days[6].getDate() + '. ' + days[6].toLocaleDateString('de-DE', { month: 'long', year: 'numeric' });
  const onDrop = (day) => (ev) => { ev.preventDefault(); const id = ev.dataTransfer.getData('text/plain'); if (id) window.SfStore.update(id, { due: day.toISOString().slice(0, 10) }); };
  return (
    <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 8, boxShadow: 'var(--shadow)', overflow: 'hidden' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px', borderBottom: '1px solid var(--line)' }}>
        <button onClick={() => nav(-1)} style={sfNav}>‹</button>
        <button onClick={() => setWeek(sfStartOfWeek(new Date('2026-07-17T00:00:00Z')))} style={{ ...sfNav, width: 'auto', padding: '0 12px' }}>Heute</button>
        <button onClick={() => nav(1)} style={sfNav}>›</button>
        <span style={{ marginLeft: 6, fontWeight: 600, fontSize: 13.5 }}>{label}</span>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', minHeight: 320 }}>
        {days.map((d, i) => {
          const list = rows.filter(a => a.due === d.toISOString().slice(0, 10));
          return (
            <div key={i} onDragOver={ev => ev.preventDefault()} onDrop={onDrop(d)} style={{ borderLeft: i ? '1px solid var(--line)' : 'none', minHeight: 300, background: sfSameDay(d, today) ? 'color-mix(in oklch, var(--accent) 10%, transparent)' : 'transparent' }}>
              <div style={{ textAlign: 'center', padding: '8px 4px', borderBottom: '1px solid var(--line)' }}>
                <div className="label" style={{ fontSize: 9.5 }}>{SF_WD[i]}</div>
                <div className="num" style={{ fontFamily: 'var(--mono)', fontSize: 15, fontWeight: 700, color: sfSameDay(d, today) ? 'var(--accent-ink)' : 'var(--ink)' }}>{d.getDate()}</div>
              </div>
              <div style={{ padding: 6, display: 'flex', flexDirection: 'column', gap: 5 }}>
                {list.map(a => (
                  <div key={a.id} draggable onDragStart={ev => ev.dataTransfer.setData('text/plain', a.id)} onClick={() => onEdit(a)} title={a.titel}
                    style={{ borderLeft: '3px solid ' + catColors[a.cat], background: 'var(--surface-2)', borderRadius: '0 5px 5px 0', padding: '5px 7px', cursor: 'pointer', opacity: a.status === 'erledigt' ? 0.55 : 1 }}>
                    <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{a.titel}</div>
                    <div style={{ fontSize: 10, color: 'var(--muted)' }}>{a.owner}</div>
                  </div>
                ))}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function SfMeasureForm({ rec, onClose }) {
  const isNew = !rec.id;
  const [f, setF] = useSfS({ titel: '', cat: 'S', owner: 'SM', due: '2026-07-17', status: 'offen', ref: '', note: '', esk: false, ...rec });
  const set = (k, v) => setF(p => ({ ...p, [k]: v }));
  const canSave = f.titel.trim();
  const save = () => { if (!canSave) return; if (isNew) window.SfStore.add(f); else window.SfStore.update(rec.id, f); onClose(); };
  const fld = { width: '100%', height: 34, boxSizing: 'border-box', padding: '0 10px', border: '1px solid var(--line-2)', borderRadius: 6, fontSize: 13, background: 'var(--surface)', color: 'var(--ink)', fontFamily: 'var(--sans)' };
  const lb = (t) => <div className="label" style={{ marginBottom: 4 }}>{t}</div>;
  return (
    <React.Fragment>
      <div onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'rgba(63,62,61,.34)', zIndex: 60, animation: 'rowIn .15s' }} />
      <div style={{ position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', width: 'min(560px, 94vw)', background: 'var(--surface)', zIndex: 61, borderRadius: 12, boxShadow: '0 24px 64px rgba(63,62,61,.28)', border: '1px solid var(--line-2)', display: 'flex', flexDirection: 'column', animation: 'rowIn .18s' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '15px 18px', borderBottom: '1px solid var(--line)' }}>
          <div style={{ fontWeight: 600, fontSize: 15 }}>{isNew ? 'Neue Maßnahme' : 'Maßnahme bearbeiten'}</div>
          <button onClick={onClose} style={{ marginLeft: 'auto', width: 30, height: 30, border: '1px solid var(--line-2)', borderRadius: 6, background: 'var(--surface)', display: 'grid', placeItems: 'center', color: 'var(--ink-2)', cursor: 'pointer' }}><Icon name="close" size={15} /></button>
        </div>
        <div style={{ padding: 18, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <div style={{ gridColumn: '1 / -1' }}>{lb('Titel')}<input autoFocus value={f.titel} onChange={e => set('titel', e.target.value)} placeholder="z. B. Rüstzeit CTX 4 reduzieren" style={fld} /></div>
          <div>{lb('Kategorie')}<select value={f.cat} onChange={e => set('cat', e.target.value)} style={fld}>{SF_CATS.map(([c, l]) => <option key={c} value={c}>{c} · {l}</option>)}</select></div>
          <div>{lb('Verantwortlich')}<select value={f.owner} onChange={e => set('owner', e.target.value)} style={fld}>{SF_OWNERS.map(o => <option key={o} value={o}>{o}</option>)}</select></div>
          <div>{lb('Fällig')}<input type="date" value={f.due} onChange={e => set('due', e.target.value)} style={fld} /></div>
          <div>{lb('Status')}<select value={f.status} onChange={e => set('status', e.target.value)} style={fld}>{SF_STATUS.map(([s, l]) => <option key={s} value={s}>{l}</option>)}</select></div>
          <div style={{ gridColumn: '1 / -1' }}>{lb('Bezug (Board-Kachel)')}<input value={f.ref} onChange={e => set('ref', e.target.value)} placeholder="z. B. OEE-Abweichung" style={fld} /></div>
          <div style={{ gridColumn: '1 / -1' }}><label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, cursor: 'pointer' }}><input type="checkbox" checked={!!f.esk} onChange={e => set('esk', e.target.checked)} style={{ width: 16, height: 16, accentColor: '#3269B4' }} /> Als Eskalation auf dem Board anzeigen</label></div>
          <div style={{ gridColumn: '1 / -1' }}>{lb('Notiz')}<textarea value={f.note} onChange={e => set('note', e.target.value)} style={{ ...fld, height: 70, padding: 10, resize: 'vertical' }} /></div>
        </div>
        <div style={{ display: 'flex', gap: 8, padding: '14px 18px', borderTop: '1px solid var(--line)' }}>
          <button onClick={onClose} style={{ flex: 1, height: 38, borderRadius: 8, border: '1px solid var(--line-2)', background: 'var(--surface)', color: 'var(--ink-2)', fontWeight: 500, fontSize: 13, cursor: 'pointer' }}>Abbrechen</button>
          <button onClick={save} disabled={!canSave} style={{ flex: 1, height: 38, borderRadius: 8, border: 'none', background: '#3269B4', color: '#fff', fontWeight: 600, fontSize: 13, cursor: canSave ? 'pointer' : 'not-allowed', opacity: canSave ? 1 : 0.5 }}>{isNew ? 'Anlegen' : 'Speichern'}</button>
        </div>
      </div>
    </React.Fragment>
  );
}
const sfChip = (on) => ({ height: 36, padding: '0 12px', borderRadius: 8, fontSize: 12.5, fontWeight: 500, cursor: 'pointer', border: '1px solid ' + (on ? 'var(--accent-ink)' : 'var(--line-2)'), background: on ? 'var(--accent)' : 'var(--panel)', color: on ? 'var(--accent-ink)' : 'var(--ink-2)' });
const sfIco = { width: 28, height: 28, border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--ink-2)', borderRadius: 6, marginLeft: 2 };
const sfNav = { width: 30, height: 30, borderRadius: 6, border: '1px solid var(--line-2)', background: 'var(--surface)', color: 'var(--ink-2)', cursor: 'pointer', fontSize: 15 };
