/* ctor-team-access.jsx — sub-tab «Доступ»: делегирование прав вкладки «Команда»
   Super выдаёт пакет team_profile_editor (CRUD профилей и бригад) БЕЗ аналитики и publish.
   ТЗ §3.1 (делегирование), §3.1.2 (capabilities), §3.1.3 (UI выдачи), §3.1.4 (аудит), §8.1 (матрица). */
const { useState: acUseState } = React;

/* ============ КАНДИДАТЫ (платформенные аккаунты с userId) ============ */
/* Делегатами обычно становятся People Ops, старший менеджер, координатор (§3.1).
   В список попадают пользователи, у кого есть userId — в т.ч. штатные профили команды. */
const ACCESS_USERS_SEED = [
  { id: 'u_lebedeva', name: '—', title: 'People Ops · HR',        platform: 'people_ops', staff: false, seen: 'Сегодня, 11:24', online: true,  hue: 268 },
  { id: 'u_doronin',  name: '—',  title: 'Старший менеджер',       platform: 'manager',    staff: true,  seen: '2 часа назад',    online: true,  hue: 212 },
  { id: 'u_kuznetsova',name:'—',  title: 'Операционный координатор',platform: 'people_ops', staff: false, seen: 'Вчера, 18:02',     online: false, hue: 24  },
  { id: 'u_vlasov',   name: '—',   title: 'Менеджер проекта',       platform: 'manager',    staff: true,  seen: '3 дня назад',     online: false, hue: 158 },
  { id: 'u_karpov',   name: '—',                title: 'Прораб · Бригада «Капитал»', platform: 'foreman', staff: true, seen: '5 дней назад',    online: false, hue: 4   },
];

/* ============ persistence ============ */
const K_ACCESS = 'ctor_team_access';
function loadAccessGrants() {
  try { const r = localStorage.getItem(K_ACCESS); return r ? JSON.parse(r) : {}; } catch (e) { return {}; }
}
function saveAccessGrants(g) { try { localStorage.setItem(K_ACCESS, JSON.stringify(g)); } catch (e) {} }
function countDelegates(g) { return Object.values(g || {}).filter((x) => x && x.editor).length; }

/* ============ матрица capabilities (§3.1.2 / §8.1) ============ */
/* state: 'yes' | 'no' | 'opt' (опционально для делегата) */
const CAP_MATRIX = [
  { cap: 'catalog:team:read',        label: 'Просмотр вкладки «Команда»',        super: 'yes', deleg: 'yes', analyst: 'no'  },
  { cap: 'catalog:team:write',       label: 'Правка профилей, бригад, parent',   super: 'yes', deleg: 'yes', analyst: 'no'  },
  { cap: 'catalog:team:roles:write', label: 'Справочник trade-ролей',            super: 'yes', deleg: 'opt', analyst: 'no'  },
  { cap: 'catalog:subs:write',       label: 'Субподрядчики (запись)',            super: 'yes', deleg: 'opt', analyst: 'no'  },
  { cap: 'catalog:publish',          label: 'Публикация каталога',               super: 'yes', deleg: 'no',  analyst: 'no'  },
  { cap: 'users:activity:read',      label: 'Аналитика активности людей',        super: 'yes', deleg: 'no',  analyst: 'yes' },
  { cap: 'crm:analytics:read',       label: 'CRM / маркетинг-дашборды',          super: 'yes', deleg: 'no',  analyst: 'yes' },
];

