/* ctor-team-staff.jsx — sub-tab «Команда (штат)»: единый authoring профилей каталога
   Секции М·Д·А·П·И на одной странице (ТЗ §4.3). Профиль по умолчанию самостоятельный
   (parentId:null), исполнителя можно перевести «под крыло» прораба/дизайнера/архитектора. */
const { useState: stUseState, useEffect: stUseEffect, useRef: stUseRef } = React;
const stUid = window.ConstructorData.uid;
function stInitials(n) { return (n || '?').split(/\s+/).map((w) => w[0]).slice(0, 2).join('').toUpperCase(); }

/* ============ сиды новых коллекций (parentId по умолчанию null) ============ */
const MANAGERS_SEED = [
  { id: 'mgr_doronin', kind: 'manager', name: '—', phone: '', email: '', note: 'Старший менеджер · бизнес-сегмент', isActive: true },
  { id: 'mgr_vlasov', kind: 'manager', name: '—', phone: '', email: '', note: 'Менеджер проекта', isActive: true },
];
const DESIGNERS_SEED = [
  { id: 'dsg_danilova', kind: 'designer', name: '—', phone: '', email: '', note: 'Студия «Контур»', isActive: true, childExecutorIds: ['ex_larin'] },
];
const ARCHITECTS_SEED = [
  { id: 'arc_lazarev', kind: 'architect', name: '—', phone: '', email: '', note: 'Перепланировки, согласования', isActive: true, childExecutorIds: [] },
];
const EXECUTORS_SEED = [
  { id: 'ex_larin',   kind: 'executor', name: '—',     tradeRoleIds: ['lowvolt'],            parentId: 'dsg_danilova', parentKind: 'designer', grade: 1, load: 'low' },
  { id: 'ex_kovalev', kind: 'executor', name: '—',  tradeRoleIds: ['electrician'],        parentId: null,            parentKind: null,       grade: 0, load: 'mid' },
  { id: 'ex_orlov',   kind: 'executor', name: '—',   tradeRoleIds: ['tiler', 'plasterer'], parentId: null,            parentKind: null,       grade: 1, load: 'low' },
];

const SK = { managers: 'remontpro_team_managers', designers: 'remontpro_team_designers', architects: 'remontpro_team_architects', executors: 'remontpro_team_executors' };
function stLoad(key, seed) { try { const r = localStorage.getItem(key); return r ? JSON.parse(r) : seed.map((x) => ({ ...x })); } catch (e) { return seed.map((x) => ({ ...x })); } }
function stSave(key, v) { try { localStorage.setItem(key, JSON.stringify(v)); } catch (e) {} }

/* ============ мета ============ */
function stGrade(g) { return g <= 1 ? { l: 'Элита ' + g, c: '#7c3aed', bg: 'color-mix(in srgb, #7c3aed 12%, transparent)' } : { l: 'Профи ' + g, c: 'var(--primary)', bg: 'var(--primary-soft)' }; }
const ST_LOAD = { low: { c: 'var(--success-strong)', l: 'свободен' }, mid: { c: 'var(--warning-strong)', l: 'загружен' }, high: { c: 'var(--destructive)', l: 'перегружен' } };
const ST_GRADES = [
  { v: 0, l: 'Элита 0' },
  { v: 1, l: 'Элита 1' },
  { v: 2, l: 'Профи 2' },
  { v: 3, l: 'Профи 3' },
];
const PARENT_LABEL = { foreman: 'Прораб', designer: 'Дизайнер', architect: 'Архитектор' };
/* ============ аватар (инициалы или фото) ============ */
function StaffAvatar({ name, avatarUrl, bg, onClick, title }) {
  const style = { background: bg || 'var(--ink)', cursor: onClick ? 'pointer' : undefined };
  if (avatarUrl) {
    return (
      <img src={avatarUrl} alt="" className="staff-avatar staff-avatar--img" style={style} onClick={onClick} title={title} onError={(ev) => { ev.currentTarget.style.display = 'none'; }} />
    );
  }
  return (
    <span className="staff-avatar" style={style} onClick={onClick} title={title}>{stInitials(name)}</span>
  );
}

function useClickOutside(ref, open, onClose) {
  stUseEffect(() => {
    if (!open) return;
    const onDown = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
    document.addEventListener('mousedown', onDown);
    return () => document.removeEventListener('mousedown', onDown);
  }, [open, onClose]);
}

function GradeChip({ grade, onChange }) {
  const [open, setOpen] = stUseState(false);
  const ref = stUseRef(null);
  useClickOutside(ref, open, () => setOpen(false));
  const g = grade == null ? 2 : grade;
  const gm = stGrade(g);
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button type="button" onClick={() => setOpen((o) => !o)} title="Уровень: Элита 0–1 · Профи 2–3"
        style={{ fontSize: 10.5, fontWeight: 700, color: gm.c, background: gm.bg, padding: '2px 9px', borderRadius: 999, border: 'none', cursor: 'pointer', fontFamily: 'inherit', display: 'inline-flex', alignItems: 'center', gap: 3 }}>
        {gm.l}
        <svg width="8" height="8" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><polyline points="6 9 12 15 18 9" /></svg>
      </button>
      {open && (
        <div style={{ position: 'absolute', top: 'calc(100% + 4px)', left: 0, zIndex: 70, minWidth: 120, background: 'var(--card)', borderRadius: 10, border: '1px solid var(--border-subtle)', boxShadow: 'var(--shadow-pop)', overflow: 'hidden', padding: 4 }}>
          {ST_GRADES.map((opt) => {
            const om = stGrade(opt.v);
            const sel = g === opt.v;
            return (
              <button key={opt.v} type="button" onClick={() => { onChange(opt.v); setOpen(false); }}
                style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 8, padding: '7px 10px', border: 'none', borderRadius: 7, background: sel ? om.bg : 'transparent', cursor: 'pointer', fontFamily: 'inherit', fontSize: 12, fontWeight: sel ? 700 : 500, color: om.c, textAlign: 'left' }}>
                {opt.l}
              </button>
            );
          })}
        </div>
      )}
    </div>
  );
}

