(function () {
  // 通用线性图标
  const Icon = ({ name, size = 16, className = '', filled = false, strokeWidth = 2 }) => {
    const p = { width: size, height: size, viewBox: '0 0 24 24', fill: filled ? 'currentColor' : 'none', stroke: 'currentColor', strokeWidth, strokeLinecap: 'round', strokeLinejoin: 'round', className };
    switch (name) {
      case 'plus':         return <svg {...p}><path d="M12 5v14M5 12h14"/></svg>;
      case 'minus':        return <svg {...p}><path d="M5 12h14"/></svg>;
      case 'check':        return <svg {...p}><path d="M5 12l5 5L20 7"/></svg>;
      case 'close':        return <svg {...p}><path d="M6 6l12 12M18 6L6 18"/></svg>;
      case 'edit':         return <svg {...p}><path d="M11 4H4v16h16v-7M18.5 2.5a2.1 2.1 0 113 3L12 15l-4 1 1-4z"/></svg>;
      case 'search':       return <svg {...p}><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.3-4.3"/></svg>;
      case 'location':     return <svg {...p} fill="currentColor" stroke="none"><path d="M12 2C8 2 5 5 5 9c0 5 7 13 7 13s7-8 7-13c0-4-3-7-7-7zm0 9.5a2.5 2.5 0 110-5 2.5 2.5 0 010 5z"/></svg>;
      case 'clock':        return <svg {...p}><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>;
      case 'message':      return <svg {...p}><path d="M21 11.5a8.4 8.4 0 01-12 7.6L5 20l1-4A8.4 8.4 0 1121 11.5z"/></svg>;
      case 'bell':         return <svg {...p}><path d="M6 8a6 6 0 1112 0c0 7 3 9 3 9H3s3-2 3-9M14 20a2 2 0 11-4 0"/></svg>;
      case 'star':         return <svg {...p} fill={filled ? 'currentColor' : 'none'}><path d="M12 2l3 7 7 .5-5 5 1.5 7L12 18l-6.5 3.5L7 14l-5-5 7-.5z"/></svg>;
      case 'heart':        return <svg {...p} fill={filled ? 'currentColor' : 'none'}><path d="M12 21s-9-6-9-12a5 5 0 019-3 5 5 0 019 3c0 6-9 12-9 12z"/></svg>;
      case 'chevronRight': return <svg {...p}><path d="M9 6l6 6-6 6"/></svg>;
      case 'chevronLeft':  return <svg {...p}><path d="M15 6l-6 6 6 6"/></svg>;
      case 'moreH':        return <svg {...p} fill="currentColor" stroke="none"><circle cx="6" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="18" cy="12" r="1.5"/></svg>;
      case 'camera':       return <svg {...p}><path d="M21 19a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h3l2-3h4l2 3h3a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg>;
      case 'trash':        return <svg {...p}><path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2M5 6v14a2 2 0 002 2h10a2 2 0 002-2V6"/></svg>;
      case 'eye':          return <svg {...p}><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></svg>;
      case 'lock':         return <svg {...p}><rect x="3" y="11" width="18" height="10" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg>;
      case 'warn':         return <svg {...p}><path d="M10.3 3l-9 16a2 2 0 001.7 3h18a2 2 0 001.7-3l-9-16a2 2 0 00-3.4 0zM12 9v4"/><circle cx="12" cy="17" r="0.5" fill="currentColor"/></svg>;
      case 'help':         return <svg {...p}><circle cx="12" cy="12" r="10"/><path d="M9.5 9a2.5 2.5 0 015 0c0 1.5-2.5 2-2.5 3.5"/><circle cx="12" cy="17" r="0.5" fill="currentColor"/></svg>;
      case 'settings':     return <svg {...p}><circle cx="12" cy="12" r="3"/><path d="M19 12a7 7 0 00-.1-1.2l2-1.6-2-3.4-2.4 1a7 7 0 00-2-1.2l-.4-2.6h-4l-.4 2.6a7 7 0 00-2 1.2l-2.4-1-2 3.4 2 1.6A7 7 0 005 12a7 7 0 00.1 1.2l-2 1.6 2 3.4 2.4-1a7 7 0 002 1.2l.4 2.6h4l.4-2.6a7 7 0 002-1.2l2.4 1 2-3.4-2-1.6A7 7 0 0019 12z"/></svg>;
      case 'send':         return <svg {...p}><path d="M22 2L11 13M22 2l-7 20-4-9-9-4z"/></svg>;
      case 'image':        return <svg {...p}><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg>;
      case 'sparkle':      return <svg {...p} fill="currentColor" stroke="none"><path d="M12 3l1.5 5.5L19 10l-5.5 1.5L12 17l-1.5-5.5L5 10l5.5-1.5z"/></svg>;
      case 'paw':          return <svg {...p} fill="currentColor" stroke="none"><circle cx="12" cy="16" r="3"/><ellipse cx="6" cy="10" rx="2" ry="2.5"/><ellipse cx="10" cy="7" rx="2" ry="2.5"/><ellipse cx="14" cy="7" rx="2" ry="2.5"/><ellipse cx="18" cy="10" rx="2" ry="2.5"/></svg>;
      case 'phone':        return <svg {...p}><path d="M22 16.9v3a2 2 0 01-2.2 2A19.8 19.8 0 011 4.2 2 2 0 013 2h3a2 2 0 012 1.7c.1.9.3 1.8.6 2.7a2 2 0 01-.5 2.1L7 9.6a16 16 0 006 6l1.1-1.1a2 2 0 012.1-.5c.9.3 1.8.5 2.7.6a2 2 0 011.7 2z"/></svg>;
      case 'share':        return <svg {...p}><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="M8.6 13.5l6.8 4M15.4 6.5l-6.8 4"/></svg>;
      case 'home':         return <svg {...p}><path d="M3 12l9-9 9 9M5 10v10a1 1 0 001 1h4v-7h4v7h4a1 1 0 001-1V10"/></svg>;
      case 'user':         return <svg {...p}><circle cx="12" cy="8" r="4"/><path d="M4 22c0-4 4-6 8-6s8 2 8 6"/></svg>;
      case 'shield':       return <svg {...p}><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>;
      case 'trophy':       return <svg {...p}><path d="M6 9V4h12v5a6 6 0 11-12 0zM8 21h8M12 16v5M6 5H3v3a3 3 0 003 3M18 5h3v3a3 3 0 01-3 3"/></svg>;
      case 'fire':         return <svg {...p} fill="currentColor" stroke="none"><path d="M12 2s5 5 5 11a5 5 0 01-10 0c0-2 1-4 2-5 0 0 0 2 1 2 0-3 1-5 2-8z"/></svg>;
      case 'tag':          return <svg {...p}><path d="M20 12l-8 8a2 2 0 01-3 0L2 13V4h9l9 8z"/><circle cx="7" cy="7" r="1" fill="currentColor"/></svg>;
      case 'pin':          return <svg {...p}><path d="M16 4v6l3 4H5l3-4V4M12 14v7"/></svg>;
      case 'play':         return <svg {...p} fill="currentColor" stroke="none"><path d="M6 4l14 8-14 8z"/></svg>;
      case 'flag':         return <svg {...p}><path d="M4 21V4h12l-2 4 2 4H4M4 4v17"/></svg>;
      case 'plusBig':      return <svg {...p} strokeWidth={2.5}><circle cx="12" cy="12" r="10"/><path d="M12 8v8M8 12h8"/></svg>;
      case 'megaphone':    return <svg {...p}><path d="M3 11v2a2 2 0 002 2h1l4 4V5L6 9H5a2 2 0 00-2 2zM14 8a4 4 0 010 8M19 5a8 8 0 010 14"/></svg>;
      case 'gift':         return <svg {...p}><rect x="3" y="8" width="18" height="4" rx="1"/><path d="M5 12v9h14v-9M12 8v13M8 8a3 3 0 010-6c2 0 4 6 4 6s2-6 4-6a3 3 0 010 6"/></svg>;
      case 'calendar':     return <svg {...p}><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 10h18M8 3v4M16 3v4"/></svg>;
      case 'menu':         return <svg {...p}><path d="M4 6h16M4 12h16M4 18h16"/></svg>;
      default:             return null;
    }
  };

  // 服务类型图标
  const ServiceIcon = ({ type, size = 24, color = 'currentColor', className = '' }) => {
    const p = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: color, strokeWidth: 1.8, strokeLinecap: 'round', strokeLinejoin: 'round', className };
    switch (type) {
      case 'feed':  // 食盆
        return <svg {...p}><path d="M3 13h18M3 13c0 5 4 7 9 7s9-2 9-7M7 13V9a5 5 0 0110 0v4"/><circle cx="12" cy="6" r="1.5" fill={color}/></svg>;
      case 'clean': // 洗澡 - 浴缸
        return <svg {...p}><path d="M3 11h18v6a3 3 0 01-3 3H6a3 3 0 01-3-3v-6zM6 11V6a3 3 0 016 0v2"/><path d="M3 11V8M21 11V9"/></svg>;
      case 'walk':  // 遛狗 - 牵引绳
        return <svg {...p}><circle cx="8" cy="4" r="2"/><path d="M6 22l2-9 2 3 3-2 3 8M8 13l-2-3 5-2 4 3-2 2"/><circle cx="18" cy="18" r="2"/></svg>;
      case 'sit':   // 寄养 - 房子
        return <svg {...p}><path d="M3 11l9-8 9 8v9a2 2 0 01-2 2H5a2 2 0 01-2-2v-9z"/><rect x="9" y="14" width="6" height="8"/></svg>;
      case 'groom': // 美容 - 剪刀
        return <svg {...p}><circle cx="6" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M20 4L8.1 15.9M14 14l6 6M8 8l8 8"/></svg>;
      case 'train': // 训练 - 球
        return <svg {...p}><circle cx="12" cy="12" r="10"/><path d="M2 12c5 0 9-4 9-9M22 12c-5 0-9-4-9-9M2 12c5 0 9 4 9 9M22 12c-5 0-9 4-9 9"/></svg>;
      case 'funeral': // 殡葬 - 鸽子/羽毛
        return <svg {...p}><path d="M4 19c4 0 7-2 9-5 1.5-2.2 3-5 7-5-1 4-3 6-5 7-3 1.5-6 2-8 2M4 19l3-2M9 12c1-1 2-2 4-2"/></svg>;
      case 'other': // 其他 - 闪烁
        return <svg {...p}><path d="M12 3v3M12 18v3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M3 12h3M18 12h3M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/><circle cx="12" cy="12" r="3"/></svg>;
      default:      return null;
    }
  };

  // 头像 - 彩色圆 + 中文首字
  const Avatar = ({ name, size = 48, bg, className = '', square = false }) => {
    const palette = ['#FFB877','#7CC8E8','#B58FD9','#FF99B6','#8FCF8F','#E8B88C','#FFD088','#A8D5BA'];
    const code = (name || 'A').charCodeAt(0);
    const c = bg || palette[code % palette.length];
    const letter = (name || '?').slice(0, 1);
    return (
      <div className={`${square ? 'rounded-2xl' : 'rounded-full'} flex items-center justify-center font-display text-white shrink-0 ${className}`}
           style={{ width: size, height: size, background: c, fontSize: size * 0.42, lineHeight: 1 }}>
        {letter}
      </div>
    );
  };

  // 宠物头像 - SVG 萌系绘制
  const PetIcon = ({ type = 'dog', size = 40, className = '' }) => {
    const props = { width: size, height: size, viewBox: '0 0 48 48', className };
    if (type === 'dog') return (
      <svg {...props}>
        <ellipse cx="13" cy="14" rx="4" ry="6" fill="#E08840" transform="rotate(-20 13 14)"/>
        <ellipse cx="35" cy="14" rx="4" ry="6" fill="#E08840" transform="rotate(20 35 14)"/>
        <circle cx="24" cy="27" r="13" fill="#F4A865"/>
        <ellipse cx="24" cy="31" rx="9" ry="7" fill="#FFF2E0"/>
        <circle cx="19" cy="26" r="1.8" fill="#2A1810"/>
        <circle cx="29" cy="26" r="1.8" fill="#2A1810"/>
        <ellipse cx="24" cy="30" rx="1.3" ry="1" fill="#2A1810"/>
        <path d="M22 33 Q24 35 26 33" stroke="#2A1810" strokeWidth="1.4" fill="none" strokeLinecap="round"/>
        <circle cx="14" cy="30" r="2" fill="#FFB5BA" opacity="0.6"/>
        <circle cx="34" cy="30" r="2" fill="#FFB5BA" opacity="0.6"/>
      </svg>
    );
    if (type === 'cat') return (
      <svg {...props}>
        <path d="M11 12 L7 4 L18 12 Z" fill="#C9C2BC"/>
        <path d="M37 12 L41 4 L30 12 Z" fill="#C9C2BC"/>
        <path d="M13 11 L11 6 L15 10 Z" fill="#FFB5BA"/>
        <path d="M35 11 L37 6 L33 10 Z" fill="#FFB5BA"/>
        <circle cx="24" cy="27" r="13" fill="#C9C2BC"/>
        <ellipse cx="24" cy="31" rx="8" ry="6" fill="white"/>
        <ellipse cx="19" cy="25" rx="1.5" ry="2" fill="#2A1810"/>
        <ellipse cx="29" cy="25" rx="1.5" ry="2" fill="#2A1810"/>
        <ellipse cx="24" cy="30" rx="1.2" ry="0.8" fill="#FF99B6"/>
        <path d="M22 32 Q24 33 26 32" stroke="#2A1810" strokeWidth="1.4" fill="none" strokeLinecap="round"/>
      </svg>
    );
    if (type === 'rabbit') return (
      <svg {...props}>
        <ellipse cx="18" cy="8" rx="3" ry="8" fill="#F8F0E5"/>
        <ellipse cx="30" cy="8" rx="3" ry="8" fill="#F8F0E5"/>
        <ellipse cx="18" cy="9" rx="1.3" ry="5" fill="#FFB5BA"/>
        <ellipse cx="30" cy="9" rx="1.3" ry="5" fill="#FFB5BA"/>
        <circle cx="24" cy="28" r="13" fill="#F8F0E5"/>
        <circle cx="19" cy="26" r="1.8" fill="#2A1810"/>
        <circle cx="29" cy="26" r="1.8" fill="#2A1810"/>
        <ellipse cx="24" cy="30" rx="1.3" ry="1" fill="#FF99B6"/>
        <path d="M22 32 Q24 33 26 32" stroke="#2A1810" strokeWidth="1.4" fill="none" strokeLinecap="round"/>
        <circle cx="14" cy="30" r="2" fill="#FFB5BA" opacity="0.6"/>
        <circle cx="34" cy="30" r="2" fill="#FFB5BA" opacity="0.6"/>
      </svg>
    );
    return (
      <svg {...props}>
        <circle cx="14" cy="14" r="4" fill="#E8B88C"/>
        <circle cx="34" cy="14" r="4" fill="#E8B88C"/>
        <circle cx="24" cy="27" r="13" fill="#E8B88C"/>
        <ellipse cx="24" cy="31" rx="9" ry="7" fill="#FFF8EC"/>
        <circle cx="19" cy="26" r="1.8" fill="#2A1810"/>
        <circle cx="29" cy="26" r="1.8" fill="#2A1810"/>
      </svg>
    );
  };

  // 在线指示点
  const OnlineDot = ({ size = 10, online = true }) => (
    <span className={`inline-block rounded-full border-2 border-white ${online ? 'bg-leaf-500' : 'bg-bark-700/30'}`}
          style={{ width: size, height: size }}></span>
  );

  window.__SHAPE__.Icon = Icon;
  window.__SHAPE__.ServiceIcon = ServiceIcon;
  window.__SHAPE__.Avatar = Avatar;
  window.__SHAPE__.PetIcon = PetIcon;
  window.__SHAPE__.OnlineDot = OnlineDot;
})();