/* ============ аудит (§3.1.4) — кто из делегатов что менял ============ */
const AUDIT_META = {
  catalog_team_profile_created: { l: 'Создал профиль',     ic: 'plus',   c: 'var(--success-strong)', bg: 'var(--success-soft)' },
  catalog_team_profile_updated: { l: 'Изменил профиль',    ic: 'pencil', c: 'var(--text-secondary)', bg: 'var(--secondary)' },
  catalog_team_crew_updated:    { l: 'Состав бригады',     ic: 'users',  c: 'var(--primary)',        bg: 'var(--primary-soft)' },
  catalog_team_parent_changed:  { l: 'Перевод под крыло',  ic: 'tree',   c: '#7c3aed',               bg: 'color-mix(in srgb, #7c3aed 12%, transparent)' },
};
const ACCESS_AUDIT_SEED = [
  { id: 'a1', type: 'catalog_team_profile_created', actor: 'u_lebedeva', target: 'Дизайнер · Елена Соболева',          time: 'Сегодня, 11:20' },
  { id: 'a2', type: 'catalog_team_parent_changed',  actor: 'u_lebedeva', target: '—', time: 'Сегодня, 10:58' },
  { id: 'a3', type: 'catalog_team_crew_updated',    actor: 'u_doronin',  target: 'Бригада «Капитал» · +Электрик',      time: 'Вчера, 17:41' },
  { id: 'a4', type: 'catalog_team_profile_updated', actor: 'u_doronin',  target: '—',  time: '20 июня, 14:09' },
  { id: 'a5', type: 'catalog_team_profile_created', actor: 'u_kuznetsova', target: 'Исполнитель · Тимур Яковлев',       time: '19 июня, 09:33' },
];

/* ============ финансовый контур (Б): пакеты бухгалтера ============ */
const FINANCE_USERS_SEED = [
  { id: 'f_sokolova', name: '—', title: 'Главный бухгалтер', seen: 'Сегодня, 09:50', hue: 158 },
  { id: 'f_gushchina', name: '—',   title: 'Помощник бухгалтера', seen: 'Сегодня, 12:10', hue: 286 },
  { id: 'f_titov',    name: '—',     title: 'Финансовый ассистент', seen: '2 дня назад', hue: 40 },
];
/* caps: [label, allowed] */
const FINANCE_PACKAGES = [
  { id: 'accountant', name: 'Бухгалтер', slug: 'accountant',
    desc: 'Полный финансовый контур: счета, платежи, дебиторка, закрытие периода.',
    caps: [['Счета и акты', true], ['Платежи · ввод', true], ['Утверждение платежей', true], ['Дебиторка', true], ['Закрытие периода', true], ['Себестоимость и маржа', true]] },
  { id: 'assistant', name: 'Помощник бухгалтера', slug: 'accountant_assistant',
    desc: 'Операционный ввод и сверка — без утверждения платежей и доступа к марже.',
    caps: [['Счета и акты · ввод', true], ['Платежи · ввод', true], ['Сверка и документы', true], ['Утверждение платежей', false], ['Закрытие периода', false], ['Себестоимость и маржа', false]] },
];
const K_FINANCE = 'ctor_finance_access';
function loadFinanceGrants() { try { const r = localStorage.getItem(K_FINANCE); return r ? JSON.parse(r) : { f_sokolova: 'accountant', f_gushchina: 'assistant' }; } catch (e) { return {}; } }
function saveFinanceGrants(g) { try { localStorage.setItem(K_FINANCE, JSON.stringify(g)); } catch (e) {} }

/* ============ helpers ============ */
function acInitials(n) { return (n || '?').split(/\s+/).map((w) => w[0]).slice(0, 2).join('').toUpperCase(); }
function userById(id) { return ACCESS_USERS_SEED.find((u) => u.id === id); }
const PLATFORM_LABEL = { people_ops: 'People Ops', manager: 'Менеджер', foreman: 'Прораб', designer: 'Дизайнер' };

const ACC_IC = {
  plus:   <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>,
  pencil: <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg>,
  users:  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/></svg>,
  tree:   <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="2" width="6" height="6" rx="1"/><rect x="2" y="16" width="6" height="6" rx="1"/><rect x="16" y="16" width="6" height="6" rx="1"/><path d="M12 8v4M5 16v-2h14v2"/></svg>,
  lock:   <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>,
  check:  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>,
  shield: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z"/></svg>,
};