function LoadChip({ load, onChange }) {
  const [open, setOpen] = stUseState(false);
  const ref = stUseRef(null);
  useClickOutside(ref, open, () => setOpen(false));
  const lm = ST_LOAD[load] || ST_LOAD.low;
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button type="button" onClick={() => setOpen((o) => !o)} title="Текущая загрузка"
        style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 11, color: 'var(--text-tertiary)', padding: '2px 6px', borderRadius: 999, border: 'none', background: 'transparent', cursor: 'pointer', fontFamily: 'inherit' }}>
        <span style={{ width: 6, height: 6, borderRadius: '50%', background: lm.c }} />{lm.l}
        <svg width="8" height="8" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><polyline points="6 9 12 15 18 9" /></svg>
      </button>
      {open && (
        <div style={{ position: 'absolute', top: 'calc(100% + 4px)', left: 0, zIndex: 70, minWidth: 130, background: 'var(--card)', borderRadius: 10, border: '1px solid var(--border-subtle)', boxShadow: 'var(--shadow-pop)', overflow: 'hidden', padding: 4 }}>
          {Object.entries(ST_LOAD).map(([k, meta]) => (
            <button key={k} type="button" onClick={() => { onChange(k); setOpen(false); }}
              style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 8, padding: '7px 10px', border: 'none', borderRadius: 7, background: load === k ? 'var(--secondary)' : 'transparent', cursor: 'pointer', fontFamily: 'inherit', fontSize: 12, fontWeight: load === k ? 700 : 500, color: 'var(--foreground)', textAlign: 'left' }}>
              <span style={{ width: 6, height: 6, borderRadius: '50%', background: meta.c }} />{meta.l}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

const staffRowShell = {
  background: 'var(--card)',
  borderRadius: 'var(--radius-md, 10px)',
  border: '1px solid var(--border-subtle)',
};

/* ============ маленький toggle статуса ============ */
function StatusToggle({ active, onChange }) {
  return (
    <button onClick={(e) => { e.stopPropagation(); onChange(!active); }} style={{
      display: 'inline-flex', alignItems: 'center', gap: 6, padding: '3px 10px 3px 8px', borderRadius: 999, border: 'none', cursor: 'pointer', fontFamily: 'inherit',
      fontSize: 11.5, fontWeight: 700,
      color: active ? 'var(--success-strong)' : 'var(--text-tertiary)',
      background: active ? 'var(--success-soft)' : 'var(--secondary)',
    }}>
      <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'currentColor' }} />
      {active ? 'Активен' : 'Неактивен'}
    </button>
  );
}

/* ============ обёртка секции ============ */
function StaffSection({ label, count, addLabel, onAdd, children }) {
  return (
    <div className="staff-section">
      <div className="staff-section-head">
        <span style={ctorStyles.sectionLabel}>{label}</span>
        <span className="staff-section-count">{count}</span>
        <div style={{ flex: 1 }} />
        <button type="button" onClick={onAdd} className="staff-section-add" style={ctorStyles.btnGhost}>{Icon.plus} {addLabel}</button>
      </div>
      <div className="staff-row-stack">{children}</div>
    </div>
  );
}

/* ============ строка менеджера (inline expand) ============ */
function ManagerRow({ m, onPatch, onDel, last }) {
  const [open, setOpen] = stUseState(false);
  return (
    <div style={{ ...staffRowShell, padding: 0, overflow: 'hidden' }}>
      <div className="staff-row-main" onClick={() => setOpen((o) => !o)}>
        <span className="staff-avatar" style={{ background: 'hsl(212 52% 46%)' }}>{stInitials(m.name)}</span>
        <div className="staff-row-body" onClick={(e) => e.stopPropagation()}>
          <InlineInput value={m.name} onCommit={(v) => onPatch({ name: v || 'Менеджер' })} style={{ fontSize: 14, fontWeight: 650, letterSpacing: '-.01em', color: 'var(--foreground)', width: '100%' }} />
          <div className="staff-row-sub">{m.note || 'Менеджер проекта'}{m.phone && ' · ' + m.phone}</div>
        </div>
        <div onClick={(e) => e.stopPropagation()}><StatusToggle active={m.isActive} onChange={(v) => onPatch({ isActive: v })} /></div>
        <div onClick={(e) => e.stopPropagation()}><WorkspaceAccess profile={m} kind="manager" /></div>
        <KebabMenu items={[{ icon: Icon.trash, label: 'Удалить менеджера', onClick: onDel, danger: true }]} />
        <span style={{ ...ctorStyles.iconBtn, color: 'var(--text-tertiary)', transform: open ? 'rotate(90deg)' : 'none', transition: 'transform .15s' }}>{Icon.chevron}</span>
      </div>
      {open && (
        <div className="staff-row-expand">
          <label style={{ display: 'flex', flexDirection: 'column', gap: 4, flex: 1, minWidth: 180 }}>
            <span style={ctorStyles.fieldLabel}>Телефон</span>
            <InlineInput value={m.phone} onCommit={(v) => onPatch({ phone: v })} placeholder="+7 …" style={{ ...ctorStyles.input, padding: '8px 10px' }} />
          </label>
          <label style={{ display: 'flex', flexDirection: 'column', gap: 4, flex: 1, minWidth: 180 }}>
            <span style={ctorStyles.fieldLabel}>Email</span>
            <InlineInput value={m.email} onCommit={(v) => onPatch({ email: v })} placeholder="name@…" style={{ ...ctorStyles.input, padding: '8px 10px' }} />
          </label>
          <label style={{ display: 'flex', flexDirection: 'column', gap: 4, flex: 2, minWidth: 220 }}>
            <span style={ctorStyles.fieldLabel}>Заметка</span>
            <InlineInput value={m.note} onCommit={(v) => onPatch({ note: v })} placeholder="Сегмент, специализация" style={{ ...ctorStyles.input, padding: '8px 10px' }} />
          </label>
        </div>
      )}
    </div>
  );
}

/* ============ аккордеон дизайнера / архитектора ============ */
function ParentProfileAccordion({ p, hue, subtitleLabel, onPatch, onDel, executors, setExecutors, roles, last }) {
  const [open, setOpen] = stUseState(false);
  const children = executors.filter((e) => e.parentKind === p.kind && e.parentId === p.id);
  const attach = (exId) => setExecutors((xs) => xs.map((e) => e.id === exId ? { ...e, parentId: p.id, parentKind: p.kind } : e));
  const detach = (exId) => setExecutors((xs) => xs.map((e) => e.id === exId ? { ...e, parentId: null, parentKind: null } : e));
  const createChild = (name) => { const e = { id: stUid('ex'), kind: 'executor', name, tradeRoleIds: [], parentId: p.id, parentKind: p.kind, grade: 2, load: 'low' }; setExecutors((xs) => [...xs, e]); };
  return (
    <div style={{ ...staffRowShell, padding: 0, overflow: 'hidden' }}>
      <div className="staff-row-main" onClick={() => setOpen((o) => !o)}>
        <span className="staff-avatar" style={{ background: `hsl(${hue} 52% 46%)` }}>{stInitials(p.name)}</span>
        <div className="staff-row-body" onClick={(e) => e.stopPropagation()}>
          <InlineInput value={p.name} onCommit={(v) => onPatch({ name: v || 'Профиль' })} style={{ fontSize: 14, fontWeight: 650, letterSpacing: '-.01em', color: 'var(--foreground)', width: '100%' }} />
          <div className="staff-row-sub">{p.note || subtitleLabel}</div>
        </div>
        <span className="staff-team-chip" style={{ color: children.length ? 'var(--primary)' : 'var(--text-tertiary)', background: children.length ? 'var(--primary-soft)' : 'var(--secondary)' }}>
          {children.length ? `${children.length} в команде` : 'без команды'}
        </span>
        <div onClick={(e) => e.stopPropagation()}><StatusToggle active={p.isActive} onChange={(v) => onPatch({ isActive: v })} /></div>
        <div onClick={(e) => e.stopPropagation()}><WorkspaceAccess profile={p} kind={p.kind} /></div>
        <KebabMenu items={[{ icon: Icon.trash, label: 'Удалить профиль', onClick: onDel, danger: true }]} />
        <span style={{ ...ctorStyles.iconBtn, color: 'var(--text-tertiary)', transform: open ? 'rotate(90deg)' : 'none', transition: 'transform .15s' }}>{Icon.chevron}</span>
      </div>
      {open && (
        <div className="staff-row-expand" style={{ display: 'block' }}>
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 12 }}>
            <label style={{ display: 'flex', flexDirection: 'column', gap: 4, flex: 1, minWidth: 170 }}>
              <span style={ctorStyles.fieldLabel}>Телефон</span>
              <InlineInput value={p.phone} onCommit={(v) => onPatch({ phone: v })} placeholder="+7 …" style={{ ...ctorStyles.input, padding: '8px 10px' }} />
            </label>
            <label style={{ display: 'flex', flexDirection: 'column', gap: 4, flex: 1, minWidth: 170 }}>
              <span style={ctorStyles.fieldLabel}>Email</span>
              <InlineInput value={p.email} onCommit={(v) => onPatch({ email: v })} placeholder="name@…" style={{ ...ctorStyles.input, padding: '8px 10px' }} />
            </label>
            <label style={{ display: 'flex', flexDirection: 'column', gap: 4, flex: 2, minWidth: 200 }}>
              <span style={ctorStyles.fieldLabel}>{subtitleLabel}</span>
              <InlineInput value={p.note} onCommit={(v) => onPatch({ note: v })} placeholder={subtitleLabel} style={{ ...ctorStyles.input, padding: '8px 10px' }} />
            </label>
          </div>
          <div style={{ ...ctorStyles.sectionLabel, marginBottom: 10 }}>Состав команды <span style={{ textTransform: 'none', fontWeight: 500, color: 'var(--text-tertiary)' }}>· опционально</span></div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 7, alignItems: 'center' }}>
            {children.map((e) => (
              <span key={e.id} style={{ display: 'inline-flex', alignItems: 'center', gap: 7, padding: '5px 7px 5px 8px', borderRadius: 999, background: 'var(--card)', border: '1px solid var(--c-border)', fontSize: 13, color: 'var(--foreground)' }}>
                <span style={{ width: 20, height: 20, borderRadius: '50%', background: `hsl(${hue} 52% 46%)`, color: '#fff', fontSize: 8.5, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{stInitials(e.name)}</span>
                {e.name}
                <button onClick={() => detach(e.id)} title="Убрать из команды" style={{ ...ctorStyles.iconBtnSm, width: 18, height: 18, color: 'var(--text-tertiary)' }}>{Icon.x}</button>
              </span>
            ))}
            <ExecutorPicker executors={executors} onPick={attach} onCreate={createChild} excludeParentId={p.id} parentKind={p.kind} />
          </div>
        </div>
      )}
    </div>
  );
}

