/* global React, Button, Avatar, Overline, Dropdown, Icon */
// Schools.ArtemenkoCRM — Add / Edit client — пошаговая модалка (wizard)

function Field({ label, required, children }) {
  return (
    <div>
      <label style={{ display: 'block', fontSize: 13, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 6 }}>
        {label}{required && <span style={{ color: 'var(--coral)' }}> *</span>}
      </label>
      {children}
    </div>
  );
}

function TextField({ value, onChange, placeholder, mono, autoFocus }) {
  const [focus, setFocus] = React.useState(false);
  const [hover, setHover] = React.useState(false);
  return (
    <input value={value} onChange={e => onChange && onChange(e.target.value)} placeholder={placeholder} autoFocus={autoFocus}
      onFocus={() => setFocus(true)} onBlur={() => setFocus(false)}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{
        width: '100%', boxSizing: 'border-box', borderRadius: 'var(--radius-sm)', padding: '11px 13px',
        border: '1px solid ' + (focus ? 'var(--brand)' : hover ? 'var(--border-strong)' : 'var(--border)'),
        boxShadow: focus ? 'var(--shadow-focus)' : 'none', outline: 'none', background: 'var(--bg-card)',
        fontFamily: mono ? 'var(--font-mono)' : 'var(--font-sans)', fontSize: 14, color: 'var(--text)',
        transform: focus || hover ? 'scale(1.012)' : 'scale(1)', transformOrigin: 'left center',
        transition: 'border-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease)',
      }} />
  );
}

// Phone mask: defaults to +7 template, but the country digit is editable
// (erase 7 → type another) for foreign students. Lightly groups foreign numbers.
function formatPhone(raw) {
  let s = (raw || '').replace(/[^\d+]/g, '');
  if (!s) return '';
  const digits = s.replace(/\+/g, '');
  if (digits === '') return '+';
  if (digits[0] === '7') {
    const d = digits.slice(1, 11);
    let r = '+7';
    if (d.length) r += ' (' + d.slice(0, 3);
    if (d.length > 3) r += ')';
    if (d.length > 3) r += ' ' + d.slice(3, 6);
    if (d.length > 6) r += '-' + d.slice(6, 8);
    if (d.length > 8) r += '-' + d.slice(8, 10);
    return r;
  }
  // foreign country code — keep "+" and light grouping by 3
  return '+' + digits.slice(0, 15).replace(/(.{3})/g, '$1 ').trim();
}

function ContactsEditor({ contacts, onChange, openPicker, max = 4 }) {
  const { CONTACT_TYPES } = window.CRM_DATA;
  const typeOpts = CONTACT_TYPES.map(t => ({ value: t.value, label: t.label }));
  const [removing, setRemoving] = React.useState(null);
  const setOne = (i, key, val) => onChange(contacts.map((c, idx) => idx === i ? { ...c, [key]: val } : c));
  const add = () => { if (contacts.length < max) onChange([...contacts, { type: 'phone', value: '+7 ' }]); };
  const remove = (i) => { setRemoving(i); setTimeout(() => { onChange(contacts.filter((_, idx) => idx !== i)); setRemoving(null); }, 230); };
  const typeLabel = (t) => { const m = CONTACT_TYPES.find(x => x.value === t); return m ? m.label : (t || 'Канал'); };
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
      {contacts.map((c, i) => {
        const meta = CONTACT_TYPES.find(t => t.value === c.type) || {};
        return (
          <div key={i} className={removing === i ? 'om-fly-right' : 'om-fade-in'} style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
            <div style={{ width: 132, flex: 'none' }}>
              <PickerTrigger label={typeLabel(c.type)} onClick={() => openPicker({
                title: 'Канал связи', value: c.type, options: typeOpts, allowCustom: true,
                customPlaceholder: 'Название канала',
                onPick: (v) => onChange(contacts.map((cc, idx) => idx === i ? { ...cc, type: v, value: window.reseedContactValue(v, cc.type, cc.value) } : cc)),
              })} />
            </div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <TextField value={c.value} onChange={v => setOne(i, 'value', window.maskContactValue(c.type, v))} placeholder={meta.ph || '@username или номер'} mono={!!meta.mono} />
            </div>
            <button onClick={() => remove(i)} title="Удалить" style={{ border: 'none', background: 'none', cursor: 'pointer', color: 'var(--text-dim)', display: 'inline-flex', padding: 4, flex: 'none' }}>
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round"><path d="M9.2 9.2l5.6 5.6M14.8 9.2l-5.6 5.6"/></svg>
            </button>
          </div>
        );
      })}
      {contacts.length === 0 && <div style={{ fontSize: 12.5, color: 'var(--text-dim)' }}>Контакты не добавлены</div>}
      {contacts.length < max
        ? <button onClick={add} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '9px 12px', border: '1px dashed var(--border-strong)', borderRadius: 'var(--radius-sm)', background: 'var(--bg-card)', cursor: 'pointer', color: 'var(--brand-ink)', fontSize: 13, fontWeight: 600, fontFamily: 'var(--font-sans)', alignSelf: 'flex-start' }}><Icon name="plus" size={15} />Добавить контакт</button>
        : <div style={{ fontSize: 11.5, color: 'var(--text-dim)' }}>Максимум {max} контакта</div>}
    </div>
  );
}