/* ============ Switch ============ */
function Switch({ on, onChange, disabled }) {
  return (
    <button onClick={(e) => { e.stopPropagation(); if (!disabled) onChange(!on); }} disabled={disabled} role="switch" aria-checked={on}
      style={{
        width: 44, height: 26, borderRadius: 999, border: 'none', padding: 3, cursor: disabled ? 'not-allowed' : 'pointer',
        background: on ? 'var(--ink)' : 'color-mix(in srgb, var(--text-tertiary) 32%, transparent)',
        opacity: disabled ? 0.4 : 1, transition: 'background .18s var(--ease-out)', flexShrink: 0, display: 'flex',
      }}>
      <span style={{
        width: 20, height: 20, borderRadius: '50%', background: '#fff', boxShadow: '0 1px 3px rgba(0,0,0,.25)',
        transform: on ? 'translateX(18px)' : 'translateX(0)', transition: 'transform .18s var(--ease-spring, cubic-bezier(.32,.72,0,1))',
      }} />
    </button>
  );
}

/* ============ ячейка матрицы ============ */
function MatrixCell({ state }) {
  if (state === 'yes')  return <span title="Разрешено" style={{ color: 'var(--success-strong)' }}>{ACC_IC.check}</span>;
  if (state === 'opt')  return <span title="Опционально (включается отдельно)" style={{ fontSize: 11, fontWeight: 800, color: 'var(--warning-strong)', background: 'var(--warning-soft)', padding: '2px 9px', borderRadius: 999 }}>опц.</span>;
  return <span title="Запрещено" style={{ fontSize: 16, color: 'color-mix(in srgb, var(--text-tertiary) 55%, transparent)', fontWeight: 400 }}>—</span>;
}

/* ============ матрица capabilities ============ */
function CapMatrixCard() {
  const cols = [
    { k: 'super',   t: 'Super',    s: 'Полный доступ' },
    { k: 'deleg',   t: 'Делегат',  s: 'Редактор команды' },
    { k: 'analyst', t: 'Аналитик', s: 'marketing_analyst' },
  ];
  return (
    <div style={{ ...ctorStyles.card, padding: 0, overflow: 'hidden' }}>
      <div style={{ padding: '18px 22px 14px' }}>
        <div style={ctorStyles.sectionLabel}>Что даёт каждая роль</div>
        <div style={{ fontSize: 13, color: 'var(--text-tertiary)', marginTop: 5 }}>Делегат «Редактор команды» получает <b style={{ color: 'var(--foreground)' }}>правку профилей</b>, но не публикацию и не аналитику.</div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0,1fr) 92px 92px 100px', alignItems: 'center', padding: '8px 22px', borderTop: '1px solid var(--border-subtle)', borderBottom: '1px solid var(--border-subtle)', background: 'var(--secondary)' }}>
        <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-tertiary)', textTransform: 'uppercase', letterSpacing: '.04em' }}>Возможность</div>
        {cols.map((c) => (
          <div key={c.k} style={{ textAlign: 'center' }}>
            <div style={{ fontSize: 12.5, fontWeight: 800, color: c.k === 'deleg' ? 'var(--primary)' : 'var(--foreground)' }}>{c.t}</div>
            <div style={{ fontSize: 9.5, color: 'var(--text-tertiary)', marginTop: 1 }}>{c.s}</div>
          </div>
        ))}
      </div>
      {CAP_MATRIX.map((row, i) => (
        <div key={row.cap} style={{ display: 'grid', gridTemplateColumns: 'minmax(0,1fr) 92px 92px 100px', alignItems: 'center', padding: '11px 22px', borderBottom: i < CAP_MATRIX.length - 1 ? '1px solid var(--border-subtle)' : 'none', background: row.cap === 'catalog:publish' || row.cap === 'users:activity:read' ? 'color-mix(in srgb, var(--warning-soft) 24%, transparent)' : 'transparent' }}>
          <div>
            <div style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--foreground)' }}>{row.label}</div>
            <code style={{ fontSize: 10.5, color: 'var(--text-tertiary)', fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace' }}>{row.cap}</code>
          </div>
          <div style={{ display: 'flex', justifyContent: 'center' }}><MatrixCell state={row.super} /></div>
          <div style={{ display: 'flex', justifyContent: 'center' }}><MatrixCell state={row.deleg} /></div>
          <div style={{ display: 'flex', justifyContent: 'center' }}><MatrixCell state={row.analyst} /></div>
        </div>
      ))}
    </div>
  );
}