/* ============ picker исполнителей (для дизайнера/архитектора) ============ */
function ExecutorPicker({ executors, onPick, onCreate, excludeParentId, parentKind }) {
  const [open, setOpen] = stUseState(false);
  const [q, setQ] = stUseState('');
  const ref = stUseRef(null);
  stUseEffect(() => {
    if (!open) return;
    const onDown = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onDown);
    return () => document.removeEventListener('mousedown', onDown);
  }, [open]);
  // кандидаты: самостоятельные (parentId:null), не уже у этого родителя
  const cand = executors.filter((e) => (!e.parentId) && e.name.toLowerCase().includes(q.toLowerCase()));
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button onClick={() => setOpen((o) => !o)} style={{ display: 'inline-flex', alignItems: 'center', gap: 5, padding: '5px 12px 5px 9px', borderRadius: 999, background: open ? 'var(--primary-soft)' : 'var(--secondary)', border: '1px solid ' + (open ? 'color-mix(in srgb, var(--primary) 30%, transparent)' : 'transparent'), color: open ? 'var(--primary)' : 'var(--text-secondary)', fontSize: 12.5, fontWeight: 700, cursor: 'pointer', fontFamily: 'inherit' }}>
        {Icon.plus} исполнитель
      </button>
      {open && (
        <div style={{ position: 'absolute', top: 'calc(100% + 6px)', left: 0, width: 290, zIndex: 60, background: 'var(--card)', borderRadius: 14, border: '1px solid var(--border-subtle)', boxShadow: 'var(--shadow-pop)', overflow: 'hidden' }}>
          <div style={{ padding: '10px 12px', borderBottom: '1px solid var(--border-subtle)' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 7, background: 'var(--secondary)', borderRadius: 9, padding: '6px 10px' }}>
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="var(--text-tertiary)" strokeWidth="2"><circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" /></svg>
              <input autoFocus value={q} onChange={(e) => setQ(e.target.value)} placeholder="Имя или создать нового" style={{ border: 'none', outline: 'none', background: 'transparent', fontFamily: 'inherit', fontSize: 12.5, flex: 1, color: 'var(--foreground)' }} />
            </div>
          </div>
          <div style={{ maxHeight: 230, overflowY: 'auto', padding: 5 }}>
            {cand.map((e) => (
              <button key={e.id} onClick={() => { onPick(e.id); setOpen(false); setQ(''); }} style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 9, padding: '8px 9px', borderRadius: 9, border: 'none', background: 'transparent', cursor: 'pointer', fontFamily: 'inherit', textAlign: 'left' }}
                onMouseEnter={(ev) => ev.currentTarget.style.background = 'var(--secondary)'} onMouseLeave={(ev) => ev.currentTarget.style.background = 'transparent'}>
                <span style={{ width: 26, height: 26, borderRadius: '50%', background: 'var(--ink)', color: '#fff', fontSize: 9.5, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{stInitials(e.name)}</span>
                <span style={{ fontSize: 13, fontWeight: 500, color: 'var(--foreground)' }}>{e.name}</span>
                <span style={{ marginLeft: 'auto', fontSize: 11, color: 'var(--text-tertiary)' }}>самостоятельный</span>
              </button>
            ))}
            {q.trim() && (
              <button onClick={() => { onCreate(q.trim()); setOpen(false); setQ(''); }} style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 9, padding: '9px', borderRadius: 9, border: 'none', background: 'var(--primary-soft)', cursor: 'pointer', fontFamily: 'inherit', color: 'var(--primary)', fontWeight: 700, fontSize: 13, marginTop: 4 }}>
                {Icon.plus} Создать «{q.trim()}»
              </button>
            )}
            {cand.length === 0 && !q.trim() && <div style={{ padding: '18px 12px', textAlign: 'center', color: 'var(--text-tertiary)', fontSize: 12.5 }}>Нет свободных исполнителей.<br />Введите имя, чтобы создать.</div>}
          </div>
        </div>
      )}
    </div>
  );
}

