// nyashelf-modals.jsx
// Modal/sheet primitive + ToastProvider + a few task-specific modals
// (NotesModal, ExportCsvModal, ConfirmDialog).

// ─────────────────────────────────────────────────────────────────────────────
// Modal — bottom-sheet style modal on top of the phone area. position: fixed
// anchors to .nya-stage (transformed ancestor) so it fills the phone exactly.
// ─────────────────────────────────────────────────────────────────────────────
function Modal({ open, onClose, title, children, footer, maxHeight = 600 }) {
  React.useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose?.(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div
      onClick={onClose}
      style={{
        position: 'fixed', inset: 0, zIndex: 300,
        background: 'rgba(8,4,20,.72)',
        backdropFilter: 'blur(10px)', WebkitBackdropFilter: 'blur(10px)',
        display: 'flex', flexDirection: 'column', justifyContent: 'flex-end',
        borderRadius: 56, overflow: 'hidden',
        animation: 'nya-fade-in .18s ease forwards',
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          background: 'linear-gradient(180deg, rgba(60,40,90,.55), rgba(30,18,55,.85))',
          backdropFilter: 'blur(24px) saturate(160%)',
          WebkitBackdropFilter: 'blur(24px) saturate(160%)',
          borderTop: '1px solid var(--card-border)',
          borderLeft: '1px solid var(--card-border)',
          borderRight: '1px solid var(--card-border)',
          borderTopLeftRadius: 28, borderTopRightRadius: 28,
          maxHeight: maxHeight, display: 'flex', flexDirection: 'column',
          animation: 'nya-slide-up .25s ease forwards',
          boxShadow: '0 -10px 40px rgba(0,0,0,.4), 0 -2px 0 rgba(255,255,255,.05) inset',
        }}
      >
        {/* grab handle */}
        <div style={{
          padding: '10px 0 0', display: 'flex', justifyContent: 'center',
        }}>
          <div style={{
            width: 40, height: 4, borderRadius: 2,
            background: 'rgba(255,255,255,.2)',
          }}/>
        </div>
        {/* title bar */}
        {title && (
          <div style={{
            padding: '10px 18px 6px', display: 'flex',
            alignItems: 'center', justifyContent: 'space-between',
          }}>
            <h2 style={{
              margin: 0, fontFamily: 'Comfortaa, sans-serif', fontWeight: 600,
              fontSize: 18, color: 'var(--text)',
            }}>{title}</h2>
            <button onClick={onClose} style={{
              width: 32, height: 32, borderRadius: '50%', border: 0,
              background: 'rgba(255,255,255,.06)', color: 'var(--text)',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              cursor: 'pointer', padding: 0,
            }}>{I.close(16)}</button>
          </div>
        )}
        {/* body */}
        <div style={{
          padding: '10px 18px 18px', overflowY: 'auto', flex: 1,
        }}>{children}</div>
        {/* sticky footer */}
        {footer && (
          <div style={{
            padding: '12px 18px 18px',
            borderTop: '1px solid rgba(200,155,240,.08)',
            background: 'rgba(20,12,40,.4)',
          }}>{footer}</div>
        )}
      </div>
    </div>
  );
}

// Form helpers for use inside modals
function FormField({ label, children, hint }) {
  return (
    <div style={{ marginBottom: 14 }}>
      <label style={{
        display: 'block', fontSize: 11, fontWeight: 600, color: 'var(--text-dim)',
        textTransform: 'uppercase', letterSpacing: '.06em', marginBottom: 6,
      }}>{label}</label>
      {children}
      {hint && (
        <div style={{ fontSize: 11, color: 'var(--text-dim)', marginTop: 5 }}>{hint}</div>
      )}
    </div>
  );
}

