/* App primitives: icons, buttons, modals, layout helpers */
const Icons = {
  search:'<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>',
  plus:'<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>',
  x:'<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>',
  check:'<polyline points="20 6 9 17 4 12"/>',
  arrow:'<line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/>',
  chevR:'<polyline points="9 18 15 12 9 6"/>',
  chevL:'<polyline points="15 18 9 12 15 6"/>',
  chevD:'<polyline points="6 9 12 15 18 9"/>',
  chevU:'<polyline points="18 15 12 9 6 15"/>',
  cal:'<rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>',
  home:'<path d="M3 9l9-7 9 7v11a2 2 0 01-2 2h-4v-7H10v7H6a2 2 0 01-2-2z"/>',
  users:'<path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 00-3-3.87"/><path d="M16 3.13a4 4 0 010 7.75"/>',
  user:'<path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/>',
  whats:'<path d="M20 12a8 8 0 10-3 6.2L20 20l-1.3-3A8 8 0 0020 12z"/>',
  money:'<line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6"/>',
  chart:'<line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/>',
  cog:'<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 11-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 11-2.83-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 112.83-2.83l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 112.83 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"/>',
  tooth:'<path d="M12 5.5C9 5.5 7 4 5 4c-2 0-3 1.5-3 4 0 4 2 6 2.5 9C5 19 6 21 7.5 21c1.2 0 1.5-2 2-4 .3-1.2.8-2 2.5-2s2.2.8 2.5 2c.5 2 .8 4 2 4 1.5 0 2.5-2 3-4 .5-3 2.5-5 2.5-9 0-2.5-1-4-3-4-2 0-4 1.5-7 1.5z"/>',
  bell:'<path d="M18 8a6 6 0 00-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/>',
  inbox:'<polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/><path d="M5.45 5.11L2 12v6a2 2 0 002 2h16a2 2 0 002-2v-6l-3.45-6.89A2 2 0 0016.76 4H7.24a2 2 0 00-1.79 1.11z"/>',
  star:'<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26"/>',
  filter:'<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>',
  pin:'<path d="M21 10c0 7-9 13-9 13S3 17 3 10a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/>',
  phone:'<path d="M22 17v3a2 2 0 01-2.2 2A20 20 0 012 4.2 2 2 0 014 2h3a2 2 0 012 1.7c.1 1 .3 2 .6 2.8a2 2 0 01-.4 2.1L8 10a16 16 0 006 6l1.4-1.3a2 2 0 012.1-.4c.8.3 1.8.5 2.8.6A2 2 0 0122 17z"/>',
  mail:'<path d="M4 4h16a2 2 0 012 2v12a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2z"/><polyline points="22,6 12,13 2,6"/>',
  download:'<path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>',
  edit:'<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>',
  trash:'<polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/>',
  info:'<circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/>',
  alert:'<path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>',
  more:'<circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/>',
  sliders:'<line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/><line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/><line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/><line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/>',
  qr:'<rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><line x1="14" y1="14" x2="14" y2="17"/><line x1="17" y1="14" x2="17" y2="20"/><line x1="20" y1="14" x2="20" y2="17"/><line x1="14" y1="20" x2="20" y2="20"/>',
  doc:'<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/>',
  upload:'<path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/>',
  link:'<path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71"/>',
  power:'<path d="M18.36 6.64a9 9 0 11-12.73 0"/><line x1="12" y1="2" x2="12" y2="12"/>',
  zap:'<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>',
  tag:'<path d="M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/>',
  eye:'<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>',
  gift:'<polyline points="20 12 20 22 4 22 4 12"/><rect x="2" y="7" width="20" height="5"/><line x1="12" y1="22" x2="12" y2="7"/><path d="M12 7H7.5a2.5 2.5 0 010-5C11 2 12 7 12 7z"/><path d="M12 7h4.5a2.5 2.5 0 000-5C13 2 12 7 12 7z"/>',
  refresh:'<polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"/>',
  copy:'<rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>',
  globe:'<circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"/>',
  video:'<polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/>',
  shield:'<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>',
  printer:'<polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 01-2-2v-5a2 2 0 012-2h16a2 2 0 012 2v5a2 2 0 01-2 2h-2"/><rect x="6" y="14" width="12" height="8"/>',
  send:'<line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/>',
  lock:'<rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/>',
  loc:'<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>',
};