/* ============ строка исполнителя ============ */
function ExecutorRow({ e, roles, parentName, onPatch, onDel, onAssign, last }) {
  const [open, setOpen] = stUseState(false);
  return (
    <div className={'staff-exec-block' + (last ? ' is-last' : '')}>
      <div className={'staff-exec-row' + (open ? ' is-open' : '')}>
        <StaffAvatar name={e.name} avatarUrl={e.avatarUrl} bg="var(--ink)" onClick={() => setOpen((o) => !o)} title="Профиль · фото и контакты" />
        <div style={{ minWidth: 150, flex: '1 1 150px' }}>
          <InlineInput value={e.name} onCommit={(v) => onPatch({ name: v || 'Исполнитель' })} style={{ fontSize: 14, fontWeight: 600, color: 'var(--foreground)', width: '100%' }} />
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 2, flexWrap: 'wrap' }}>
            <GradeChip grade={e.grade} onChange={(g) => onPatch({ grade: g })} />
            <LoadChip load={e.load || 'low'} onChange={(l) => onPatch({ load: l })} />
          </div>
        </div>
        {/* trades */}
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5, flex: '1 1 160px', minWidth: 120 }}>
          {e.tradeRoleIds.map((rid) => { const r = roles.find((x) => x.id === rid); if (!r) return null; return (
            <span key={rid} style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 11.5, fontWeight: 600, color: r.color, padding: '2px 9px', borderRadius: 999, background: r.color + '18' }}>
              <span style={{ width: 5, height: 5, borderRadius: '50%', background: r.color }} />{r.name}
              <button type="button" onClick={() => onPatch({ tradeRoleIds: e.tradeRoleIds.filter((x) => x !== rid) })} title="Убрать специальность" style={{ ...ctorStyles.iconBtnSm, width: 16, height: 16, color: r.color, opacity: .7 }}>{Icon.x}</button>
            </span>
          ); })}
          <RolePill roleId={null} roles={roles.filter((r) => !['pm', 'designer', 'architect', 'foreman'].includes(r.id) && !e.tradeRoleIds.includes(r.id))} onChange={(rid) => rid && onPatch({ tradeRoleIds: [...e.tradeRoleIds, rid] })} size="sm" />
        </div>
        {/* parent */}
        <button onClick={onAssign} title="Назначить родителя" style={{ flexShrink: 0, display: 'inline-flex', alignItems: 'center', gap: 6, padding: '4px 10px', borderRadius: 999, border: '1px solid var(--c-border)', background: 'var(--secondary)', cursor: 'pointer', fontFamily: 'inherit', fontSize: 12, fontWeight: 600, color: parentName ? 'var(--foreground)' : 'var(--text-tertiary)' }}>
          {parentName ? <><span style={{ fontWeight: 700, color: 'var(--primary)' }}>{PARENT_LABEL[e.parentKind]}:</span> {parentName}</> : '— самостоятельный'}
        </button>
        <div onClick={(ev) => ev.stopPropagation()}><WorkspaceAccess profile={e} kind="executor" /></div>
        <KebabMenu items={[
          { icon: Icon.copy, label: 'Профиль и контакты', onClick: () => setOpen(true) },
          { icon: Icon.copy, label: 'Назначить родителя', onClick: onAssign },
          { icon: Icon.trash, label: 'Удалить исполнителя', onClick: onDel, danger: true },
        ]} />
        <button type="button" onClick={() => setOpen((o) => !o)} aria-label="Профиль" style={{ ...ctorStyles.iconBtn, color: 'var(--text-tertiary)', transform: open ? 'rotate(90deg)' : 'none', transition: 'transform .15s' }}>{Icon.chevron}</button>
      </div>
      {open && (
        <div className="staff-exec-expand">
          <div style={{ display: 'flex', gap: 14, alignItems: 'flex-start', flexWrap: 'wrap', marginBottom: 12 }}>
            <StaffAvatar name={e.name} avatarUrl={e.avatarUrl} bg="var(--ink)" />
            <div style={{ flex: 1, minWidth: 220 }}>
              <div style={ctorStyles.fieldLabel}>Фото (URL)</div>
              <InlineInput value={e.avatarUrl || ''} onCommit={(v) => onPatch({ avatarUrl: v || undefined })} placeholder="https://…/photo.jpg" style={{ ...ctorStyles.input, padding: '8px 10px', marginTop: 4, width: '100%' }} />
              <div style={{ fontSize: 11, color: 'var(--text-tertiary)', marginTop: 4 }}>Пока только ссылка на изображение. Пустое поле — инициалы.</div>
            </div>
          </div>
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 12 }}>
            <label style={{ display: 'flex', flexDirection: 'column', gap: 4, flex: 1, minWidth: 170 }}>
              <span style={ctorStyles.fieldLabel}>Email</span>
              <InlineInput value={e.email || ''} onCommit={(v) => onPatch({ email: v })} placeholder="name@…" style={{ ...ctorStyles.input, padding: '8px 10px' }} />
            </label>
            <label style={{ display: 'flex', flexDirection: 'column', gap: 4, flex: 1, minWidth: 170 }}>
              <span style={ctorStyles.fieldLabel}>Телефон</span>
              <InlineInput value={e.phone || ''} onCommit={(v) => onPatch({ phone: v })} placeholder="+7 …" style={{ ...ctorStyles.input, padding: '8px 10px' }} />
            </label>
          </div>
          <div style={{ display: 'flex', gap: 16, flexWrap: 'wrap' }}>
            <div>
              <div style={ctorStyles.fieldLabel}>Уровень</div>
              <div style={{ display: 'flex', gap: 4, marginTop: 6, flexWrap: 'wrap' }}>
                {ST_GRADES.map((opt) => {
                  const om = stGrade(opt.v);
                  const sel = (e.grade == null ? 2 : e.grade) === opt.v;
                  return (
                    <button key={opt.v} type="button" onClick={() => onPatch({ grade: opt.v })}
                      style={{ padding: '5px 11px', borderRadius: 999, border: sel ? '1px solid color-mix(in srgb, ' + om.c + ' 40%, transparent)' : '1px solid var(--border-subtle)', background: sel ? om.bg : 'var(--card)', color: om.c, fontSize: 12, fontWeight: sel ? 700 : 500, cursor: 'pointer', fontFamily: 'inherit' }}>
                      {opt.l}
                    </button>
                  );
                })}
              </div>
            </div>
            <div>
              <div style={ctorStyles.fieldLabel}>Загрузка</div>
              <div style={{ display: 'flex', gap: 4, marginTop: 6, flexWrap: 'wrap' }}>
                {Object.entries(ST_LOAD).map(([k, meta]) => {
                  const sel = (e.load || 'low') === k;
                  return (
                    <button key={k} type="button" onClick={() => onPatch({ load: k })}
                      style={{ padding: '5px 11px', borderRadius: 999, border: sel ? '1px solid var(--border-subtle)' : '1px solid var(--border-subtle)', background: sel ? 'var(--secondary)' : 'var(--card)', color: 'var(--foreground)', fontSize: 12, fontWeight: sel ? 700 : 500, cursor: 'pointer', fontFamily: 'inherit', display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                      <span style={{ width: 6, height: 6, borderRadius: '50%', background: meta.c }} />{meta.l}
                    </button>
                  );
                })}
              </div>
            </div>
          </div>
          <div style={{ fontSize: 11.5, color: 'var(--text-tertiary)', marginTop: 12, lineHeight: 1.5 }}>
            <b>Доступ в систему</b> — кнопка справа в строке. Укажите email здесь или в модалке, затем «Открыть доступ» — откроется ЛК исполнителя.
          </div>
        </div>
      )}
    </div>
  );
}