function AddClientModal({ onClose, onCreate, onSave, client, prefill, onNavSettings }) {
  const { TEACHERS, DIRECTIONS, SOURCES, MANAGERS } = window.CRM_DATA;
  const editing = !!client;
  const seed = client || prefill || null;
  const [shown, setShown] = React.useState(false);
  const [picker, setPicker] = React.useState(null);
  const openPicker = (cfg) => setPicker(cfg);
  const [self, setSelf] = React.useState(seed ? !!seed.self : false);
  const [name, setName] = React.useState(seed ? (seed.child || '') : '');
  const [contacts, setContacts] = React.useState(seed && seed.contacts ? seed.contacts.map(c => ({ ...c })) : []);
  const [parents, setParents] = React.useState(seed && seed.parents && seed.parents.length ? seed.parents.map(p => ({ name: p.name, contacts: (p.contacts || []).map(c => ({ ...c })) })) : [{ name: '', contacts: [] }]);
  const [source, setSource] = React.useState(seed ? (seed.source || 'Сайт') : 'Сайт');
  // Заметка о клиенте. При конвертации заявки сюда приезжает её заметка (prefill.notes) —
  // менеджер видит контекст первого касания и может дополнить перед созданием карточки.
  const [notes, setNotes] = React.useState(seed ? (seed.notes || '') : '');
  const [directions, setDirections] = React.useState(
    seed ? (seed.directions && seed.directions.length ? seed.directions.slice()
      : (seed.subjects && seed.subjects.length ? seed.subjects.slice()
        : (seed.direction ? [seed.direction] : (seed.subject ? [seed.subject] : [])))) : []);
  const addDirection = (v) => { if (!v) return; if (!window.CRM_DATA.DIRECTIONS.includes(v)) window.CRM_DATA.DIRECTIONS.push(v); setDirections(d => d.includes(v) ? d : [...d, v]); };
  const removeDirection = (v) => setDirections(d => d.filter(x => x !== v));
  const [teachers, setTeachers] = React.useState(seed && seed.teachers && seed.teachers.length ? seed.teachers.slice() : (seed && seed.teacher ? [seed.teacher] : []));
  // Карта «преподаватель → какие направления он ведёт у этого ученика».
  const [teacherSubjects, setTeacherSubjects] = React.useState(seed && seed.teacherSubjects ? { ...seed.teacherSubjects } : {});
  // Цена занятия для ученика ЗАВИСИТ ОТ ПЕДАГОГА: { педагог: цена }. Откат — общий lessonPrice.
  const [teacherPrices, setTeacherPrices] = React.useState(seed && seed.teacherPrices ? { ...seed.teacherPrices } : {});
  const setTPrice = (t, v) => setTeacherPrices(m => ({ ...m, [t]: v }));
  const [subjModalFor, setSubjModalFor] = React.useState(null); // имя педагога, для которого выбираем предметы
  const [subjDraft, setSubjDraft] = React.useState([]);          // черновик выбранных направлений
  const [subjConfirm, setSubjConfirm] = React.useState(false);   // подтверждение «двойного» предмета
  // Предметы преподавателя — источник правды его карточка (Сотрудники), храним по имени.
  const teacherTeaches = (name) => { const st = (window.CRM_DATA.STAFF || []).find(s => s.name === name && s.role === 'teacher'); return (st && st.subjects) ? st.subjects : []; };
  // «Фамилия И.О.» для компактных подписей.
  const shortName = (name) => { const p = String(name || '').trim().split(/\s+/); return p.length >= 2 ? `${p[0]} ${p.slice(1).map(w => w[0] + '.').join('')}` : name; };
  const [manager, setManager] = React.useState(seed ? (seed.manager || null) : null);
  const [price, setPrice] = React.useState(seed && seed.defaultPrice != null ? String(seed.defaultPrice) : String(window.DEFAULT_LESSON_PRICE || 1800));
  const [payFormat, setPayFormat] = React.useState('За занятие'); // пока единственный формат (за месяц/курс — в бэклоге)
  const [animal, setAnimal] = React.useState(seed ? (seed.animal || 'rabbit') : 'rabbit');
  const [tone, setTone] = React.useState(seed ? (seed.tone || 'navy') : 'navy');

  React.useEffect(() => { const t = setTimeout(() => setShown(true), 10); return () => clearTimeout(t); }, []);
  const close = () => { setShown(false); setTimeout(onClose, 200); };
  const [pickerCloseReq, setPickerCloseReq] = React.useState(0);

  const ANIMALS = ['rabbit', 'cat', 'bird', 'dog', 'fish', 'horse', 'butterfly', 'paw-print'];
  const TONES = ['navy', 'green', 'gold'];
  const opt = (label, items) => [{ value: null, label }].concat(items.map(v => ({ value: v, label: v })));
  const labelOf = (items, v, fallback) => v == null ? fallback : (items.includes(v) ? v : v);

  const setParent = (i, key, val) => setParents(ps => ps.map((p, idx) => idx === i ? { ...p, [key]: val } : p));
  const addParent = () => setParents(ps => [...ps, { name: '', contacts: [] }]);
  const removeParent = (i) => setParents(ps => ps.filter((_, idx) => idx !== i));

  // Единый экран (как у сотрудников): все секции на одной модалке, без шагов.
  // Цена занятия по педагогу обязательна: у каждого назначенного педагога должна быть цена > 0.
  const teachersMissingPrice = teachers.filter(t => { const v = teacherPrices[t]; const n = parseInt(String(v).replace(/\D/g, ''), 10); return !(n > 0); });
  // Предмет у педагога ОБЯЗАТЕЛЕН: без него непонятно, что он ведёт, и в кабинете преподавателя
  // ученик появляется без предмета. Прикрепить педагога «просто так» нельзя.
  const teachersMissingSubject = teachers.filter(t => !((teacherSubjects[t] || []).length));
  // При конвертации заявки педагог ОБЯЗАТЕЛЕН (нельзя создать клиента из заявки без преподавателя).
  const needTeacher = !!(prefill && prefill.requireTeacher) && teachers.length === 0;
  const canSave = name.trim().length > 0 && teachersMissingPrice.length === 0
    && teachersMissingSubject.length === 0 && !needTeacher;

  // Текущая ставка преподавателя (на сегодня; будущие повышения НЕ учитываются).
  const teacherCurrentRate = (tname) => {
    const st = (window.CRM_DATA.STAFF || []).find(s => s.name === tname && s.role === 'teacher');
    if (!st) return null;
    return window.rateOn ? window.rateOn(st, window.APP_TODAY_ISO || '2026-05-31') : (st.rate || null);
  };
  // Добавление преподавателя: ученик может числиться сразу у нескольких педагогов.
  // При добавлении первого педагога пустую «оплату за занятие» подставляем из его ставки.
  const addTeacher = (v) => {
    if (!v) return;
    setTeachers(ts => ts.includes(v) ? ts : [...ts, v]);
    // Цена занятия по педагогу ОБЯЗАТЕЛЬНА: при добавлении сразу подставляем дефолт (из заявки, если есть, иначе общий).
    setTeacherPrices(m => { if (m[v] != null && String(m[v]).length) return m; const def = (seed && seed.defaultPrice && parseInt(seed.defaultPrice, 10)) || window.DEFAULT_LESSON_PRICE || 1800; return { ...m, [v]: String(def) }; });
    // Сразу спрашиваем, какие из направлений ученика будет вести этот педагог.
    setSubjDraft((teacherSubjects[v] || []).slice());
    setSubjConfirm(false);
    setSubjModalFor(v);
  };
  const removeTeacher = (v) => { setTeachers(ts => ts.filter(t => t !== v)); setTeacherSubjects(m => { const n = { ...m }; delete n[v]; return n; }); setTeacherPrices(m => { const n = { ...m }; delete n[v]; return n; }); };
  // Пикер преподавателя: те, кто ведёт хотя бы один предмет ученика — активны (сверху);
  // остальные — неактивны (серые снизу) с подписью предметов, которые они ведут.
  const buildTeacherPicker = () => {
    const avail = TEACHERS.filter(t => !teachers.includes(t));
    const subsLabel = (t) => { const s = teacherTeaches(t); return s.length ? 'ведёт: ' + s.join(', ') : 'предметы не указаны'; };
    const fits = (t) => directions.length === 0 || teacherTeaches(t).some(s => directions.includes(s));
    const active = avail.filter(fits).map(t => ({ value: t, label: t, sub: subsLabel(t) }));
    const inactive = avail.filter(t => !fits(t)).map(t => ({ value: t, label: t, sub: subsLabel(t), disabled: true, disabledReason: 'Не ведёт предметы ученика' }));
    const note = directions.length === 0
      ? 'Сначала добавьте ученику направления — тогда подойдут только профильные преподаватели.'
      : (inactive.length ? 'Серые преподаватели не ведут ни одного предмета ученика. Чтобы назначить такого — добавьте нужный предмет в его карточке: Сотрудники → профиль → Предметы.' : null);
    return { title: 'Добавить преподавателя', value: null, options: active.concat(inactive), note, onPick: addTeacher };
  };
  const openSubjModal = (v) => { setSubjDraft((teacherSubjects[v] || []).slice()); setSubjConfirm(false); setSubjModalFor(v); };
  // Тогл предмета: разрешён только если педагог реально его ведёт (источник — карточка педагога).
  const toggleSubjDraft = (s) => { if (subjModalFor && !teacherTeaches(subjModalFor).includes(s)) return; setSubjConfirm(false); setSubjDraft(d => d.includes(s) ? d.filter(x => x !== s) : [...d, s]); };
  // Предметы черновика, которые уже ведёт ДРУГОЙ назначенный педагог этого ученика.
  const subjConflicts = () => { if (!subjModalFor) return []; const out = []; subjDraft.forEach(s => { const others = teachers.filter(t => t !== subjModalFor && (teacherSubjects[t] || []).includes(s)); if (others.length) out.push({ subject: s, by: others }); }); return out; };
  const saveSubjModal = () => {
    const conflicts = subjConflicts();
    if (conflicts.length && !subjConfirm) { setSubjConfirm(true); return; } // требуем подтверждение «двойного» предмета
    const v = subjModalFor; setTeacherSubjects(m => ({ ...m, [v]: subjDraft.slice() })); setSubjModalFor(null);
  };

  const numericTP = () => { const o = {}; Object.keys(teacherPrices).forEach(k => { const n = parseInt(String(teacherPrices[k]).replace(/\D/g, ''), 10); if (n) o[k] = n; }); return o; };
  const submit = (recalcMap) => {
    const cleanContacts = (arr) => (arr || []).filter(c => c.value && c.value.trim());
    const payload = {
      child: name || 'Новый клиент', self, contacts: cleanContacts(contacts),
      parents: self ? [] : parents.filter(p => p.name.trim()).map(p => ({ name: p.name, contacts: cleanContacts(p.contacts) })),
      source, direction: directions[0] || null, directions: directions.slice(), teacher: teachers[0] || null, teachers: teachers.slice(), teacherSubjects: { ...teacherSubjects }, teacherPrices: numericTP(), manager,
      animal, tone, notes,
    };
    // recalcMap: { имяПедагога: '__all__' | ISO } — с какого момента применить новую цену к занятиям.
    if (recalcMap && Object.keys(recalcMap).length) payload.priceRecalc = recalcMap;
    if (editing) onSave({ ...client, ...payload }); else onCreate(payload);
  };
  // Animate the modal out before handing off (so close feels finished).
  const doClose = (recalcMap) => { setPicker(null); setShown(false); setTimeout(() => submit(recalcMap), 200); };
  // Очередь подтверждений смены цены: по одному модальному окну на каждого педагога с изменённой ценой.
  const [priceQueue, setPriceQueue] = React.useState(null); // [{teacher, subjects, oldPrice, newPrice}]
  const [priceIdx, setPriceIdx] = React.useState(0);
  const [priceMap, setPriceMap] = React.useState({}); // накопленные ответы { педагог: eff }
  const [priceForm, setPriceForm] = React.useState({ mode: 'today', date: null }); // ответ по текущему окну очереди
  const effPriceFor = (t, tpNum) => (tpNum[t] != null ? tpNum[t] : (parseInt(price.replace(/\D/g, ''), 10) || window.DEFAULT_LESSON_PRICE || 1800));
  const finish = () => {
    if (!editing) { doClose(); return; }
    const tpNum = numericTP();
    const oldTP = (client && client.teacherPrices) || {};
    const oldBase = window.DEFAULT_LESSON_PRICE || 1800;
    const oldEffFor = (t) => (oldTP[t] != null ? oldTP[t] : oldBase);
    // Список педагогов с изменившейся ценой → отдельное окно на каждого.
    const q = [];
    teachers.forEach(t => { const oldP = oldEffFor(t); const newP = effPriceFor(t, tpNum); if (oldP != null && newP != null && oldP !== newP) q.push({ teacher: t, subjects: teacherSubjects[t] || [], oldPrice: oldP, newPrice: newP }); });
    if (q.length) { setPicker(null); setPriceMap({}); setPriceIdx(0); setPriceQueue(q); return; }
    doClose();
  };

  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 50 }}>
      <div onClick={close} style={{ position: 'absolute', inset: 0, background: 'rgba(21,28,46,0.45)', backdropFilter: 'blur(2px)', opacity: shown ? 1 : 0, transition: 'opacity var(--dur) var(--ease)' }} />
      <div style={{ position: 'absolute', top: 0, right: 0, bottom: 0, display: 'flex' }}>
        <div style={{ position: 'relative', width: 0, zIndex: 0 }}>
          <SlidePicker cfg={picker} onClose={() => setPicker(null)} closeReq={pickerCloseReq} />
        </div>
      <div style={{
        position: 'relative', zIndex: 2, width: 460, maxWidth: '100vw', height: '100%', background: 'var(--bg-card)',
        boxShadow: 'var(--shadow-lg)', display: 'flex', flexDirection: 'column', overflow: 'hidden',
        transform: shown ? 'translateX(0)' : 'translateX(100%)',
        transition: 'transform 280ms cubic-bezier(0.22, 1, 0.36, 1)',
      }}>
        {/* Header */}
        <div style={{ padding: '18px 22px 16px', borderBottom: '1px solid var(--border)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 13 }}>
            <Avatar animal={animal} tone={tone} size={44} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <h2 style={{ fontSize: 18, fontWeight: 700, letterSpacing: '-0.3px', margin: 0, color: 'var(--text)' }}>{editing ? 'Редактировать клиента' : 'Добавить клиента'}</h2>
              <div style={{ fontSize: 13, color: 'var(--text-dim)', marginTop: 1 }}>{editing ? (client.child || 'Клиент') : 'Новый клиент школы'}</div>
            </div>
            <button onClick={close} title="Закрыть" style={{ width: 34, height: 34, borderRadius: 6, border: '1px solid var(--border)', background: 'var(--bg-card)', cursor: 'pointer', color: 'var(--text-secondary)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flex: 'none' }}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round"><path d="M9.2 9.2l5.6 5.6M14.8 9.2l-5.6 5.6"/></svg>
            </button>
          </div>
        </div>

        {/* Body — единый экран (как у сотрудников) */}
        <div style={{ flex: 1, overflowY: 'auto', padding: '20px 22px', display: 'flex', flexDirection: 'column', gap: 16 }}>
          {/* Ученик */}
          <label style={{ display: 'flex', alignItems: 'center', gap: 9, cursor: 'pointer', fontSize: 13.5, color: 'var(--text-secondary)', fontWeight: 500, padding: '10px 12px', background: 'var(--bg-soft)', borderRadius: 'var(--radius-sm)' }}>
            <input type="checkbox" checked={self} onChange={e => setSelf(e.target.checked)} style={{ width: 16, height: 16, accentColor: 'var(--brand)' }} />
            Самостоятельный (взрослый ученик)
          </label>
          <Field label="ФИО" required><TextField value={name} onChange={setName} placeholder="Например, Анна Морозова" autoFocus /></Field>
          <Field label="Контакты"><ContactsEditor contacts={contacts} onChange={setContacts} openPicker={openPicker} /></Field>
          <div style={{ marginTop: 4 }}>
            <label style={{ display: 'block', fontSize: 13, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 8 }}>Аватар</label>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
              <div style={{ display: 'flex', gap: 6 }}>
                {ANIMALS.map(a => (
                  <button key={a} onClick={() => setAnimal(a)} style={{ padding: 2, borderRadius: '50%', cursor: 'pointer', background: 'none', border: '2px solid ' + (animal === a ? 'var(--brand)' : 'transparent') }}>
                    <Avatar animal={a} tone={tone} size={28} />
                  </button>
                ))}
              </div>
              <span style={{ width: 1, height: 24, background: 'var(--border)' }} />
              <div style={{ display: 'flex', gap: 6 }}>
                {TONES.map(t => (
                  <button key={t} onClick={() => setTone(t)} title={t} style={{ width: 24, height: 24, borderRadius: '50%', cursor: 'pointer', boxSizing: 'border-box', background: t === 'navy' ? 'var(--brand)' : t === 'green' ? 'var(--green)' : 'var(--gold)', border: '2px solid ' + (tone === t ? 'var(--text)' : 'transparent') }} />
                ))}
              </div>
            </div>
          </div>

          {/* Родители */}
          {!self && (
            <div style={{ borderTop: '1px solid var(--border)', paddingTop: 16, display: 'flex', flexDirection: 'column', gap: 16 }}>
              <Overline>Родители</Overline>
              {parents.map((p, i) => (
                <div key={i} style={{ border: '1px solid var(--border)', borderRadius: 'var(--radius-md)', overflow: 'hidden' }}>
                  <div style={{ padding: '9px 14px', background: 'var(--bg-soft)', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                    <span style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--text-secondary)' }}>Родитель {i + 1}</span>
                    {parents.length > 1 && (
                      <button onClick={() => removeParent(i)} title="Удалить" style={{ border: 'none', background: 'none', cursor: 'pointer', color: 'var(--coral)', display: 'inline-flex', padding: 2 }}>
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round"><path d="M9.2 9.2l5.6 5.6M14.8 9.2l-5.6 5.6"/></svg>
                      </button>
                    )}
                  </div>
                  <div style={{ padding: 14, display: 'flex', flexDirection: 'column', gap: 13 }}>
                    <Field label="ФИО"><TextField value={p.name} onChange={v => setParent(i, 'name', v)} placeholder="Например, Лариса" /></Field>
                    <Field label="Контакты"><ContactsEditor contacts={p.contacts || []} onChange={v => setParent(i, 'contacts', v)} openPicker={openPicker} /></Field>
                  </div>
                </div>
              ))}
              <button onClick={addParent} style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6, padding: '11px', border: '1px dashed var(--border-strong)', borderRadius: 'var(--radius-sm)', background: 'var(--bg-card)', cursor: 'pointer', color: 'var(--brand-ink)', fontSize: 13.5, fontWeight: 600, fontFamily: 'var(--font-sans)' }}>
                <Icon name="plus" size={16} />Добавить ещё родителя
              </button>
            </div>
          )}

          {/* Обучение */}
          <div style={{ borderTop: '1px solid var(--border)', paddingTop: 16, display: 'flex', flexDirection: 'column', gap: 16 }}>
            <Overline>Обучение</Overline>
            <Field label="Источник"><PickerTrigger label={source} placeholder="Выберите" onClick={() => openPicker({ title: 'Источник', value: source, options: SOURCES.map(s => ({ value: s, label: s })), allowCustom: true, customPlaceholder: 'Свой источник', onPick: setSource })} /></Field>
            <div>
              <label style={{ display: 'block', fontSize: 13, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 8 }}>Направления / предметы</label>
              {directions.length > 0 ? (
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 8 }}>
                  {directions.map(s => (
                    <span key={s} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '5px 8px 5px 11px', borderRadius: 'var(--radius-pill)', background: 'var(--brand-soft)', color: 'var(--brand-ink)', fontSize: 13, fontWeight: 600 }}>
                      {s}
                      <button onClick={() => removeDirection(s)} title="Убрать" style={{ border: 'none', background: 'none', cursor: 'pointer', color: 'var(--brand-ink)', display: 'inline-flex', padding: 0, opacity: 0.7 }}
                        onMouseEnter={e => { e.currentTarget.style.opacity = 1; }} onMouseLeave={e => { e.currentTarget.style.opacity = 0.7; }}>
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M9.2 9.2l5.6 5.6M14.8 9.2l-5.6 5.6"/></svg>
                      </button>
                    </span>
                  ))}
                </div>
              ) : <div style={{ fontSize: 12.5, color: 'var(--text-dim)', marginBottom: 8 }}>Не выбраны</div>}
              <button onClick={() => openPicker({
                title: 'Добавить направление', value: null,
                options: DIRECTIONS.filter(s => !directions.includes(s)).map(s => ({ value: s, label: s })).concat([{ value: '__add', label: '+ Добавить предмет в настройках…' }]),
                allowCustom: true, customPlaceholder: 'Своё направление (напр. Python, C++)',
                onPick: (v) => { if (v === '__add') { close(); if (onNavSettings) onNavSettings('staff-directions'); return; } addDirection(v); },
              })}
                style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '9px 12px', border: '1px dashed var(--border-strong)', borderRadius: 'var(--radius-sm)', background: 'var(--bg-card)', cursor: 'pointer', color: 'var(--brand-ink)', fontSize: 13, fontWeight: 600, fontFamily: 'var(--font-sans)' }}>
                <Icon name="plus" size={15} />Добавить направление
              </button>
              <div style={{ fontSize: 10.5, color: 'var(--text-dim)', marginTop: 6, lineHeight: 1.35 }}>Можно указать несколько — например, Python и C++.</div>
            </div>
            <div>
              <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 13, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 4 }}>
                Преподаватели
                <Tip width={250} text="У каждого педагога — своя цена занятия для этого ученика (поле справа в строке). Выплата педагогу считается отдельно от его ставки. При изменении цены спросим, с какого числа применить.">
                  <span style={{ display: 'inline-flex', cursor: 'help', color: 'var(--text-dim)' }}><Icon name="info" size={14} /></span>
                </Tip>
              </label>
              <div style={{ fontSize: 11.5, color: 'var(--text-dim)', marginBottom: 8 }}>Цена в строке педагога — это <b style={{ color: 'var(--text-secondary)', fontWeight: 600 }}>стоимость занятия для ученика</b>.</div>
              {teachers.length > 0 ? (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 8 }}>
                  {teachers.map(t => { const subs = teacherSubjects[t] || []; return (
                    <div key={t} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 12px', border: '1px solid var(--border)', borderRadius: 'var(--radius-sm)', background: 'var(--bg-soft)' }}>
                      <span style={{ width: 26, height: 26, borderRadius: '50%', flex: 'none', background: 'var(--brand-soft)', color: 'var(--brand-ink)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 12, fontWeight: 700 }}>{t.split(/\s+/).map(w => w[0]).slice(0, 2).join('')}</span>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontSize: 13.5, color: 'var(--text)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{t}</div>
                        <button onClick={() => openSubjModal(t)} style={{ border: 'none', background: 'none', padding: 0, marginTop: 2, cursor: 'pointer', fontFamily: 'var(--font-sans)', fontSize: 11.5, fontWeight: 600, color: subs.length ? 'var(--brand-ink)' : 'var(--coral)', display: 'inline-flex', alignItems: 'center', gap: 4 }}>
                          {subs.length ? subs.join(', ') : 'предмет не выбран'}<Icon name="pencil" size={11} style={{ opacity: 0.7 }} />
                        </button>
                      </div>
                      <div style={{ flex: 'none', display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 2 }}>
                        <span style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: '0.02em', color: 'var(--text-dim)', textTransform: 'uppercase' }}>Стоимость занятия</span>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 4, background: 'var(--bg-card)', border: '1px solid ' + (!(parseInt(String(teacherPrices[t]).replace(/\D/g, ''), 10) > 0) ? 'var(--coral)' : 'var(--border)'), borderRadius: 'var(--radius-sm)', padding: '4px 8px' }} title="Стоимость занятия для ученика у этого педагога — обязательна">
                          <input value={teacherPrices[t] != null ? teacherPrices[t] : ''} onChange={e => setTPrice(t, e.target.value.replace(/\D/g, ''))} placeholder={String(window.DEFAULT_LESSON_PRICE || 1800)} style={{ width: 52, border: 'none', outline: 'none', background: 'none', fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--text)', textAlign: 'right' }} />
                          <span style={{ fontSize: 12, color: 'var(--text-dim)' }}>₽</span>
                        </div>
                      </div>
                      <button onClick={() => removeTeacher(t)} title="Открепить" style={{ border: 'none', background: 'none', cursor: 'pointer', color: 'var(--text-dim)', display: 'inline-flex', padding: 3, flex: 'none' }}
                        onMouseEnter={e => { e.currentTarget.style.color = 'var(--coral)'; }} onMouseLeave={e => { e.currentTarget.style.color = 'var(--text-dim)'; }}>
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round"><path d="M9.2 9.2l5.6 5.6M14.8 9.2l-5.6 5.6"/></svg>
                      </button>
                    </div>
                  ); })}
                </div>
              ) : <div style={{ fontSize: 12.5, color: 'var(--text-dim)', marginBottom: 8 }}>Не назначены</div>}
              {TEACHERS.filter(t => !teachers.includes(t)).length > 0 && (
                <button onClick={() => openPicker(buildTeacherPicker())}
                  style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '9px 12px', border: '1px dashed var(--border-strong)', borderRadius: 'var(--radius-sm)', background: 'var(--bg-card)', cursor: 'pointer', color: 'var(--brand-ink)', fontSize: 13, fontWeight: 600, fontFamily: 'var(--font-sans)' }}>
                  <Icon name="plus" size={15} />Добавить преподавателя
                </button>
              )}
              <div style={{ fontSize: 10.5, color: 'var(--text-dim)', marginTop: 6, lineHeight: 1.35 }}>Ученик появится в разделе «Ученики» у каждого добавленного преподавателя.</div>
            </div>
            <Field label="Менеджер"><PickerTrigger label={manager} placeholder="Не назначен" onClick={() => openPicker({ title: 'Менеджер', value: manager, options: (MANAGERS || []).map(s => ({ value: s, label: s })), allowCustom: true, customPlaceholder: '@username', onPick: setManager })} /></Field>
            <div>
              <label style={{ display: 'block', fontSize: 13, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 8 }}>Заметка</label>
              <textarea value={notes} onChange={(e) => setNotes(e.target.value)} rows={3}
                placeholder="Запрос, договорённости, важные детали — попадёт в карточку ученика"
                style={{ width: '100%', boxSizing: 'border-box', resize: 'vertical', border: '1px solid var(--border)', borderRadius: 'var(--radius-sm)', padding: '10px 12px', fontFamily: 'var(--font-sans)', fontSize: 13.5, color: 'var(--text)', outline: 'none', background: 'var(--bg-card)', lineHeight: 1.5 }} />
            </div>
          </div>

          {/* Условия оплаты */}
          <div style={{ borderTop: '1px solid var(--border)', paddingTop: 16, display: 'flex', flexDirection: 'column', gap: 16 }}>
            <Overline>Условия оплаты</Overline>
            <div>
              <label style={{ display: 'block', fontSize: 13, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 8 }}>Формат оплаты</label>
              <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, padding: '9px 12px', borderRadius: 'var(--radius-sm)', border: '1px solid var(--border)', background: 'var(--bg-soft)', fontSize: 13.5, color: 'var(--text)', fontWeight: 500 }}>
                <Icon name="check-circle" size={15} style={{ color: 'var(--green)' }} />За занятие
              </div>
              <div style={{ fontSize: 10.5, color: 'var(--text-dim)', marginTop: 6, lineHeight: 1.35 }}>Пополнение и оплата ведутся по занятиям. Форматы «за месяц» и «за курс» — в разработке.</div>
            </div>
          </div>
        </div>

        {/* Footer */}
        <div style={{ padding: '14px 22px', borderTop: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ flex: 1 }} />
          {needTeacher && <span style={{ fontSize: 12, color: 'var(--coral)', fontWeight: 600 }}>Назначьте преподавателя — без него заявку нельзя конвертировать</span>}
          {!needTeacher && teachersMissingSubject.length > 0 && (
            <span style={{ fontSize: 12, color: 'var(--coral)', fontWeight: 600 }}>
              Укажите предмет: {teachersMissingSubject.map(t => t.split(/\s+/)[0]).join(', ')} — без него преподавателя не прикрепить
            </span>
          )}
          {!needTeacher && !canSave && teachersMissingSubject.length === 0 && teachersMissingPrice.length > 0 && <span style={{ fontSize: 12, color: 'var(--coral)', fontWeight: 600 }}>Укажите стоимость занятия у всех педагогов</span>}
          <Button variant="ghost" onClick={close}>Отмена</Button>
          <Button variant="primary" icon={editing ? 'check' : 'add-student'} onClick={() => canSave && finish()} style={canSave ? {} : { opacity: 0.5, cursor: 'not-allowed' }}>{editing ? 'Сохранить' : 'Создать'}</Button>
        </div>
      </div>
      </div>

      {/* Модалка: с какого момента пересчитать стоимость занятий */}
      {priceQueue && priceQueue[priceIdx] && (() => {
        const cur = priceQueue[priceIdx];
        const total = priceQueue.length;
        const todayISO = window.APP_TODAY_ISO || '2026-05-31';
        const ruDate = (iso) => { const p = String(iso).split('-'); const M = ['янв', 'фев', 'мар', 'апр', 'мая', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек']; return p.length === 3 ? `${+p[2]} ${M[+p[1] - 1]} ${p[0]}` : iso; };
        const fmt = (n) => new Intl.NumberFormat('ru-RU').format(n);
        const eff = priceForm.mode === 'all' ? '__all__' : (priceForm.mode === 'date' ? (priceForm.date || todayISO) : todayISO);
        const setMode = (m) => setPriceForm(pc => ({ ...pc, mode: m }));
        const next = () => {
          const map = { ...priceMap, [cur.teacher]: eff };
          if (priceIdx + 1 < total) { setPriceMap(map); setPriceForm({ mode: 'today', date: null }); setPriceIdx(priceIdx + 1); }
          else { setPriceQueue(null); doClose(map); }
        };
        const opt = (val, title, sub) => {
          const on = (priceForm.mode || 'today') === val;
          return (
            <button onClick={() => setMode(val)} style={{ display: 'flex', alignItems: 'flex-start', gap: 10, width: '100%', textAlign: 'left', padding: '10px 12px', borderRadius: 'var(--radius-sm)', border: '1px solid ' + (on ? 'var(--brand)' : 'var(--border)'), background: on ? 'var(--brand-soft)' : 'var(--bg-card)', cursor: 'pointer', fontFamily: 'var(--font-sans)' }}>
              <span style={{ width: 16, height: 16, borderRadius: '50%', flex: 'none', marginTop: 1, border: '2px solid ' + (on ? 'var(--brand)' : 'var(--border-strong)'), background: on ? 'var(--brand)' : 'transparent', boxShadow: on ? 'inset 0 0 0 2px var(--bg-card)' : 'none' }} />
              <span style={{ flex: 1 }}><span style={{ display: 'block', fontSize: 13.5, fontWeight: 600, color: 'var(--text)' }}>{title}</span><span style={{ display: 'block', fontSize: 11.5, color: 'var(--text-dim)' }}>{sub}</span></span>
            </button>
          );
        };
        return (
          <div style={{ position: 'fixed', inset: 0, zIndex: 75, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}>
            <div onClick={() => setPriceQueue(null)} className="om-fade-in" style={{ position: 'absolute', inset: 0, background: 'rgba(21,28,46,0.5)', backdropFilter: 'blur(2px)' }} />
            <div className="om-sheet-up" style={{ position: 'relative', width: 440, maxWidth: '100%', background: 'var(--bg-card)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-lg)', overflow: 'hidden' }}>
              <div style={{ padding: '18px 22px 14px', borderBottom: '1px solid var(--border)' }}>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                  <h3 style={{ fontSize: 17, fontWeight: 700, margin: 0, color: 'var(--text)' }}>Смена цены занятия</h3>
                  {total > 1 && <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)' }}>{priceIdx + 1} из {total}</span>}
                </div>
                {/* О каком предмете и педагоге речь */}
                <div style={{ fontSize: 12.5, color: 'var(--text-secondary)', marginTop: 6 }}>{shortName(cur.teacher)}{cur.subjects && cur.subjects.length ? <span style={{ color: 'var(--text-dim)' }}> · {cur.subjects.join(', ')}</span> : ''}</div>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginTop: 8 }}>
                  <span style={{ fontFamily: 'var(--font-mono)', fontSize: 15, color: 'var(--text-dim)', textDecoration: 'line-through' }}>{fmt(cur.oldPrice)} ₽</span>
                  <Icon name="arrow-right" size={15} style={{ color: 'var(--text-dim)', alignSelf: 'center' }} />
                  <span style={{ fontFamily: 'var(--font-mono)', fontSize: 15, fontWeight: 700, color: 'var(--brand-ink)' }}>{fmt(cur.newPrice)} ₽</span>
                  <span style={{ fontSize: 12, color: 'var(--text-dim)' }}>/занятие</span>
                </div>
              </div>
              <div style={{ padding: '16px 22px', display: 'flex', flexDirection: 'column', gap: 9 }}>
                <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text-secondary)' }}>С какого момента применить новую цену?</div>
                {opt('today', 'С сегодняшнего дня', ruDate(todayISO))}
                {opt('date', 'С конкретной даты', 'можно указать в прошлом или будущем')}
                {(priceForm.mode === 'date') && (
                  <input type="date" value={priceForm.date || todayISO} onChange={e => setPriceForm(pc => ({ ...pc, date: e.target.value }))} className="om-fade-in" style={{ marginLeft: 26, padding: '9px 11px', border: '1px solid var(--border-strong)', borderRadius: 'var(--radius-sm)', fontFamily: 'var(--font-mono)', fontSize: 13.5, color: 'var(--text)', outline: 'none', background: 'var(--bg-card)' }} />
                )}
                {opt('all', 'За весь период', 'пересчитать все ещё не проведённые занятия с этим педагогом')}
              </div>
              <div style={{ margin: '0 22px 16px', padding: '12px 14px', borderRadius: 'var(--radius-md)', background: 'var(--gold-soft)', border: '1px solid #E7CFA3', display: 'flex', gap: 10 }}>
                <Icon name="alert-triangle" size={17} style={{ color: 'var(--gold-ink)', flex: 'none', marginTop: 1 }} />
                <span style={{ fontSize: 12.5, color: 'var(--text-secondary)', lineHeight: 1.45 }}>Цена пересчитается только у занятий с <b style={{ color: 'var(--text)' }}>{shortName(cur.teacher)}</b> {eff === '__all__' ? <b style={{ color: 'var(--text)' }}>за весь период</b> : <React.Fragment>начиная с <b style={{ color: 'var(--text)' }}>{ruDate(eff)}</b></React.Fragment>}. Проведённые занятия и прошлые списания не меняются — новые занятия и запланированные пойдут по новой цене.</span>
              </div>
              <div style={{ padding: '0 22px 18px', display: 'flex', justifyContent: 'flex-end', gap: 10 }}>
                <Button variant="ghost" onClick={() => setPriceQueue(null)}>Отмена</Button>
                <Button variant="primary" icon={priceIdx + 1 < total ? 'arrow-right' : 'check'} onClick={next}>{priceIdx + 1 < total ? 'Далее' : 'Подтвердить'}</Button>
              </div>
            </div>
          </div>
        );
      })()}

      {/* Модалка: какие направления ведёт выбранный преподаватель */}
      {subjModalFor && (
        <div style={{ position: 'fixed', inset: 0, zIndex: 70, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}>
          <div onClick={() => setSubjModalFor(null)} className="om-fade-in" style={{ position: 'absolute', inset: 0, background: 'rgba(21,28,46,0.5)', backdropFilter: 'blur(2px)' }} />
          <div className="om-sheet-up" style={{ position: 'relative', width: 420, maxWidth: '100%', background: 'var(--bg-card)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-lg)', overflow: 'hidden' }}>
            <div style={{ padding: '18px 22px 14px', borderBottom: '1px solid var(--border)' }}>
              <h3 style={{ fontSize: 17, fontWeight: 700, margin: 0, color: 'var(--text)' }}>Какие направления ведёт?</h3>
              <div style={{ fontSize: 12.5, color: 'var(--text-dim)', marginTop: 2 }}>{subjModalFor}</div>
            </div>
            <div style={{ padding: '14px 22px', maxHeight: '50vh', overflowY: 'auto' }}>
              {directions.length === 0 ? (
                <div style={{ fontSize: 13, color: 'var(--text-dim)', lineHeight: 1.5 }}>У ученика ещё не выбраны направления. Сначала добавьте предметы в разделе «Обучение», затем выберите, какие из них ведёт преподаватель.</div>
              ) : (() => {
                const teaches = teacherTeaches(subjModalFor);
                const canList = directions.filter(s => teaches.includes(s));
                const cantList = directions.filter(s => !teaches.includes(s));
                return (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                  {canList.map(s => { const on = subjDraft.includes(s); const conflict = teachers.some(t => t !== subjModalFor && (teacherSubjects[t] || []).includes(s)); return (
                    <label key={s} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px', borderRadius: 'var(--radius-sm)', border: '1px solid ' + (on ? 'var(--brand)' : 'var(--border)'), background: on ? 'var(--brand-soft)' : 'var(--bg-card)', cursor: 'pointer' }}>
                      <input type="checkbox" checked={on} onChange={() => toggleSubjDraft(s)} style={{ width: 16, height: 16, accentColor: 'var(--brand)' }} />
                      <span style={{ flex: 1, fontSize: 13.5, fontWeight: on ? 600 : 500, color: on ? 'var(--brand-ink)' : 'var(--text)' }}>{s}</span>
                      {conflict && <span title="Этот предмет уже ведёт другой педагог" style={{ display: 'inline-flex', alignItems: 'center', gap: 3, fontSize: 10.5, fontWeight: 600, color: 'var(--gold-ink)' }}><Icon name="users" size={11} />уже ведут</span>}
                    </label>
                  ); })}
                  {cantList.map(s => (
                    <div key={s} title="Преподаватель не ведёт этот предмет" style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px', borderRadius: 'var(--radius-sm)', border: '1px solid var(--border)', background: 'var(--bg-soft)', opacity: 0.7, cursor: 'not-allowed' }}>
                      <span style={{ width: 16, height: 16, borderRadius: 4, border: '1.5px solid var(--border-strong)', flex: 'none' }} />
                      <span style={{ flex: 1, fontSize: 13.5, fontWeight: 500, color: 'var(--text-dim)', textDecoration: 'none' }}>{s}</span>
                      <span style={{ fontSize: 10.5, fontWeight: 600, color: 'var(--text-dim)' }}>не ведёт</span>
                    </div>
                  ))}
                </div>
                );
              })()}
              {directions.length > 0 && (() => {
                const teaches = teacherTeaches(subjModalFor);
                const hasCant = directions.some(s => !teaches.includes(s));
                const conflicts = subjConflicts();
                return (
                  <React.Fragment>
                    {hasCant && (
                      <div style={{ display: 'flex', gap: 8, marginTop: 12, padding: '10px 12px', borderRadius: 'var(--radius-sm)', background: 'var(--bg-soft)', border: '1px solid var(--border)' }}>
                        <Icon name="info" size={14} style={{ color: 'var(--text-dim)', flex: 'none', marginTop: 1 }} />
                        <span style={{ fontSize: 11, color: 'var(--text-dim)', lineHeight: 1.45 }}>Серые предметы преподаватель не ведёт — выбрать их нельзя. Чтобы он смог их вести, добавьте предмет в его карточке: <b style={{ color: 'var(--text-secondary)' }}>Сотрудники → профиль преподавателя → Предметы</b>.</span>
                      </div>
                    )}
                    {subjConfirm && conflicts.length > 0 && (
                      <div style={{ display: 'flex', gap: 8, marginTop: 10, padding: '10px 12px', borderRadius: 'var(--radius-sm)', background: 'var(--gold-soft)', border: '1px solid #E7CFA3' }}>
                        <Icon name="alert-triangle" size={15} style={{ color: 'var(--gold-ink)', flex: 'none', marginTop: 1 }} />
                        <span style={{ fontSize: 11.5, color: 'var(--text-secondary)', lineHeight: 1.45 }}>{conflicts.map(c => `«${c.subject}» уже ведёт ${c.by.map(shortName).join(', ')}`).join('; ')}. Точно назначить ещё одного преподавателя по этому предмету?</span>
                      </div>
                    )}
                  </React.Fragment>
                );
              })()}
            </div>
            <div style={{ padding: '12px 22px 18px', display: 'flex', justifyContent: 'flex-end', gap: 10 }}>
              <Button variant="ghost" onClick={() => setSubjModalFor(null)}>Отмена</Button>
              <Button variant={subjConfirm ? 'danger' : 'primary'} icon="check" onClick={saveSubjModal}>{subjConfirm ? 'Всё равно назначить' : 'Готово'}</Button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { AddClientModal, Field, TextField, formatPhone, ContactsEditor });