const Icon = ({ name, size = 18, stroke = 1.5, ...rest }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
    strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"
    dangerouslySetInnerHTML={{__html: Icons[name] || Icons.info}} {...rest} />
);

const Btn = ({ kind = 'primary', size = 'md', icon, children, onClick, type = 'button', disabled, className = '', style }) => (
  <button type={type} disabled={disabled} onClick={onClick}
    className={`btn btn-${kind} ${size === 'sm' ? 'btn-sm' : size === 'lg' ? 'btn-lg' : ''} ${className}`} style={style}>
    {icon && <Icon name={icon} />} {children}
  </button>
);

const IconBtn = ({ name, onClick, title, size = 18, ariaLabel, kind = 'ghost' }) => (
  <button onClick={onClick} title={title} aria-label={ariaLabel || title}
    className={`icon-btn icon-btn-${kind}`}>
    <Icon name={name} size={size} />
  </button>
);

const Badge = ({ children, color, kind = 'soft' }) => (
  <span className={`badge badge-${kind}`} style={color ? {'--bd': color} : null}>{children}</span>
);

const Avatar = ({ initials, color, size = 36 }) => (
  <div className="avatar" style={{ width: size, height: size, background: color || '#0EA5E9', fontSize: size * 0.36 }}>
    {initials}
  </div>
);

const Field = ({ label, hint, error, children, required }) => (
  <label className="field">
    {label && <span className="field-label">{label}{required && <span style={{color:'#EF4444'}}> *</span>}</span>}
    {children}
    {hint && !error && <span className="field-hint">{hint}</span>}
    {error && <span className="field-error">{error}</span>}
  </label>
);

const Input = (props) => <input className="input" {...props} />;
const Select = ({ children, ...p }) => <select className="input select" {...p}>{children}</select>;
const Textarea = (props) => <textarea className="input textarea" {...props} />;

const Toggle = ({ checked, onChange, label }) => (
  <label className="toggle">
    <input type="checkbox" checked={checked} onChange={(e) => onChange?.(e.target.checked)} />
    <span className="toggle-track"><span className="toggle-thumb"></span></span>
    {label && <span className="toggle-label">{label}</span>}
  </label>
);