/* ============ модал «Назначить родителя» ============ */
function AssignParentModal({ executor, foremen, designers, architects, roles, onSave, onClose }) {
  const [kind, setKind] = stUseState(executor.parentKind || 'none');
  const [pid, setPid] = stUseState(executor.parentId || '');
  const lists = { foreman: foremen, designer: designers, architect: architects };
  const opt = (k) => (lists[k] || []).map((x) => ({ id: x.id, name: x.name }));
  const choose = (k) => { setKind(k); if (k === 'none') setPid(''); else { const first = opt(k)[0]; setPid(first ? first.id : ''); } };
  const rows = [
    { k: 'none', t: 'Самостоятельно', s: 'Без родителя · доступен любому' },
    { k: 'foreman', t: 'Прораб', s: 'Войдёт в бригаду по trade-роли' },
    { k: 'designer', t: 'Дизайнер', s: 'Помощник дизайнера' },
    { k: 'architect', t: 'Архитектор', s: 'Помощник архитектора' },
  ];
  return ReactDOM.createPortal((
    <div style={ctorStyles.modalBackdrop} onClick={onClose}>
      <div style={ctorStyles.modal} onClick={(e) => e.stopPropagation()}>
        <div style={{ fontSize: 18, fontWeight: 800, letterSpacing: '-.02em', color: 'var(--foreground)' }}>Назначить родителя</div>
        <div style={{ fontSize: 13, color: 'var(--text-tertiary)', marginTop: 3, marginBottom: 18 }}>{executor.name} · перевод под крыло другого профиля</div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {rows.map((r) => {
            const sel = kind === r.k;
            const list = opt(r.k);
            const disabled = r.k !== 'none' && list.length === 0;
            return (
              <div key={r.k} style={{ borderRadius: 12, border: '1px solid ' + (sel ? 'color-mix(in srgb, var(--primary) 45%, transparent)' : 'var(--border-subtle)'), background: sel ? 'var(--primary-soft)' : 'transparent', opacity: disabled ? 0.5 : 1, overflow: 'hidden' }}>
                <button onClick={() => !disabled && choose(r.k)} disabled={disabled} style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 11, padding: '11px 14px', border: 'none', background: 'transparent', cursor: disabled ? 'not-allowed' : 'pointer', fontFamily: 'inherit', textAlign: 'left' }}>
                  <span style={{ width: 18, height: 18, borderRadius: '50%', border: '2px solid ' + (sel ? 'var(--primary)' : 'var(--c-border)'), display: 'grid', placeItems: 'center', flexShrink: 0 }}>{sel && <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--primary)' }} />}</span>
                  <span style={{ flex: 1 }}>
                    <span style={{ fontSize: 14, fontWeight: 700, color: 'var(--foreground)' }}>{r.t}</span>
                    <span style={{ display: 'block', fontSize: 12, color: 'var(--text-tertiary)' }}>{disabled ? 'нет профилей этого типа' : r.s}</span>
                  </span>
                </button>
                {sel && r.k !== 'none' && list.length > 0 && (
                  <div style={{ padding: '0 14px 12px 43px' }}>
                    <select value={pid} onChange={(e) => setPid(e.target.value)} style={{ ...ctorStyles.input, padding: '8px 10px', cursor: 'pointer' }}>
                      {list.map((o) => <option key={o.id} value={o.id}>{o.name}</option>)}
                    </select>
                  </div>
                )}
              </div>
            );
          })}
        </div>
        {kind === 'foreman' && !(executor.tradeRoleIds || []).length && (
          <div style={{ display: 'flex', alignItems: 'flex-start', gap: 9, marginTop: 14, padding: '11px 13px', borderRadius: 10, background: 'var(--warning-soft)', fontSize: 12.5, color: 'var(--text-secondary)', lineHeight: 1.45 }}>
            <span style={{ flexShrink: 0, marginTop: 1 }}>⚠️</span>
            <span>У исполнителя нет специальности — он привяжется к прорабу, но <b>не попадёт в бригаду по роли</b>. Сначала назначьте специальность в строке исполнителя.</span>
          </div>
        )}
        <div style={{ display: 'flex', gap: 10, marginTop: 22, justifyContent: 'flex-end' }}>
          <button onClick={onClose} style={ctorStyles.btnGhost}>Отмена</button>
          <button onClick={() => onSave(kind === 'none' ? { parentId: null, parentKind: null } : { parentId: pid, parentKind: kind })} style={ctorStyles.btnPrimary}>Сохранить</button>
        </div>
      </div>
    </div>
  ), document.body);
}