/* ============ превью «что увидит делегат» ============ */
function DelegatePreview({ rolesIncluded }) {
  const topTabs = ['Смета', 'Опции', 'Чек-листы', 'Заметки', 'Связи', 'Команда', 'Замеры', 'Материалы'];
  // делегат видит штат + субподряд; sub-tab «Доступ» ему недоступен (07 §3.1, L8)
  const subTabs = [['Команда (штат)', true], ['Субподрядчики', true], ['Доступ', false]];
  return (
    <div style={{ ...ctorStyles.card, padding: 0, overflow: 'hidden' }}>
      <div style={{ padding: '18px 22px 0' }}>
        <div style={ctorStyles.sectionLabel}>Что увидит делегат</div>
        <div style={{ fontSize: 13, color: 'var(--text-tertiary)', marginTop: 5, marginBottom: 16 }}>Scoped-режим: только вкладка «Команда». Остальные разделы конструктора и публикация скрыты.</div>
      </div>
      {/* mock frame */}
      <div style={{ margin: '0 22px 22px', borderRadius: 14, border: '1px solid var(--border-subtle)', overflow: 'hidden', background: 'var(--card)' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 7, padding: '9px 13px', background: 'var(--secondary)', borderBottom: '1px solid var(--border-subtle)' }}>
          <span style={{ width: 9, height: 9, borderRadius: '50%', background: '#f04e62' }} />
          <span style={{ width: 9, height: 9, borderRadius: '50%', background: '#e8a33a' }} />
          <span style={{ width: 9, height: 9, borderRadius: '50%', background: '#5aad6e' }} />
          <span style={{ fontSize: 11, color: 'var(--text-tertiary)', marginLeft: 8, fontFamily: 'ui-monospace, monospace' }}>/calculator-constructor?tab=team</span>
        </div>
        <div style={{ padding: '14px 14px 16px' }}>
          {/* top tabs — только Команда активна */}
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5, marginBottom: 14 }}>
            {topTabs.map((t) => {
              const active = t === 'Команда';
              return (
                <span key={t} style={{
                  display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 11.5, fontWeight: active ? 800 : 600,
                  padding: '5px 11px', borderRadius: 999,
                  background: active ? 'var(--ink)' : 'transparent', color: active ? '#fff' : 'color-mix(in srgb, var(--text-tertiary) 80%, transparent)',
                  border: active ? 'none' : '1px dashed color-mix(in srgb, var(--text-tertiary) 30%, transparent)',
                }}>
                  {!active && <span style={{ opacity: 0.7 }}>{ACC_IC.lock}</span>}{t}
                </span>
              );
            })}
          </div>
          {/* sub-tabs */}
          <div style={{ display: 'inline-flex', gap: 3, padding: 3, background: 'var(--secondary)', borderRadius: 999, marginBottom: 14 }}>
            {subTabs.map(([l, show], i) => (
              <span key={l} style={{
                fontSize: 11, fontWeight: 700, padding: '5px 12px', borderRadius: 999,
                display: 'inline-flex', alignItems: 'center', gap: 4,
                background: i === 0 ? 'var(--card)' : 'transparent', boxShadow: i === 0 ? 'var(--shadow-raised)' : 'none',
                color: show ? 'var(--foreground)' : 'color-mix(in srgb, var(--text-tertiary) 45%, transparent)',
                textDecoration: show ? 'none' : 'line-through',
              }}>{!show && <span style={{ opacity: 0.7 }}>{ACC_IC.lock}</span>}{l}</span>
            ))}
          </div>
          {/* справочник специальностей — внутри штата, редактируем только с под-тумблером */}
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 11, fontWeight: 700, padding: '4px 11px', borderRadius: 999, marginBottom: 14,
            color: rolesIncluded ? 'var(--success-strong)' : 'color-mix(in srgb, var(--text-tertiary) 70%, transparent)',
            background: rolesIncluded ? 'var(--success-soft)' : 'var(--secondary)' }}>
            {rolesIncluded ? ACC_IC.check : ACC_IC.lock}Справочник специальностей {rolesIncluded ? '· можно править' : '· только просмотр'}
          </div>
          {/* фейковые строки */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {[1, 2].map((r) => (
              <div key={r} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px', borderRadius: 10, border: '1px solid var(--border-subtle)' }}>
                <span style={{ width: 26, height: 26, borderRadius: '50%', background: 'var(--secondary)' }} />
                <span style={{ height: 8, borderRadius: 4, background: 'var(--secondary)', flex: 1, maxWidth: 140 }} />
                <span style={{ marginLeft: 'auto', fontSize: 10.5, fontWeight: 700, color: 'var(--success-strong)', background: 'var(--success-soft)', padding: '2px 9px', borderRadius: 999 }}>можно править</span>
              </div>
            ))}
          </div>
          {/* footer: publish скрыт */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 14, paddingTop: 13, borderTop: '1px dashed var(--border-subtle)' }}>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 11.5, fontWeight: 700, color: 'color-mix(in srgb, var(--text-tertiary) 80%, transparent)', background: 'var(--secondary)', padding: '6px 12px', borderRadius: 999 }}>
              {ACC_IC.lock} Опубликовать — только Super
            </span>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 11.5, fontWeight: 700, color: 'color-mix(in srgb, var(--text-tertiary) 80%, transparent)', background: 'var(--secondary)', padding: '6px 12px', borderRadius: 999 }}>
              {ACC_IC.lock} Активность — скрыта
            </span>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ============ строка пользователя ============ */