const Modal = ({ open, onClose, title, children, size = 'md', footer }) => {
  if (!open) return null;
  React.useEffect(() => {
    const onKey = (e) => e.key === 'Escape' && onClose?.();
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);
  return (
    <div className="modal-overlay" onMouseDown={(e) => e.target === e.currentTarget && onClose?.()}>
      <div className={`modal modal-${size}`} role="dialog" aria-modal="true">
        <header className="modal-header">
          <h3>{title}</h3>
          <IconBtn name="x" onClick={onClose} ariaLabel="Fechar" />
        </header>
        <div className="modal-body">{children}</div>
        {footer && <footer className="modal-footer">{footer}</footer>}
      </div>
    </div>
  );
};

const Card = ({ children, padding = '20px', className = '', style, onClick }) => (
  <div className={`card ${className}`} style={{ padding, ...style }} onClick={onClick}>{children}</div>
);

const StatTile = ({ label, value, delta, deltaDir, icon, accent }) => (
  <Card className="stat-tile">
    <div className="stat-head">
      <span className="stat-label">{label}</span>
      {icon && <span className="stat-icon" style={accent ? {color: accent} : null}><Icon name={icon} size={20} /></span>}
    </div>
    <div className="stat-value">{value}</div>
    {delta != null && (
      <div className={`stat-delta stat-delta-${deltaDir || (delta > 0 ? 'up' : 'down')}`}>
        <Icon name={delta > 0 ? 'chevU' : 'chevD'} size={12} />
        {Math.abs(delta)}% vs mês anterior
      </div>
    )}
  </Card>
);

const Tabs = ({ tabs, active, onChange }) => (
  <div className="tabs" role="tablist">
    {tabs.map(t => (
      <button key={t.id} role="tab" aria-selected={active === t.id}
        className={`tab ${active === t.id ? 'is-active' : ''}`}
        onClick={() => onChange(t.id)}>
        {t.icon && <Icon name={t.icon} size={16} />}
        {t.label}
        {t.count != null && <span className="tab-count">{t.count}</span>}
      </button>
    ))}
  </div>
);

const EmptyState = ({ icon, title, body, action }) => (
  <div className="empty-state">
    {icon && <div className="empty-icon"><Icon name={icon} size={32} /></div>}
    <h4>{title}</h4>
    {body && <p>{body}</p>}
    {action}
  </div>
);

const Spinner = ({ size = 20 }) => (
  <span className="spinner" style={{ width: size, height: size }}></span>
);

// Toast system
const ToastCtx = React.createContext(null);
const ToastProvider = ({ children }) => {
  const [toasts, setToasts] = React.useState([]);
  const push = React.useCallback((t) => {
    const id = Math.random().toString(36).slice(2);
    setToasts(prev => [...prev, { id, ...t }]);
    setTimeout(() => setToasts(prev => prev.filter(x => x.id !== id)), t.duration || 3500);
  }, []);
  return (
    <ToastCtx.Provider value={{ push }}>
      {children}
      <div className="toast-stack">
        {toasts.map(t => (
          <div key={t.id} className={`toast toast-${t.kind || 'info'}`}>
            <Icon name={t.kind === 'success' ? 'check' : t.kind === 'error' ? 'alert' : 'info'} size={16} />
            <div><div className="toast-title">{t.title}</div>{t.body && <div className="toast-body">{t.body}</div>}</div>
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
};
const useToast = () => React.useContext(ToastCtx);

Object.assign(window, {
  Icons, Icon, Btn, IconBtn, Badge, Avatar, Field, Input, Select, Textarea,
  Toggle, Modal, Card, StatTile, Tabs, EmptyState, Spinner, ToastProvider, useToast
});


const D_ = window.AppData;
const findClient = (id) => D_.clients.find(c => c.id === id);
const findPro = (id) => D_.pros.find(p => p.id === id);
const findService = (id) => D_.services.find(s => s.id === id);
const fmtMoney = (v) => v === 0 ? 'Gratuito' : `R$ ${v.toFixed(2).replace('.', ',')}`;
const fmtMoneyShort = (v) => v >= 1000 ? `R$ ${(v/1000).toFixed(1)}k` : `R$ ${v.toFixed(0)}`;
const dayLabels = ['DOM','SEG','TER','QUA','QUI','SEX','SÁB'];
const dayLabelsLong = ['Domingo','Segunda','Terça','Quarta','Quinta','Sexta','Sábado'];
const statusColor = (s) => ({ confirmed:'#10B981', pending:'#F59E0B', completed:'#64748B', cancelled:'#EF4444', noshow:'#EF4444' })[s] || '#64748B';
const statusLabel = (s) => ({ confirmed:'Confirmado', pending:'Pendente', completed:'Concluído', cancelled:'Cancelado', noshow:'Faltou' })[s] || s;
const InfoRow = ({ label, value }) => (
  <div>
    <div className="muted" style={{ fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>{label}</div>
    <div style={{ fontSize: 14, marginTop: 2 }}>{value}</div>
  </div>
);

Object.assign(window, { Icon, Btn, IconBtn, Badge, Avatar, Field, Input, Select, Textarea, Toggle, Card, StatTile, Tabs, findClient, findPro, findService, fmtMoney, fmtMoneyShort, dayLabels, dayLabelsLong, statusColor, statusLabel, InfoRow });