/* ============ главная панель «Команда (штат)» ============ */
function StaffPanel({ managers, setManagers, designers, setDesigners, architects, setArchitects, executors, setExecutors, foremen, setForemen, roles, setRoles, catalog }) {
  const [addOpen, setAddOpen] = stUseState(false);
  const [assignFor, setAssignFor] = stUseState(null);
  const addRef = stUseRef(null);
  stUseEffect(() => {
    if (!addOpen) return;
    const onDown = (e) => { if (addRef.current && !addRef.current.contains(e.target)) setAddOpen(false); };
    document.addEventListener('mousedown', onDown);
    return () => document.removeEventListener('mousedown', onDown);
  }, [addOpen]);

  const total = managers.length + designers.length + architects.length + foremen.length + executors.length;

  const addManager = () => setManagers((xs) => [...xs, { id: stUid('mgr'), kind: 'manager', name: 'Новый менеджер', phone: '', email: '', note: '', isActive: true }]);
  const addDesigner = () => setDesigners((xs) => [...xs, { id: stUid('dsg'), kind: 'designer', name: 'Новый дизайнер', phone: '', email: '', note: 'Студия', isActive: true, childExecutorIds: [] }]);
  const addArchitect = () => setArchitects((xs) => [...xs, { id: stUid('arc'), kind: 'architect', name: 'Новый архитектор', phone: '', email: '', note: 'Специализация', isActive: true, childExecutorIds: [] }]);
  const addExecutor = () => setExecutors((xs) => [...xs, { id: stUid('ex'), kind: 'executor', name: 'Новый исполнитель', tradeRoleIds: [], parentId: null, parentKind: null, grade: 2, load: 'low' }]);
  const addForeman = () => setForemen((fs) => [...fs, { id: stUid('frm'), name: 'Новый прораб', brigade: 'Бригада', phone: '', durationMul: 1.0, note: '', team: {} }]);

  const ADD_ITEMS = [
    { l: 'Менеджер', fn: addManager }, { l: 'Дизайнер', fn: addDesigner }, { l: 'Архитектор', fn: addArchitect },
    { l: 'Прораб', fn: addForeman }, { l: 'Исполнитель', fn: addExecutor },
  ];

  const parentName = (e) => {
    if (!e.parentId) return null;
    const list = e.parentKind === 'foreman' ? foremen : e.parentKind === 'designer' ? designers : architects;
    const p = (list || []).find((x) => x.id === e.parentId);
    return p ? p.name : null;
  };

  return (
    <div>
      <div className="staff-panel-toolbar">
        <span className="staff-panel-meta">{total} профилей</span>
        <div style={{ flex: 1 }} />
        <div ref={addRef} style={{ position: 'relative' }}>
          <button type="button" onClick={() => setAddOpen((o) => !o)} style={ctorStyles.btnPrimary}>{Icon.plus} Добавить
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" style={{ marginLeft: 2 }}><polyline points="6 9 12 15 18 9" /></svg>
          </button>
          {addOpen && (
            <div style={{ ...ctorStyles.dropdown, minWidth: 200 }}>
              {ADD_ITEMS.map((it) => (
                <button key={it.l} style={ctorStyles.dropdownItem} onClick={() => { it.fn(); setAddOpen(false); }}>
                  <span style={{ color: 'var(--primary)', display: 'flex' }}>{Icon.plus}</span>{it.l}
                </button>
              ))}
            </div>
          )}
        </div>
      </div>

      {/* Менеджеры */}
      <StaffSection label="Менеджеры проекта" count={managers.length} addLabel="Менеджер" onAdd={addManager}>
        {managers.length === 0 ? <EmptyHint text="Пока нет менеджеров" cta="Менеджер" onAdd={addManager} />
          : managers.map((m, i) => <ManagerRow key={m.id} m={m} onPatch={(p) => setManagers((xs) => xs.map((x) => x.id === m.id ? { ...x, ...p } : x))} onDel={() => setManagers((xs) => xs.filter((x) => x.id !== m.id))} last={i === managers.length - 1} />)}
      </StaffSection>

      {/* Дизайнеры */}
      <StaffSection label="Дизайнеры" count={designers.length} addLabel="Дизайнер" onAdd={addDesigner}>
        {designers.length === 0 ? <EmptyHint text="Пока нет дизайнеров" cta="Дизайнер" onAdd={addDesigner} />
          : designers.map((d, i) => <ParentProfileAccordion key={d.id} p={d} hue={268} subtitleLabel="Студия / бюро" executors={executors} setExecutors={setExecutors} roles={roles}
              onPatch={(p) => setDesigners((xs) => xs.map((x) => x.id === d.id ? { ...x, ...p } : x))} onDel={() => setDesigners((xs) => xs.filter((x) => x.id !== d.id))} last={i === designers.length - 1} />)}
      </StaffSection>

      {/* Архитекторы */}
      <StaffSection label="Архитекторы" count={architects.length} addLabel="Архитектор" onAdd={addArchitect}>
        {architects.length === 0 ? <EmptyHint text="Пока нет архитекторов" cta="Архитектор" onAdd={addArchitect} />
          : architects.map((a, i) => <ParentProfileAccordion key={a.id} p={a} hue={200} subtitleLabel="Специализация" executors={executors} setExecutors={setExecutors} roles={roles}
              onPatch={(p) => setArchitects((xs) => xs.map((x) => x.id === a.id ? { ...x, ...p } : x))} onDel={() => setArchitects((xs) => xs.filter((x) => x.id !== a.id))} last={i === architects.length - 1} />)}
      </StaffSection>

      {/* Прорабы и бригады — переиспользуем существующий аккордеон */}
      <StaffSection label="Прорабы и бригады" count={foremen.length} addLabel="Прораб" onAdd={addForeman}>
        <TeamsPanel foremen={foremen} setForemen={setForemen} roles={roles} catalog={catalog} hideHeader />
      </StaffSection>

      {/* Исполнители */}
      <StaffSection label="Исполнители" count={executors.length} addLabel="Исполнитель" onAdd={addExecutor}>
        {executors.length === 0 ? <EmptyHint text="Пока нет исполнителей" cta="Исполнитель" onAdd={addExecutor} />
          : <div style={{ ...staffRowShell, padding: 0, overflow: 'visible' }}>
              {executors.map((e, i) => <ExecutorRow key={e.id} e={e} roles={roles} parentName={parentName(e)}
                onPatch={(p) => setExecutors((xs) => xs.map((x) => x.id === e.id ? { ...x, ...p } : x))}
                onDel={() => setExecutors((xs) => xs.filter((x) => x.id !== e.id))}
                onAssign={() => setAssignFor(e)} last={i === executors.length - 1} />)}
            </div>}
      </StaffSection>

      {assignFor && <AssignParentModal executor={assignFor} foremen={foremen} designers={designers} architects={architects} roles={roles}
        onClose={() => setAssignFor(null)}
        onSave={(patch) => {
          setExecutors((xs) => xs.map((x) => x.id === assignFor.id ? { ...x, ...patch } : x));
          // привязка к прорабу → заносим в бригаду по его специальности
          if (patch.parentKind === 'foreman' && patch.parentId) {
            const trade = (assignFor.tradeRoleIds || [])[0];
            if (trade) setForemen((fs) => fs.map((f) => f.id === patch.parentId
              ? { ...f, team: { ...f.team, [trade]: Array.from(new Set([...(f.team[trade] || []), assignFor.name])) } } : f));
          }
          setAssignFor(null);
        }} />}

      {/* Справочник специальностей — объединён с «Командой» */}
      <SpecialtiesSection roles={roles} setRoles={setRoles} catalog={catalog} />
    </div>
  );
}