function UserAccessRow({ u, grant, onChange, last }) {
  const editor = !!(grant && grant.editor);
  const roles = !!(grant && grant.roles);
  return (
    <div style={{ padding: '14px 0', borderBottom: last ? 'none' : '1px solid var(--border-subtle)' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 13 }}>
        <span style={{ position: 'relative', flexShrink: 0 }}>
          <span style={{ width: 42, height: 42, borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, fontWeight: 700, color: '#fff', background: `hsl(${u.hue} 52% 46%)` }}>{acInitials(u.name)}</span>
          {u.online && <span title="В сети" style={{ position: 'absolute', right: -1, bottom: -1, width: 12, height: 12, borderRadius: '50%', background: 'var(--success-strong)', border: '2px solid var(--card)' }} />}
        </span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
            <span style={{ fontSize: 15, fontWeight: 700, letterSpacing: '-.01em', color: 'var(--foreground)' }}>{u.name}</span>
            <span style={{ fontSize: 10.5, fontWeight: 700, color: 'var(--text-secondary)', background: 'var(--secondary)', padding: '2px 8px', borderRadius: 999 }}>{PLATFORM_LABEL[u.platform] || u.platform}</span>
            {u.staff && <span title="Есть профиль в штате каталога" style={{ fontSize: 10.5, fontWeight: 700, color: 'var(--primary)', background: 'var(--primary-soft)', padding: '2px 8px', borderRadius: 999 }}>из штата</span>}
          </div>
          <div style={{ fontSize: 12.5, color: 'var(--text-tertiary)', marginTop: 2 }}>{u.title} · был: {u.seen}</div>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 11, flexShrink: 0 }}>
          <span style={{ fontSize: 12.5, fontWeight: 700, color: editor ? 'var(--foreground)' : 'var(--text-tertiary)', textAlign: 'right', width: 96, lineHeight: 1.2 }}>
            Редактор команды
          </span>
          <Switch on={editor} onChange={(v) => onChange({ editor: v, roles: v ? roles : false })} />
        </div>
      </div>
      {/* раскрытие: что выдано + опция роли */}
      {editor && (
        <div style={{ marginLeft: 55, marginTop: 12, padding: '13px 15px', borderRadius: 12, background: 'color-mix(in srgb, var(--success-soft) 40%, transparent)', border: '1px solid color-mix(in srgb, var(--success-strong) 18%, transparent)' }}>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 12 }}>
            <CapChip on label="Просмотр" />
            <CapChip on label="Правка профилей и бригад" />
            <CapChip on={roles} label="Справочник Ролей" />
            <CapChip muted label="Без публикации" />
            <CapChip muted label="Без аналитики" />
          </div>
          <label style={{ display: 'flex', alignItems: 'flex-start', gap: 10, cursor: 'pointer' }}>
            <input type="checkbox" checked={roles} onChange={(e) => onChange({ editor: true, roles: e.target.checked })}
              style={{ width: 17, height: 17, marginTop: 1, accentColor: 'var(--ink)', cursor: 'pointer' }} />
            <span>
              <span style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--foreground)' }}>Включая справочник trade-ролей</span>
              <span style={{ display: 'block', fontSize: 12, color: 'var(--text-tertiary)', marginTop: 1 }}>Sub-tab «Роли» с правкой · <code style={{ fontFamily: 'ui-monospace, monospace', fontSize: 11 }}>catalog:team:roles:write</code></span>
            </span>
          </label>
        </div>
      )}
    </div>
  );
}