function FormInput({ value, onChange, type = 'text', placeholder, multiline = false }) {
  const base = {
    width: '100%', padding: '11px 14px',
    background: 'rgba(255,255,255,.05)',
    border: '1px solid var(--card-border)',
    borderRadius: 14, outline: 0,
    color: 'var(--text)', fontFamily: 'Quicksand, sans-serif',
    fontSize: 14, fontWeight: 500,
    transition: 'border-color .15s',
  };
  if (multiline) {
    return (
      <textarea
        value={value} placeholder={placeholder}
        onChange={(e) => onChange(e.target.value)}
        rows={4}
        style={{ ...base, resize: 'vertical', minHeight: 90, fontFamily: 'Quicksand, sans-serif' }}
      />
    );
  }
  return (
    <input
      type={type} value={value} placeholder={placeholder}
      onChange={(e) => onChange(e.target.value)}
      style={base}
    />
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// ConfirmDialog — small modal with title/message + confirm/cancel
// ─────────────────────────────────────────────────────────────────────────────
function ConfirmDialog({ open, title, message, confirmLabel = 'подтвердить', cancelLabel = 'отмена', danger = false, onConfirm, onCancel }) {
  return (
    <Modal open={open} onClose={onCancel} maxHeight={300}>
      <div style={{ textAlign: 'center', padding: '8px 0 14px' }}>
        <h3 style={{
          margin: 0, fontFamily: 'Comfortaa, sans-serif', fontWeight: 600,
          fontSize: 18, color: 'var(--text)',
        }}>{title}</h3>
        {message && (
          <p style={{
            margin: '10px 0 0', fontSize: 13.5, lineHeight: 1.5,
            color: 'var(--text-dim)', textWrap: 'pretty',
          }}>{message}</p>
        )}
      </div>
      <div style={{ display: 'flex', gap: 8, marginTop: 6 }}>
        <GhostButton full onClick={onCancel}>{cancelLabel}</GhostButton>
        {danger ? (
          <button onClick={onConfirm} style={{
            flex: 1, height: 44, borderRadius: 9999, border: 0,
            background: 'linear-gradient(135deg, #ff8aa8, #ff6b94)',
            color: '#3a1e4d',
            fontFamily: 'Quicksand, sans-serif', fontWeight: 600, fontSize: 14.5,
            cursor: 'pointer',
            boxShadow: '0 0 18px rgba(255,138,168,.5)',
          }}>{confirmLabel}</button>
        ) : (
          <GradientButton full onClick={onConfirm}>{confirmLabel}</GradientButton>
        )}
      </div>
    </Modal>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// ToastProvider — global toast system. Use via useToast() hook → toast.show(msg)
// ─────────────────────────────────────────────────────────────────────────────
const ToastContext = React.createContext({ show: () => {} });

function ToastProvider({ children }) {
  const [items, setItems] = React.useState([]);
  const idRef = React.useRef(0);
  const show = React.useCallback((message, opts = {}) => {
    const id = ++idRef.current;
    const item = { id, message, kind: opts.kind || 'info', icon: opts.icon };
    setItems(prev => [...prev, item]);
    setTimeout(() => {
      setItems(prev => prev.filter(x => x.id !== id));
    }, opts.duration || 3000);
  }, []);
  return (
    <ToastContext.Provider value={{ show }}>
      {children}
      <ToastHost items={items} />
    </ToastContext.Provider>
  );
}

function useToast() {
  return React.useContext(ToastContext);
}

function ToastHost({ items }) {
  if (items.length === 0) return null;
  return (
    <div style={{
      position: 'fixed', bottom: 96, left: 0, right: 0, zIndex: 400,
      display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8,
      padding: '0 16px', pointerEvents: 'none',
    }}>
      {items.map(it => (
        <div key={it.id} style={{
          display: 'inline-flex', alignItems: 'center', gap: 10,
          padding: '12px 18px',
          background: 'linear-gradient(135deg, rgba(60,40,90,.85), rgba(40,25,65,.92))',
          backdropFilter: 'blur(16px) saturate(180%)',
          WebkitBackdropFilter: 'blur(16px) saturate(180%)',
          border: '1px solid var(--card-border)',
          borderRadius: 9999,
          boxShadow: '0 8px 30px rgba(0,0,0,.4), 0 0 18px var(--glow-soft)',
          color: 'var(--text)',
          fontFamily: 'Quicksand, sans-serif',
          fontSize: 13.5, fontWeight: 500,
          maxWidth: '92%',
          pointerEvents: 'auto',
          animation: 'nya-toast-in .25s cubic-bezier(.3,.7,.4,1.4) forwards',
        }}>
          <span style={{
            width: 22, height: 22, borderRadius: '50%',
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            background: it.kind === 'error' ? '#ff8aa8' : it.kind === 'success' ? '#6fdb9c' : 'var(--accent-a)',
            color: '#3a1e4d', flexShrink: 0,
          }}>{it.icon || (it.kind === 'error' ? I.close(12) : I.check(12))}</span>
          {it.message}
        </div>
      ))}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// NotesModal — text editor + history of past notes
// ─────────────────────────────────────────────────────────────────────────────
function NotesModal({ open, figure, onClose }) {
  const [draft, setDraft] = React.useState('');
  const [notes, setNotes] = React.useState(() => {
    if (!figure) return [];
    // mock: a few notes for the first time, persisted in component state only
    return [
      { id: 1, text: 'упаковка от amiAmi обычно крепкая, можно не страховать', at: '3 дн назад' },
      { id: 2, text: 'если цена упадёт ниже €170 — взять второй экз',           at: '1 нед назад' },
    ];
  });
  React.useEffect(() => { setDraft(''); }, [figure]);
  const addNote = () => {
    if (!draft.trim()) return;
    setNotes(prev => [{ id: Date.now(), text: draft.trim(), at: 'только что' }, ...prev]);
    setDraft('');
  };

  return (
    <Modal
      open={open} onClose={onClose} title="заметки" maxHeight={640}
      footer={
        <div style={{ display: 'flex', gap: 8, alignItems: 'flex-end' }}>
          <div style={{ flex: 1 }}>
            <FormInput value={draft} onChange={setDraft} placeholder="мысль, ссылка, напоминание…" multiline />
          </div>
          <GradientButton onClick={addNote} icon={I.plus(14)}>добавить</GradientButton>
        </div>
      }
    >
      {figure && (
        <div style={{ fontSize: 12, color: 'var(--text-dim)', marginBottom: 12 }}>
          о фигурке <span style={{ color: 'var(--text)', fontWeight: 600 }}>{figure.name}</span>
        </div>
      )}
      {notes.length === 0 ? (
        <div style={{ padding: '20px 0', textAlign: 'center', color: 'var(--text-dim)', fontSize: 13 }}>
          заметок пока нет
        </div>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {notes.map(n => (
            <GlassCard key={n.id} padding={12}>
              <p style={{ margin: 0, fontSize: 13.5, lineHeight: 1.5, color: 'var(--text)' }}>
                {n.text}
              </p>
              <div style={{ marginTop: 6, fontSize: 10.5, color: 'var(--text-dim)' }}>{n.at}</div>
            </GlassCard>
          ))}
        </div>
      )}
    </Modal>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// ExportCsvModal — pick what to include + a fake "download" button
// ─────────────────────────────────────────────────────────────────────────────
function ExportCsvModal({ open, onClose, onExport }) {
  const [opts, setOpts] = React.useState({
    figures: true, payments: true, wishlist: true, notes: false, prices: false,
  });
  const toggle = (k) => setOpts(o => ({ ...o, [k]: !o[k] }));
  const items = [
    { id: 'figures', label: 'все фигурки',       hint: 'название, статус, цена, релиз' },
    { id: 'payments', label: 'история платежей',  hint: 'дата, сумма, валюта, заказ' },
    { id: 'wishlist', label: 'вишлист',           hint: 'желаемые позиции' },
    { id: 'notes',    label: 'заметки',           hint: 'твои мысли по каждой фигурке' },
    { id: 'prices',   label: 'история цен',       hint: 'снапшоты цен с nin-nin-game' },
  ];

  return (
    <Modal
      open={open} onClose={onClose} title="экспорт в csv"
      footer={
        <GradientButton full size="lg" onClick={() => { onExport(opts); onClose(); }}
          icon={
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                 strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M12 3 V 16"/><path d="M6 11 L 12 17 L 18 11"/>
              <path d="M5 20 H 19"/>
            </svg>
          }>
          скачать csv
        </GradientButton>
      }
    >
      <div style={{ fontSize: 12.5, color: 'var(--text-dim)', marginBottom: 12, lineHeight: 1.5 }}>
        выбери что включить. файл придёт в telegram чат с ботом.
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
        {items.map(it => {
          const on = opts[it.id];
          return (
            <button key={it.id} onClick={() => toggle(it.id)} style={{
              display: 'flex', alignItems: 'center', gap: 12,
              padding: '12px 14px',
              background: on ? 'rgba(255,158,205,.10)' : 'rgba(255,255,255,.04)',
              border: '1px solid ' + (on ? 'var(--accent-a)' : 'var(--card-border)'),
              borderRadius: 14, cursor: 'pointer',
              color: 'var(--text)', textAlign: 'left',
              boxShadow: on ? '0 0 10px var(--glow-soft)' : 'none',
              transition: 'all .15s',
            }}>
              <span style={{
                width: 22, height: 22, borderRadius: 7,
                background: on ? 'linear-gradient(135deg, var(--accent-a), var(--accent-b))' : 'rgba(255,255,255,.06)',
                border: '1px solid ' + (on ? 'transparent' : 'var(--card-border)'),
                color: '#3a1e4d',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                flexShrink: 0,
              }}>{on && I.check(14)}</span>
              <div style={{ flex: 1 }}>
                <div style={{ fontFamily: 'Quicksand, sans-serif', fontWeight: 600, fontSize: 13.5 }}>{it.label}</div>
                <div style={{ fontSize: 11, color: 'var(--text-dim)', marginTop: 2 }}>{it.hint}</div>
              </div>
            </button>
          );
        })}
      </div>
    </Modal>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// CatalogFilterModal — price range / status / makers / release year
// ─────────────────────────────────────────────────────────────────────────────
function CatalogFilterModal({ open, onClose, value, onApply }) {
  const fmt = useFormat();
  // value: { priceMin, priceMax, statuses (Set), makers (Set), yearRange }
  const PRICE_MAX = 350; // base EUR

  const [draft, setDraft] = React.useState(() => ({
    priceMin: value?.priceMin ?? 0,
    priceMax: value?.priceMax ?? PRICE_MAX,
    statuses: new Set(value?.statuses || []),
    makers:   new Set(value?.makers   || []),
    year:     value?.year ?? 'all',
  }));
  React.useEffect(() => { if (open) setDraft({
    priceMin: value?.priceMin ?? 0,
    priceMax: value?.priceMax ?? PRICE_MAX,
    statuses: new Set(value?.statuses || []),
    makers:   new Set(value?.makers   || []),
    year:     value?.year ?? 'all',
  }); }, [open]);

  const toggleSet = (key, v) => setDraft(d => {
    const n = new Set(d[key]); n.has(v) ? n.delete(v) : n.add(v);
    return { ...d, [key]: n };
  });

  const reset = () => setDraft({ priceMin: 0, priceMax: PRICE_MAX, statuses: new Set(), makers: new Set(), year: 'all' });

  const apply = () => { onApply(draft); onClose(); };

  const statuses = [
    { id: 'preorder',  label: 'предзаказ' },
    { id: 'soon',      label: 'скоро' },
    { id: 'available', label: 'в наличии' },
    { id: 'paid',      label: 'оплачено' },
    { id: 'shipped',   label: 'в пути' },
  ];
  const makers = ['Alter', 'Kotobukiya', 'GSC', 'Max Factory'];
  const years = ['all', '2026', '2027'];

  return (
    <Modal open={open} onClose={onClose} title="фильтры" maxHeight={680}
      footer={
        <div style={{ display: 'flex', gap: 8 }}>
          <GhostButton full onClick={reset}>сбросить</GhostButton>
          <GradientButton full onClick={apply}>применить</GradientButton>
        </div>
      }
    >
      <FormField label={`цена · ${fmt(draft.priceMin)} — ${draft.priceMax >= PRICE_MAX ? fmt(PRICE_MAX) + '+' : fmt(draft.priceMax)}`}>
        <DualRangeSlider
          min={0} max={PRICE_MAX} step={5}
          valueLow={draft.priceMin} valueHigh={draft.priceMax}
          onChange={(lo, hi) => setDraft(d => ({ ...d, priceMin: lo, priceMax: hi }))}
        />
      </FormField>

      <FormField label="статус">
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {statuses.map(s => {
            const on = draft.statuses.has(s.id);
            return (
              <ChipToggle key={s.id} on={on} onClick={() => toggleSet('statuses', s.id)}>
                {s.label}
              </ChipToggle>
            );
          })}
        </div>
      </FormField>

      <FormField label="производитель">
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {makers.map(m => {
            const on = draft.makers.has(m);
            return (
              <ChipToggle key={m} on={on} onClick={() => toggleSet('makers', m)}>
                {m}
              </ChipToggle>
            );
          })}
        </div>
      </FormField>

      <FormField label="год релиза">
        <div style={{ display: 'flex', gap: 6 }}>
          {years.map(y => {
            const on = draft.year === y;
            return (
              <ChipToggle key={y} on={on} onClick={() => setDraft(d => ({ ...d, year: y }))} grow>
                {y === 'all' ? 'любой' : y}
              </ChipToggle>
            );
          })}
        </div>
      </FormField>
    </Modal>
  );
}

// Pill toggle for filter chips
function ChipToggle({ on, onClick, children, grow }) {
  return (
    <button onClick={onClick} style={{
      flex: grow ? 1 : 'unset',
      padding: '8px 14px', borderRadius: 9999, border: 0,
      background: on
        ? 'linear-gradient(135deg, var(--accent-a), var(--accent-b))'
        : 'rgba(255,255,255,.06)',
      color: on ? '#3a1e4d' : 'var(--text)',
      fontFamily: 'Quicksand, sans-serif', fontSize: 12, fontWeight: 600,
      cursor: 'pointer',
      boxShadow: on ? '0 0 10px var(--glow-soft)' : 'none',
      border: '1px solid ' + (on ? 'transparent' : 'var(--card-border)'),
      transition: 'all .12s',
    }}>{children}</button>
  );
}

// Two-thumb range slider — pure CSS + JS, accepts both pointer and click
function DualRangeSlider({ min, max, step, valueLow, valueHigh, onChange }) {
  const ref = React.useRef(null);
  const dragging = React.useRef(null); // 'lo' | 'hi'
  const lowPct  = ((valueLow  - min) / (max - min)) * 100;
  const highPct = ((valueHigh - min) / (max - min)) * 100;

  const onDown = (which) => (e) => {
    dragging.current = which;
    const move = (ev) => {
      const r = ref.current.getBoundingClientRect();
      const x = (ev.touches ? ev.touches[0].clientX : ev.clientX) - r.left;
      const pct = Math.max(0, Math.min(1, x / r.width));
      let v = Math.round((min + pct * (max - min)) / step) * step;
      if (dragging.current === 'lo') onChange(Math.min(v, valueHigh - step), valueHigh);
      else onChange(valueLow, Math.max(v, valueLow + step));
    };
    const up = () => {
      dragging.current = null;
      window.removeEventListener('pointermove', move);
      window.removeEventListener('pointerup', up);
    };
    window.addEventListener('pointermove', move);
    window.addEventListener('pointerup', up);
  };

  return (
    <div ref={ref} style={{ position: 'relative', height: 32, padding: '14px 0' }}>
      <div style={{
        position: 'absolute', left: 0, right: 0, top: '50%',
        height: 4, borderRadius: 9999,
        background: 'rgba(255,255,255,.08)',
        transform: 'translateY(-50%)',
      }}/>
      <div style={{
        position: 'absolute', top: '50%', height: 4, borderRadius: 9999,
        left: `${lowPct}%`, right: `${100 - highPct}%`,
        background: 'linear-gradient(90deg, var(--accent-a), var(--accent-b))',
        boxShadow: '0 0 10px var(--glow-soft)',
        transform: 'translateY(-50%)',
      }}/>
      {[['lo', lowPct], ['hi', highPct]].map(([k, p]) => (
        <div key={k}
             onPointerDown={onDown(k)}
             style={{
          position: 'absolute', top: '50%', left: `${p}%`,
          width: 22, height: 22, borderRadius: '50%',
          background: '#fff',
          border: '2px solid var(--accent-a)',
          boxShadow: '0 2px 6px rgba(0,0,0,.3), 0 0 10px var(--glow-soft)',
          transform: 'translate(-50%, -50%)',
          cursor: 'grab', touchAction: 'none',
        }}/>
      ))}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// CalendarFilterModal — status + min payment amount
// ─────────────────────────────────────────────────────────────────────────────
function CalendarFilterModal({ open, onClose, value, onApply }) {
  const fmt = useFormat();
  const [draft, setDraft] = React.useState(() => ({
    statuses: new Set(value?.statuses || []),
    minAmount: value?.minAmount ?? 0,
    showPaid: value?.showPaid ?? false,
  }));
  React.useEffect(() => { if (open) setDraft({
    statuses: new Set(value?.statuses || []),
    minAmount: value?.minAmount ?? 0,
    showPaid: value?.showPaid ?? false,
  }); }, [open]);

  const toggleStatus = (s) => setDraft(d => {
    const n = new Set(d.statuses); n.has(s) ? n.delete(s) : n.add(s);
    return { ...d, statuses: n };
  });
  const reset = () => setDraft({ statuses: new Set(), minAmount: 0, showPaid: false });
  const apply = () => { onApply(draft); onClose(); };

  const statuses = [
    { id: 'preorder',  label: 'предзаказ' },
    { id: 'soon',      label: 'скоро' },
    { id: 'paid',      label: 'оплачено' },
  ];

  return (
    <Modal open={open} onClose={onClose} title="фильтры календаря"
      footer={
        <div style={{ display: 'flex', gap: 8 }}>
          <GhostButton full onClick={reset}>сбросить</GhostButton>
          <GradientButton full onClick={apply}>применить</GradientButton>
        </div>
      }
    >
      <FormField label="статус">
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {statuses.map(s => (
            <ChipToggle key={s.id} on={draft.statuses.has(s.id)} onClick={() => toggleStatus(s.id)}>
              {s.label}
            </ChipToggle>
          ))}
        </div>
      </FormField>

      <FormField label={`платёж от ${fmt(draft.minAmount)}`}>
        <input type="range" min="0" max="300" step="10"
          value={draft.minAmount}
          onChange={e => setDraft(d => ({ ...d, minAmount: Number(e.target.value) }))}
          style={{ width: '100%' }}/>
      </FormField>

      <FormField label="показать">
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          padding: '12px 0' }}>
          <div>
            <div style={{ fontSize: 13.5, fontWeight: 500 }}>оплаченные месяцы</div>
            <div style={{ fontSize: 11, color: 'var(--text-dim)', marginTop: 2 }}>
              по умолчанию скрыты
            </div>
          </div>
          <button onClick={() => setDraft(d => ({ ...d, showPaid: !d.showPaid }))} style={{
            position: 'relative', width: 44, height: 26, borderRadius: 9999, border: 0,
            background: draft.showPaid ? 'linear-gradient(135deg, var(--accent-a), var(--accent-b))' : 'rgba(255,255,255,.12)',
            boxShadow: draft.showPaid ? '0 0 10px var(--glow-soft)' : 'none',
            cursor: 'pointer', padding: 0,
          }}>
            <span style={{
              position: 'absolute', top: 3, left: draft.showPaid ? 21 : 3,
              width: 20, height: 20, borderRadius: '50%', background: '#fff',
              boxShadow: '0 1px 3px rgba(0,0,0,.3)',
              transition: 'left .18s',
            }}/>
          </button>
        </div>
      </FormField>
    </Modal>
  );
}

Object.assign(window, {
  Modal, FormField, FormInput,
  ConfirmDialog, ToastProvider, useToast,
  NotesModal, ExportCsvModal,
  CatalogFilterModal, CalendarFilterModal, ChipToggle, DualRangeSlider,
});