/* ============ справочник специальностей (trade-роли), встроен в штат ============ */
function SpecialtiesSection({ roles, setRoles, catalog }) {
  const [open, setOpen] = stUseState(false);
  const addRole = () => setRoles((rs) => [...rs, { id: stUid('role'), name: 'Новая специальность', abbr: 'НС', color: '#e8793a' }]);
  return (
    <div style={{ marginTop: 14, borderTop: '1px solid var(--border-subtle)', paddingTop: 22 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <button onClick={() => setOpen((o) => !o)} style={{ display: 'flex', alignItems: 'center', gap: 9, background: 'none', border: 'none', cursor: 'pointer', fontFamily: 'inherit', padding: 0 }}>
          <span style={{ color: 'var(--text-tertiary)', transform: open ? 'rotate(90deg)' : 'none', transition: 'transform .15s', display: 'flex' }}>{Icon.chevron}</span>
          <span style={ctorStyles.sectionLabel}>Справочник специальностей</span>
          <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--text-tertiary)', background: 'var(--secondary)', padding: '1px 9px', borderRadius: 999 }}>{roles.length}</span>
        </button>
        <div style={{ flex: 1 }} />
        {open && <button onClick={addRole} style={ctorStyles.btnGhost}>{Icon.plus} Специальность</button>}
      </div>
      <div style={{ fontSize: 12.5, color: 'var(--text-tertiary)', marginTop: 6, maxWidth: 620 }}>Trade-роли (ЭЛ, СН…), которыми пользуются исполнители и бригады. Это <b>не</b> доступы — аккаунты на вкладке «Доступ».</div>
      {open && <div style={{ marginTop: 16 }}><RolesPanel roles={roles} setRoles={setRoles} catalog={catalog} hideHeader /></div>}
    </div>
  );
}

function EmptyHint({ text, cta, onAdd }) {
  return (
    <div style={{ padding: '22px 18px', borderRadius: 14, border: '1px dashed var(--c-border)', textAlign: 'center' }}>
      <div style={{ fontSize: 13.5, color: 'var(--text-tertiary)', marginBottom: 12 }}>{text}</div>
      <button onClick={onAdd} style={{ ...ctorStyles.btnGhost, margin: '0 auto' }}>{Icon.plus} {cta}</button>
    </div>
  );
}

/* счёт профилей М+Д+А+И для badge (П=foremen считается отдельно в родителе) */
function staffExtraCount() {
  return stLoad(SK.managers, MANAGERS_SEED).length
    + stLoad(SK.designers, DESIGNERS_SEED).length
    + stLoad(SK.architects, ARCHITECTS_SEED).length
    + stLoad(SK.executors, EXECUTORS_SEED).length;
}

Object.assign(window, { StaffPanel, MANAGERS_SEED, DESIGNERS_SEED, ARCHITECTS_SEED, EXECUTORS_SEED, stLoad, stSave, STAFF_KEYS: SK, staffExtraCount });