function CapChip({ on, muted, label }) {
  if (muted) return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 11.5, fontWeight: 700, color: 'color-mix(in srgb, var(--text-tertiary) 85%, transparent)', background: 'color-mix(in srgb, var(--text-tertiary) 12%, transparent)', padding: '3px 10px', borderRadius: 999 }}>
      {ACC_IC.lock}{label}
    </span>
  );
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 11.5, fontWeight: 700, padding: '3px 10px', borderRadius: 999,
      color: on ? 'var(--success-strong)' : 'color-mix(in srgb, var(--text-tertiary) 60%, transparent)',
      background: on ? 'var(--card)' : 'transparent', border: '1px solid ' + (on ? 'color-mix(in srgb, var(--success-strong) 28%, transparent)' : 'color-mix(in srgb, var(--text-tertiary) 22%, transparent)'),
      opacity: on ? 1 : 0.6 }}>
      {on ? ACC_IC.check : ACC_IC.lock}{label}
    </span>
  );
}

/* ============ финансовые пакеты (Б) ============ */
function FinancePackages({ finance, setFinance }) {
  const assign = (uid, pkg) => setFinance((g) => {
    const next = { ...g };
    if (next[uid] === pkg) delete next[uid]; else next[uid] = pkg;
    return next;
  });
  return (
    <div>
      <div style={{ marginBottom: 14 }}>
        <div style={ctorStyles.sectionLabel}>Финансовый контур · пакеты прав</div>
        <p style={{ fontSize: 13.5, color: 'var(--text-secondary)', marginTop: 6, lineHeight: 1.5, maxWidth: 680 }}>
          Бухгалтер и помощник — <b style={{ color: 'var(--foreground)' }}>платформенные аккаунты</b>, не профили сметы. Помощнику выдаётся урезанный пакет: ввод и сверка <b style={{ color: 'var(--foreground)' }}>без</b> утверждения платежей, закрытия периода и доступа к марже.
        </p>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(340px, 1fr))', gap: 22, alignItems: 'start' }}>
        {FINANCE_PACKAGES.map((pkg) => {
          const assigned = FINANCE_USERS_SEED.filter((u) => finance[u.id] === pkg.id);
          return (
            <div key={pkg.id} style={{ ...ctorStyles.card, padding: 0, overflow: 'hidden' }}>
              <div style={{ padding: '16px 20px 14px', borderBottom: '1px solid var(--border-subtle)' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
                  <span style={{ color: pkg.id === 'accountant' ? 'var(--primary)' : 'var(--text-secondary)' }}>{ACC_IC.shield}</span>
                  <span style={{ fontSize: 16, fontWeight: 800, letterSpacing: '-.015em', color: 'var(--foreground)' }}>{pkg.name}</span>
                  <span style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-tertiary)', background: 'var(--secondary)', padding: '2px 8px', borderRadius: 999, marginLeft: 'auto' }}>{assigned.length}</span>
                </div>
                <div style={{ fontSize: 12.5, color: 'var(--text-tertiary)', marginTop: 5 }}>{pkg.desc}</div>
                <code style={{ fontSize: 10.5, color: 'var(--text-tertiary)', fontFamily: 'ui-monospace, monospace' }}>{pkg.slug}</code>
              </div>
              <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--border-subtle)', display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                {pkg.caps.map(([l, ok]) => <CapChip key={l} on={ok} muted={!ok} label={l} />)}
              </div>
              <div style={{ padding: '12px 20px 16px' }}>
                <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-tertiary)', textTransform: 'uppercase', letterSpacing: '.04em', marginBottom: 9 }}>Кому выдан</div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                  {FINANCE_USERS_SEED.map((u) => {
                    const on = finance[u.id] === pkg.id;
                    const otherPkg = finance[u.id] && finance[u.id] !== pkg.id;
                    return (
                      <div key={u.id} style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '7px 0' }}>
                        <span style={{ width: 30, height: 30, borderRadius: '50%', fontSize: 11, fontWeight: 700, color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, background: `hsl(${u.hue} 50% 47%)` }}>{acInitials(u.name)}</span>
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--foreground)' }}>{u.name}</div>
                          <div style={{ fontSize: 11.5, color: 'var(--text-tertiary)' }}>{u.title}{otherPkg ? ' · уже: ' + (FINANCE_PACKAGES.find((p) => p.id === finance[u.id]) || {}).name : ''}</div>
                        </div>
                        <Switch on={on} onChange={() => assign(u.id, pkg.id)} />
                      </div>
                    );
                  })}
                </div>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ============ лента аудита (§3.1.4) ============ */
function AuditFeed({ grants }) {
  // показываем все исторические события; помечаем актёров, у кого сейчас активны права
  return (
    <div style={ctorStyles.card}>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 4, flexWrap: 'wrap' }}>
        <div style={ctorStyles.sectionLabel}>Аудит изменений команды</div>
        <span style={{ fontSize: 12.5, color: 'var(--text-tertiary)' }}>Кто из делегатов менял шаблоны — видно только Super</span>
      </div>
      <div style={{ marginTop: 14, display: 'flex', flexDirection: 'column' }}>
        {ACCESS_AUDIT_SEED.map((ev, i) => {
          const m = AUDIT_META[ev.type];
          const actor = userById(ev.actor);
          const active = !!(grants[ev.actor] && grants[ev.actor].editor);
          return (
            <div key={ev.id} style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '11px 0', borderBottom: i < ACCESS_AUDIT_SEED.length - 1 ? '1px solid var(--border-subtle)' : 'none' }}>
              <span style={{ width: 32, height: 32, borderRadius: 9, display: 'grid', placeItems: 'center', flexShrink: 0, color: m.c, background: m.bg }}>{ACC_IC[m.ic]}</span>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13.5, color: 'var(--foreground)' }}>
                  <span style={{ fontWeight: 700 }}>{m.l}</span> · {ev.target}
                </div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 7, marginTop: 2, fontSize: 12, color: 'var(--text-tertiary)' }}>
                  <span style={{ width: 16, height: 16, borderRadius: '50%', fontSize: 8, fontWeight: 700, color: '#fff', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', background: actor ? `hsl(${actor.hue} 52% 46%)` : '#888' }}>{actor ? acInitials(actor.name) : '?'}</span>
                  {actor ? actor.name : 'Неизвестно'}
                  {!active && <span title="Права делегата сейчас отозваны" style={{ fontSize: 10.5, fontWeight: 700, color: 'var(--text-tertiary)', background: 'var(--secondary)', padding: '1px 7px', borderRadius: 999 }}>права отозваны</span>}
                </div>
              </div>
              <span style={{ fontSize: 12, color: 'var(--text-tertiary)', whiteSpace: 'nowrap', flexShrink: 0, fontVariantNumeric: 'tabular-nums' }}>{ev.time}</span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ============ главная панель ============ */
function AccessPanel({ grants, setGrants }) {
  const setGrant = (uid, patch) => setGrants((g) => {
    const next = { ...g, [uid]: { ...(g[uid] || {}), ...patch } };
    if (!next[uid].editor) delete next[uid];
    return next;
  });
  const [finance, setFinance] = acUseState(() => loadFinanceGrants());
  React.useEffect(() => { saveFinanceGrants(finance); }, [finance]);
  const n = countDelegates(grants);
  const rolesIncluded = Object.values(grants).some((x) => x && x.editor && x.roles);

  const LAC = window.LiveAccessCenter;
  return (
    <div>
      {/* W3: живой центр — учётные записи, матрица, активность, аудит */}
      {LAC && <LAC />}

      {/* заголовок + инвариант */}
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap', marginBottom: 18 }}>
        <div style={{ maxWidth: 620 }}>
          <div style={ctorStyles.sectionLabel}>Делегирование прав · демо-контур</div>
          <p style={{ fontSize: 14, color: 'var(--text-secondary)', marginTop: 7, lineHeight: 1.5 }}>
            Выдайте доверенному сотруднику право вести профили и бригады во вкладке «Команда» — <b style={{ color: 'var(--foreground)' }}>без</b> доступа к публикации каталога, аналитике активности и CRM.
          </p>
        </div>
        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 10, padding: '11px 16px', borderRadius: 14, background: 'var(--glass-bg-strong)', border: '1px solid var(--glass-border)' }}>
          <span style={{ color: 'var(--primary)' }}>{ACC_IC.shield}</span>
          <span><b style={{ fontSize: 22, fontWeight: 800, color: 'var(--foreground)', fontVariantNumeric: 'tabular-nums' }}>{n}</b> <span style={{ fontSize: 13, color: 'var(--text-tertiary)' }}>{n === 1 ? 'делегат' : (n >= 2 && n <= 4 ? 'делегата' : 'делегатов')}</span></span>
        </div>
      </div>

      {/* инвариант-плашка */}
      <div style={{ display: 'flex', alignItems: 'flex-start', gap: 11, padding: '13px 16px', borderRadius: 12, background: 'color-mix(in srgb, var(--warning-soft) 55%, transparent)', border: '1px solid color-mix(in srgb, var(--warning-strong) 22%, transparent)', marginBottom: 24 }}>
        <span style={{ color: 'var(--warning-strong)', flexShrink: 0, marginTop: 1 }}>{ACC_IC.lock}</span>
        <div style={{ fontSize: 13, color: 'var(--text-secondary)', lineHeight: 1.5 }}>
          Делегат сохраняет только <b style={{ color: 'var(--foreground)' }}>черновик</b>. Публикацию каталога подтверждает Super — и видит правки делегата в diff группы «Команда». Аналитика активности и CRM-дашборды делегату недоступны.
        </div>
      </div>

      {/* двухколоночный: список + превью */}
      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1.45fr) minmax(320px, 1fr)', gap: 22, alignItems: 'start' }}>
        <div style={ctorStyles.card}>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10, marginBottom: 4 }}>
            <div style={ctorStyles.sectionLabel}>Кто может редактировать команду</div>
            <span style={{ fontSize: 12, color: 'var(--text-tertiary)' }}>{ACCESS_USERS_SEED.length} пользователей с аккаунтом</span>
          </div>
          <div>
            {ACCESS_USERS_SEED.map((u, i) => (
              <UserAccessRow key={u.id} u={u} grant={grants[u.id]} onChange={(patch) => setGrant(u.id, patch)} last={i === ACCESS_USERS_SEED.length - 1} />
            ))}
          </div>
        </div>
        <DelegatePreview rolesIncluded={rolesIncluded} />
      </div>

      {/* матрица */}
      <div style={{ marginTop: 22 }}><CapMatrixCard /></div>

      {/* финансовые пакеты (Б) */}
      <div style={{ marginTop: 30, paddingTop: 26, borderTop: '1px solid var(--border-subtle)' }}>
        <FinancePackages finance={finance} setFinance={setFinance} />
      </div>

      {/* аудит */}
      <div style={{ marginTop: 22 }}><AuditFeed grants={grants} /></div>
    </div>
  );
}

Object.assign(window, { AccessPanel, loadAccessGrants, saveAccessGrants, countDelegates });
